removes job status object, moves messasge method on req object Adds 3.0.0 migration guide Fixes nits about 3.0.0 documentation Adds update guide to README
760 lines
25 KiB
JavaScript
760 lines
25 KiB
JavaScript
"use strict";
|
|
// These tests check the "create" / "update" functionality of the REST API.
|
|
const auth = require('../lib/Auth');
|
|
const Config = require('../lib/Config');
|
|
const Parse = require('parse/node').Parse;
|
|
const rest = require('../lib/rest');
|
|
const RestWrite = require('../lib/RestWrite');
|
|
const request = require('request');
|
|
const rp = require('request-promise');
|
|
|
|
let config;
|
|
let database;
|
|
|
|
describe('rest create', () => {
|
|
|
|
beforeEach(() => {
|
|
config = Config.get('test');
|
|
database = config.database;
|
|
});
|
|
|
|
it('handles _id', done => {
|
|
rest.create(config, auth.nobody(config), 'Foo', {})
|
|
.then(() => database.adapter.find('Foo', { fields: {} }, {}, {}))
|
|
.then(results => {
|
|
expect(results.length).toEqual(1);
|
|
const obj = results[0];
|
|
expect(typeof obj.objectId).toEqual('string');
|
|
expect(obj.objectId.length).toEqual(10);
|
|
expect(obj._id).toBeUndefined();
|
|
done();
|
|
});
|
|
});
|
|
|
|
it('can use custom _id size', done => {
|
|
config.objectIdSize = 20;
|
|
rest.create(config, auth.nobody(config), 'Foo', {})
|
|
.then(() => database.adapter.find('Foo', { fields: {} }, {}, {}))
|
|
.then((results) => {
|
|
expect(results.length).toEqual(1);
|
|
const obj = results[0];
|
|
expect(typeof obj.objectId).toEqual('string');
|
|
expect(obj.objectId.length).toEqual(20);
|
|
done();
|
|
});
|
|
});
|
|
|
|
it('is backwards compatible when _id size changes', done => {
|
|
rest.create(config, auth.nobody(config), 'Foo', {size: 10})
|
|
.then(() => {
|
|
config.objectIdSize = 20;
|
|
return rest.find(config, auth.nobody(config), 'Foo', {size: 10});
|
|
})
|
|
.then((response) => {
|
|
expect(response.results.length).toEqual(1);
|
|
expect(response.results[0].objectId.length).toEqual(10);
|
|
return rest.update(config, auth.nobody(config), 'Foo', {objectId: response.results[0].objectId}, {update: 20});
|
|
})
|
|
.then(() => {
|
|
return rest.find(config, auth.nobody(config), 'Foo', {size: 10});
|
|
}).then((response) => {
|
|
expect(response.results.length).toEqual(1);
|
|
expect(response.results[0].objectId.length).toEqual(10);
|
|
expect(response.results[0].update).toEqual(20);
|
|
return rest.create(config, auth.nobody(config), 'Foo', {size: 20});
|
|
})
|
|
.then(() => {
|
|
config.objectIdSize = 10;
|
|
return rest.find(config, auth.nobody(config), 'Foo', {size: 20});
|
|
})
|
|
.then((response) => {
|
|
expect(response.results.length).toEqual(1);
|
|
expect(response.results[0].objectId.length).toEqual(20);
|
|
done();
|
|
});
|
|
});
|
|
|
|
it('handles array, object, date', (done) => {
|
|
const now = new Date();
|
|
const obj = {
|
|
array: [1, 2, 3],
|
|
object: {foo: 'bar'},
|
|
date: Parse._encode(now),
|
|
};
|
|
rest.create(config, auth.nobody(config), 'MyClass', obj)
|
|
.then(() => database.adapter.find('MyClass', { fields: {
|
|
array: { type: 'Array' },
|
|
object: { type: 'Object' },
|
|
date: { type: 'Date' },
|
|
} }, {}, {}))
|
|
.then(results => {
|
|
expect(results.length).toEqual(1);
|
|
const mob = results[0];
|
|
expect(mob.array instanceof Array).toBe(true);
|
|
expect(typeof mob.object).toBe('object');
|
|
expect(mob.date.__type).toBe('Date');
|
|
expect(new Date(mob.date.iso).getTime()).toBe(now.getTime());
|
|
done();
|
|
});
|
|
});
|
|
|
|
it('handles object and subdocument', done => {
|
|
const obj = { subdoc: {foo: 'bar', wu: 'tan'} };
|
|
|
|
Parse.Cloud.beforeSave('MyClass', function() {
|
|
// this beforeSave trigger should do nothing but can mess with the object
|
|
});
|
|
|
|
rest.create(config, auth.nobody(config), 'MyClass', obj)
|
|
.then(() => database.adapter.find('MyClass', { fields: {} }, {}, {}))
|
|
.then(results => {
|
|
expect(results.length).toEqual(1);
|
|
const mob = results[0];
|
|
expect(typeof mob.subdoc).toBe('object');
|
|
expect(mob.subdoc.foo).toBe('bar');
|
|
expect(mob.subdoc.wu).toBe('tan');
|
|
expect(typeof mob.objectId).toEqual('string');
|
|
const obj = { 'subdoc.wu': 'clan' };
|
|
return rest.update(config, auth.nobody(config), 'MyClass', { objectId: mob.objectId }, obj);
|
|
})
|
|
.then(() => database.adapter.find('MyClass', { fields: {} }, {}, {}))
|
|
.then(results => {
|
|
expect(results.length).toEqual(1);
|
|
const mob = results[0];
|
|
expect(typeof mob.subdoc).toBe('object');
|
|
expect(mob.subdoc.foo).toBe('bar');
|
|
expect(mob.subdoc.wu).toBe('clan');
|
|
done();
|
|
})
|
|
.catch(error => {
|
|
console.log(error);
|
|
fail();
|
|
done();
|
|
});
|
|
});
|
|
|
|
it('handles create on non-existent class when disabled client class creation', (done) => {
|
|
const customConfig = Object.assign({}, config, {allowClientClassCreation: false});
|
|
rest.create(customConfig, auth.nobody(customConfig), 'ClientClassCreation', {})
|
|
.then(() => {
|
|
fail('Should throw an error');
|
|
done();
|
|
}, (err) => {
|
|
expect(err.code).toEqual(Parse.Error.OPERATION_FORBIDDEN);
|
|
expect(err.message).toEqual('This user is not allowed to access ' +
|
|
'non-existent class: ClientClassCreation');
|
|
done();
|
|
});
|
|
});
|
|
|
|
it('handles create on existent class when disabled client class creation', (done) => {
|
|
const customConfig = Object.assign({}, config, {allowClientClassCreation: false});
|
|
config.database.loadSchema()
|
|
.then(schema => schema.addClassIfNotExists('ClientClassCreation', {}))
|
|
.then(actualSchema => {
|
|
expect(actualSchema.className).toEqual('ClientClassCreation');
|
|
return rest.create(customConfig, auth.nobody(customConfig), 'ClientClassCreation', {});
|
|
})
|
|
.then(() => {
|
|
done();
|
|
}, () => {
|
|
fail('Should not throw error')
|
|
});
|
|
});
|
|
|
|
it('handles user signup', (done) => {
|
|
const user = {
|
|
username: 'asdf',
|
|
password: 'zxcv',
|
|
foo: 'bar',
|
|
};
|
|
rest.create(config, auth.nobody(config), '_User', user)
|
|
.then((r) => {
|
|
expect(Object.keys(r.response).length).toEqual(3);
|
|
expect(typeof r.response.objectId).toEqual('string');
|
|
expect(typeof r.response.createdAt).toEqual('string');
|
|
expect(typeof r.response.sessionToken).toEqual('string');
|
|
done();
|
|
});
|
|
});
|
|
|
|
it('handles anonymous user signup', (done) => {
|
|
const data1 = {
|
|
authData: {
|
|
anonymous: {
|
|
id: '00000000-0000-0000-0000-000000000001'
|
|
}
|
|
}
|
|
};
|
|
const data2 = {
|
|
authData: {
|
|
anonymous: {
|
|
id: '00000000-0000-0000-0000-000000000002'
|
|
}
|
|
}
|
|
};
|
|
let username1;
|
|
rest.create(config, auth.nobody(config), '_User', data1)
|
|
.then((r) => {
|
|
expect(typeof r.response.objectId).toEqual('string');
|
|
expect(typeof r.response.createdAt).toEqual('string');
|
|
expect(typeof r.response.sessionToken).toEqual('string');
|
|
expect(typeof r.response.username).toEqual('string');
|
|
return rest.create(config, auth.nobody(config), '_User', data1);
|
|
}).then((r) => {
|
|
expect(typeof r.response.objectId).toEqual('string');
|
|
expect(typeof r.response.createdAt).toEqual('string');
|
|
expect(typeof r.response.username).toEqual('string');
|
|
expect(typeof r.response.updatedAt).toEqual('string');
|
|
username1 = r.response.username;
|
|
return rest.create(config, auth.nobody(config), '_User', data2);
|
|
}).then((r) => {
|
|
expect(typeof r.response.objectId).toEqual('string');
|
|
expect(typeof r.response.createdAt).toEqual('string');
|
|
expect(typeof r.response.sessionToken).toEqual('string');
|
|
return rest.create(config, auth.nobody(config), '_User', data2);
|
|
}).then((r) => {
|
|
expect(typeof r.response.objectId).toEqual('string');
|
|
expect(typeof r.response.createdAt).toEqual('string');
|
|
expect(typeof r.response.username).toEqual('string');
|
|
expect(typeof r.response.updatedAt).toEqual('string');
|
|
expect(r.response.username).not.toEqual(username1);
|
|
done();
|
|
});
|
|
});
|
|
|
|
it('handles anonymous user signup and upgrade to new user', (done) => {
|
|
const data1 = {
|
|
authData: {
|
|
anonymous: {
|
|
id: '00000000-0000-0000-0000-000000000001'
|
|
}
|
|
}
|
|
};
|
|
|
|
const updatedData = {
|
|
authData: { anonymous: null },
|
|
username: 'hello',
|
|
password: 'world'
|
|
}
|
|
let objectId;
|
|
rest.create(config, auth.nobody(config), '_User', data1)
|
|
.then((r) => {
|
|
expect(typeof r.response.objectId).toEqual('string');
|
|
expect(typeof r.response.createdAt).toEqual('string');
|
|
expect(typeof r.response.sessionToken).toEqual('string');
|
|
objectId = r.response.objectId;
|
|
return auth.getAuthForSessionToken({config, sessionToken: r.response.sessionToken })
|
|
}).then((sessionAuth) => {
|
|
return rest.update(config, sessionAuth, '_User', { objectId }, updatedData);
|
|
}).then(() => {
|
|
return Parse.User.logOut().then(() => {
|
|
return Parse.User.logIn('hello', 'world');
|
|
})
|
|
}).then((r) => {
|
|
expect(r.id).toEqual(objectId);
|
|
expect(r.get('username')).toEqual('hello');
|
|
done();
|
|
}).catch((err) => {
|
|
jfail(err);
|
|
done();
|
|
})
|
|
});
|
|
|
|
it('handles no anonymous users config', (done) => {
|
|
const NoAnnonConfig = Object.assign({}, config);
|
|
NoAnnonConfig.authDataManager.setEnableAnonymousUsers(false);
|
|
const data1 = {
|
|
authData: {
|
|
anonymous: {
|
|
id: '00000000-0000-0000-0000-000000000001'
|
|
}
|
|
}
|
|
};
|
|
rest.create(NoAnnonConfig, auth.nobody(NoAnnonConfig), '_User', data1).then(() => {
|
|
fail("Should throw an error");
|
|
done();
|
|
}, (err) => {
|
|
expect(err.code).toEqual(Parse.Error.UNSUPPORTED_SERVICE);
|
|
expect(err.message).toEqual('This authentication method is unsupported.');
|
|
NoAnnonConfig.authDataManager.setEnableAnonymousUsers(true);
|
|
done();
|
|
})
|
|
});
|
|
|
|
it('test facebook signup and login', (done) => {
|
|
const data = {
|
|
authData: {
|
|
facebook: {
|
|
id: '8675309',
|
|
access_token: 'jenny'
|
|
}
|
|
}
|
|
};
|
|
let newUserSignedUpByFacebookObjectId;
|
|
rest.create(config, auth.nobody(config), '_User', data)
|
|
.then((r) => {
|
|
expect(typeof r.response.objectId).toEqual('string');
|
|
expect(typeof r.response.createdAt).toEqual('string');
|
|
expect(typeof r.response.sessionToken).toEqual('string');
|
|
newUserSignedUpByFacebookObjectId = r.response.objectId;
|
|
return rest.create(config, auth.nobody(config), '_User', data);
|
|
}).then((r) => {
|
|
expect(typeof r.response.objectId).toEqual('string');
|
|
expect(typeof r.response.createdAt).toEqual('string');
|
|
expect(typeof r.response.username).toEqual('string');
|
|
expect(typeof r.response.updatedAt).toEqual('string');
|
|
expect(r.response.objectId).toEqual(newUserSignedUpByFacebookObjectId);
|
|
return rest.find(config, auth.master(config),
|
|
'_Session', {sessionToken: r.response.sessionToken});
|
|
}).then((response) => {
|
|
expect(response.results.length).toEqual(1);
|
|
const output = response.results[0];
|
|
expect(output.user.objectId).toEqual(newUserSignedUpByFacebookObjectId);
|
|
done();
|
|
}).catch(err => {
|
|
jfail(err);
|
|
done();
|
|
})
|
|
});
|
|
|
|
it('stores pointers', done => {
|
|
const obj = {
|
|
foo: 'bar',
|
|
aPointer: {
|
|
__type: 'Pointer',
|
|
className: 'JustThePointer',
|
|
objectId: 'qwerty1234' // make it 10 chars to match PG storage
|
|
}
|
|
};
|
|
rest.create(config, auth.nobody(config), 'APointerDarkly', obj)
|
|
.then(() => database.adapter.find('APointerDarkly', { fields: {
|
|
foo: { type: 'String' },
|
|
aPointer: { type: 'Pointer', targetClass: 'JustThePointer' },
|
|
}}, {}, {}))
|
|
.then(results => {
|
|
expect(results.length).toEqual(1);
|
|
const output = results[0];
|
|
expect(typeof output.foo).toEqual('string');
|
|
expect(typeof output._p_aPointer).toEqual('undefined');
|
|
expect(output._p_aPointer).toBeUndefined();
|
|
expect(output.aPointer).toEqual({
|
|
__type: 'Pointer',
|
|
className: 'JustThePointer',
|
|
objectId: 'qwerty1234'
|
|
});
|
|
done();
|
|
});
|
|
});
|
|
|
|
it("cannot set objectId", (done) => {
|
|
const headers = {
|
|
'Content-Type': 'application/octet-stream',
|
|
'X-Parse-Application-Id': 'test',
|
|
'X-Parse-REST-API-Key': 'rest'
|
|
};
|
|
request.post({
|
|
headers: headers,
|
|
url: 'http://localhost:8378/1/classes/TestObject',
|
|
body: JSON.stringify({
|
|
'foo': 'bar',
|
|
'objectId': 'hello'
|
|
})
|
|
}, (error, response, body) => {
|
|
const b = JSON.parse(body);
|
|
expect(b.code).toEqual(105);
|
|
expect(b.error).toEqual('objectId is an invalid field name.');
|
|
done();
|
|
});
|
|
});
|
|
|
|
it("test default session length", (done) => {
|
|
const user = {
|
|
username: 'asdf',
|
|
password: 'zxcv',
|
|
foo: 'bar',
|
|
};
|
|
const now = new Date();
|
|
|
|
rest.create(config, auth.nobody(config), '_User', user)
|
|
.then((r) => {
|
|
expect(Object.keys(r.response).length).toEqual(3);
|
|
expect(typeof r.response.objectId).toEqual('string');
|
|
expect(typeof r.response.createdAt).toEqual('string');
|
|
expect(typeof r.response.sessionToken).toEqual('string');
|
|
return rest.find(config, auth.master(config),
|
|
'_Session', {sessionToken: r.response.sessionToken});
|
|
})
|
|
.then((r) => {
|
|
expect(r.results.length).toEqual(1);
|
|
|
|
const session = r.results[0];
|
|
const actual = new Date(session.expiresAt.iso);
|
|
const expected = new Date(now.getTime() + (1000 * 3600 * 24 * 365));
|
|
|
|
expect(actual.getFullYear()).toEqual(expected.getFullYear());
|
|
expect(actual.getMonth()).toEqual(expected.getMonth());
|
|
expect(actual.getDate()).toEqual(expected.getDate());
|
|
// less than a minute, if test happen at the wrong time :/
|
|
expect(actual.getMinutes() - expected.getMinutes() <= 1).toBe(true);
|
|
|
|
done();
|
|
});
|
|
});
|
|
|
|
it("test specified session length", (done) => {
|
|
const user = {
|
|
username: 'asdf',
|
|
password: 'zxcv',
|
|
foo: 'bar',
|
|
};
|
|
const sessionLength = 3600, // 1 Hour ahead
|
|
now = new Date(); // For reference later
|
|
config.sessionLength = sessionLength;
|
|
|
|
rest.create(config, auth.nobody(config), '_User', user)
|
|
.then((r) => {
|
|
expect(Object.keys(r.response).length).toEqual(3);
|
|
expect(typeof r.response.objectId).toEqual('string');
|
|
expect(typeof r.response.createdAt).toEqual('string');
|
|
expect(typeof r.response.sessionToken).toEqual('string');
|
|
return rest.find(config, auth.master(config),
|
|
'_Session', {sessionToken: r.response.sessionToken});
|
|
})
|
|
.then((r) => {
|
|
expect(r.results.length).toEqual(1);
|
|
|
|
const session = r.results[0];
|
|
const actual = new Date(session.expiresAt.iso);
|
|
const expected = new Date(now.getTime() + (sessionLength * 1000));
|
|
|
|
expect(actual.getFullYear()).toEqual(expected.getFullYear());
|
|
expect(actual.getMonth()).toEqual(expected.getMonth());
|
|
expect(actual.getDate()).toEqual(expected.getDate());
|
|
expect(actual.getHours()).toEqual(expected.getHours());
|
|
expect(actual.getMinutes()).toEqual(expected.getMinutes());
|
|
|
|
done();
|
|
}).catch(err => {
|
|
jfail(err);
|
|
done();
|
|
});
|
|
});
|
|
|
|
it("can create a session with no expiration", (done) => {
|
|
const user = {
|
|
username: 'asdf',
|
|
password: 'zxcv',
|
|
foo: 'bar'
|
|
};
|
|
config.expireInactiveSessions = false;
|
|
|
|
rest.create(config, auth.nobody(config), '_User', user)
|
|
.then((r) => {
|
|
expect(Object.keys(r.response).length).toEqual(3);
|
|
expect(typeof r.response.objectId).toEqual('string');
|
|
expect(typeof r.response.createdAt).toEqual('string');
|
|
expect(typeof r.response.sessionToken).toEqual('string');
|
|
return rest.find(config, auth.master(config),
|
|
'_Session', {sessionToken: r.response.sessionToken});
|
|
})
|
|
.then((r) => {
|
|
expect(r.results.length).toEqual(1);
|
|
|
|
const session = r.results[0];
|
|
expect(session.expiresAt).toBeUndefined();
|
|
|
|
done();
|
|
}).catch(err => {
|
|
console.error(err);
|
|
fail(err);
|
|
done();
|
|
})
|
|
});
|
|
|
|
it("can create object in volatileClasses if masterKey", (done) =>{
|
|
rest.create(config, auth.master(config), '_PushStatus', {})
|
|
.then((r) => {
|
|
expect(r.response.objectId.length).toBe(10);
|
|
})
|
|
.then(() => {
|
|
rest.create(config, auth.master(config), '_JobStatus', {})
|
|
.then((r) => {
|
|
expect(r.response.objectId.length).toBe(10);
|
|
done();
|
|
})
|
|
})
|
|
|
|
});
|
|
|
|
it("cannot create object in volatileClasses if not masterKey", (done) =>{
|
|
Promise.resolve()
|
|
.then(() => {
|
|
return rest.create(config, auth.nobody(config), '_PushStatus', {})
|
|
})
|
|
.then((r) => {
|
|
console.log(r);
|
|
})
|
|
.catch((error) => {
|
|
expect(error.code).toEqual(119);
|
|
done();
|
|
})
|
|
});
|
|
|
|
it('locks down session', (done) => {
|
|
let currentUser;
|
|
Parse.User.signUp('foo', 'bar').then((user) => {
|
|
currentUser = user;
|
|
const sessionToken = user.getSessionToken();
|
|
const headers = {
|
|
'Content-Type': 'application/octet-stream',
|
|
'X-Parse-Application-Id': 'test',
|
|
'X-Parse-REST-API-Key': 'rest',
|
|
'X-Parse-Session-Token': sessionToken,
|
|
};
|
|
let sessionId;
|
|
return rp.get({
|
|
headers: headers,
|
|
url: 'http://localhost:8378/1/sessions/me',
|
|
json: true,
|
|
}).then(body => {
|
|
sessionId = body.objectId;
|
|
return rp.put({
|
|
headers,
|
|
url: 'http://localhost:8378/1/sessions/' + sessionId,
|
|
json: {
|
|
installationId: 'yolo'
|
|
}
|
|
})
|
|
}).then(done.fail, (res) => {
|
|
expect(res.statusCode).toBe(400);
|
|
expect(res.error.code).toBe(105);
|
|
return rp.put({
|
|
headers,
|
|
url: 'http://localhost:8378/1/sessions/' + sessionId,
|
|
json: {
|
|
sessionToken: 'yolo'
|
|
}
|
|
})
|
|
}).then(done.fail, (res) => {
|
|
expect(res.statusCode).toBe(400);
|
|
expect(res.error.code).toBe(105);
|
|
return Parse.User.signUp('other', 'user');
|
|
}).then((otherUser) => {
|
|
const user = new Parse.User();
|
|
user.id = otherUser.id;
|
|
return rp.put({
|
|
headers,
|
|
url: 'http://localhost:8378/1/sessions/' + sessionId,
|
|
json: {
|
|
user: Parse._encode(user)
|
|
}
|
|
})
|
|
}).then(done.fail, (res) => {
|
|
expect(res.statusCode).toBe(400);
|
|
expect(res.error.code).toBe(105);
|
|
const user = new Parse.User();
|
|
user.id = currentUser.id;
|
|
return rp.put({
|
|
headers,
|
|
url: 'http://localhost:8378/1/sessions/' + sessionId,
|
|
json: {
|
|
user: Parse._encode(user)
|
|
}
|
|
})
|
|
}).then(done).catch(done.fail);
|
|
}).catch(done.fail);
|
|
});
|
|
|
|
it ('sets current user in new sessions', (done) => {
|
|
let currentUser;
|
|
Parse.User.signUp('foo', 'bar')
|
|
.then((user) => {
|
|
currentUser = user;
|
|
const sessionToken = user.getSessionToken();
|
|
const headers = {
|
|
'X-Parse-Application-Id': 'test',
|
|
'X-Parse-REST-API-Key': 'rest',
|
|
'X-Parse-Session-Token': sessionToken,
|
|
};
|
|
return rp.post({
|
|
headers,
|
|
url: 'http://localhost:8378/1/sessions',
|
|
json: true,
|
|
body: { 'user': { '__type': 'Pointer', 'className':'_User', 'objectId': 'fakeId' } },
|
|
})
|
|
})
|
|
.then((body) => {
|
|
if (body.user.objectId === currentUser.id) {
|
|
return done();
|
|
} else {
|
|
return done.fail();
|
|
}
|
|
})
|
|
.catch(done.fail);
|
|
})
|
|
});
|
|
|
|
describe('rest update', () => {
|
|
|
|
it('ignores createdAt', done => {
|
|
const config = Config.get('test');
|
|
const nobody = auth.nobody(config);
|
|
const className = 'Foo';
|
|
const newCreatedAt = new Date('1970-01-01T00:00:00.000Z');
|
|
|
|
rest.create(config, nobody, className, {}).then(res => {
|
|
const objectId = res.response.objectId;
|
|
const restObject = {
|
|
createdAt: {__type: "Date", iso: newCreatedAt}, // should be ignored
|
|
};
|
|
|
|
return rest.update(config, nobody, className, { objectId }, restObject).then(() => {
|
|
const restWhere = {
|
|
objectId: objectId,
|
|
};
|
|
return rest.find(config, nobody, className, restWhere, {});
|
|
});
|
|
}).then(res2 => {
|
|
const updatedObject = res2.results[0];
|
|
expect(new Date(updatedObject.createdAt)).not.toEqual(newCreatedAt);
|
|
done();
|
|
}).then(done).catch(done.fail);
|
|
});
|
|
});
|
|
|
|
describe('read-only masterKey', () => {
|
|
it('properly throws on rest.create, rest.update and rest.del', () => {
|
|
const config = Config.get('test');
|
|
const readOnly = auth.readOnly(config);
|
|
expect(() => {
|
|
rest.create(config, readOnly, 'AnObject', {})
|
|
}).toThrow(new Parse.Error(Parse.Error.OPERATION_FORBIDDEN, `read-only masterKey isn't allowed to perform the create operation.`));
|
|
expect(() => {
|
|
rest.update(config, readOnly, 'AnObject', {})
|
|
}).toThrow();
|
|
expect(() => {
|
|
rest.del(config, readOnly, 'AnObject', {})
|
|
}).toThrow();
|
|
});
|
|
|
|
it('properly blocks writes', (done) => {
|
|
reconfigureServer({
|
|
readOnlyMasterKey: 'yolo-read-only'
|
|
}).then(() => {
|
|
return rp.post(`${Parse.serverURL}/classes/MyYolo`, {
|
|
headers: {
|
|
'X-Parse-Application-Id': Parse.applicationId,
|
|
'X-Parse-Master-Key': 'yolo-read-only',
|
|
},
|
|
json: { foo: 'bar' }
|
|
});
|
|
}).then(done.fail).catch((res) => {
|
|
expect(res.error.code).toBe(Parse.Error.OPERATION_FORBIDDEN);
|
|
expect(res.error.error).toBe('read-only masterKey isn\'t allowed to perform the create operation.');
|
|
done();
|
|
});
|
|
});
|
|
|
|
it('should throw when masterKey and readOnlyMasterKey are the same', (done) => {
|
|
reconfigureServer({
|
|
masterKey: 'yolo',
|
|
readOnlyMasterKey: 'yolo'
|
|
}).then(done.fail).catch((err) => {
|
|
expect(err).toEqual(new Error('masterKey and readOnlyMasterKey should be different'));
|
|
done();
|
|
});
|
|
});
|
|
|
|
it('should throw when trying to create RestWrite', () => {
|
|
const config = Config.get('test');
|
|
expect(() => {
|
|
new RestWrite(config, auth.readOnly(config));
|
|
}).toThrow(new Parse.Error(Parse.Error.OPERATION_FORBIDDEN, 'Cannot perform a write operation when using readOnlyMasterKey'));
|
|
});
|
|
|
|
it('should throw when trying to create schema', (done) => {
|
|
return rp.post(`${Parse.serverURL}/schemas`, {
|
|
headers: {
|
|
'X-Parse-Application-Id': Parse.applicationId,
|
|
'X-Parse-Master-Key': 'read-only-test',
|
|
},
|
|
json: {}
|
|
}).then(done.fail).catch((res) => {
|
|
expect(res.error.code).toBe(Parse.Error.OPERATION_FORBIDDEN);
|
|
expect(res.error.error).toBe('read-only masterKey isn\'t allowed to create a schema.');
|
|
done();
|
|
});
|
|
});
|
|
|
|
it('should throw when trying to create schema with a name', (done) => {
|
|
return rp.post(`${Parse.serverURL}/schemas/MyClass`, {
|
|
headers: {
|
|
'X-Parse-Application-Id': Parse.applicationId,
|
|
'X-Parse-Master-Key': 'read-only-test',
|
|
},
|
|
json: {}
|
|
}).then(done.fail).catch((res) => {
|
|
expect(res.error.code).toBe(Parse.Error.OPERATION_FORBIDDEN);
|
|
expect(res.error.error).toBe('read-only masterKey isn\'t allowed to create a schema.');
|
|
done();
|
|
});
|
|
});
|
|
|
|
it('should throw when trying to update schema', (done) => {
|
|
return rp.put(`${Parse.serverURL}/schemas/MyClass`, {
|
|
headers: {
|
|
'X-Parse-Application-Id': Parse.applicationId,
|
|
'X-Parse-Master-Key': 'read-only-test',
|
|
},
|
|
json: {}
|
|
}).then(done.fail).catch((res) => {
|
|
expect(res.error.code).toBe(Parse.Error.OPERATION_FORBIDDEN);
|
|
expect(res.error.error).toBe('read-only masterKey isn\'t allowed to update a schema.');
|
|
done();
|
|
});
|
|
});
|
|
|
|
it('should throw when trying to delete schema', (done) => {
|
|
return rp.del(`${Parse.serverURL}/schemas/MyClass`, {
|
|
headers: {
|
|
'X-Parse-Application-Id': Parse.applicationId,
|
|
'X-Parse-Master-Key': 'read-only-test',
|
|
},
|
|
json: {}
|
|
}).then(done.fail).catch((res) => {
|
|
expect(res.error.code).toBe(Parse.Error.OPERATION_FORBIDDEN);
|
|
expect(res.error.error).toBe('read-only masterKey isn\'t allowed to delete a schema.');
|
|
done();
|
|
});
|
|
});
|
|
|
|
it('should throw when trying to update the global config', (done) => {
|
|
return rp.put(`${Parse.serverURL}/config`, {
|
|
headers: {
|
|
'X-Parse-Application-Id': Parse.applicationId,
|
|
'X-Parse-Master-Key': 'read-only-test',
|
|
},
|
|
json: {}
|
|
}).then(done.fail).catch((res) => {
|
|
expect(res.error.code).toBe(Parse.Error.OPERATION_FORBIDDEN);
|
|
expect(res.error.error).toBe('read-only masterKey isn\'t allowed to update the config.');
|
|
done();
|
|
});
|
|
});
|
|
|
|
it('should throw when trying to send push', (done) => {
|
|
return rp.post(`${Parse.serverURL}/push`, {
|
|
headers: {
|
|
'X-Parse-Application-Id': Parse.applicationId,
|
|
'X-Parse-Master-Key': 'read-only-test',
|
|
},
|
|
json: {}
|
|
}).then(done.fail).catch((res) => {
|
|
expect(res.error.code).toBe(Parse.Error.OPERATION_FORBIDDEN);
|
|
expect(res.error.error).toBe('read-only masterKey isn\'t allowed to send push notifications.');
|
|
done();
|
|
});
|
|
});
|
|
});
|