Protected fields fix (#5463)
* fix minor spelling mistake * Always process userSensitiveFields if they exist * Cover change to protectedFields Add start of some more tests for protectedFields which i need to do to document the feature. * re-arrange promise deck chairs to not swallow errors. * remove noop code * protect agains the case where options.protectedFields is set without a _User permission.
This commit is contained in:
141
spec/ProtectedFields.spec.js
Normal file
141
spec/ProtectedFields.spec.js
Normal file
@@ -0,0 +1,141 @@
|
|||||||
|
describe('ProtectedFields', function() {
|
||||||
|
it('should handle and empty protectedFields', async function() {
|
||||||
|
const protectedFields = {};
|
||||||
|
await reconfigureServer({ protectedFields });
|
||||||
|
|
||||||
|
const user = new Parse.User();
|
||||||
|
user.setUsername('Alice');
|
||||||
|
user.setPassword('sekrit');
|
||||||
|
user.set('email', 'alice@aol.com');
|
||||||
|
user.set('favoriteColor', 'yellow');
|
||||||
|
await user.save();
|
||||||
|
|
||||||
|
const fetched = await new Parse.Query(Parse.User).get(user.id);
|
||||||
|
expect(fetched.has('email')).toBeFalsy();
|
||||||
|
expect(fetched.has('favoriteColor')).toBeTruthy();
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('interaction with legacy userSensitiveFields', function() {
|
||||||
|
it('should fall back on sensitive fields if protected fields are not configured', async function() {
|
||||||
|
const userSensitiveFields = ['phoneNumber', 'timeZone'];
|
||||||
|
|
||||||
|
const protectedFields = { _User: { '*': ['email'] } };
|
||||||
|
|
||||||
|
await reconfigureServer({ userSensitiveFields, protectedFields });
|
||||||
|
const user = new Parse.User();
|
||||||
|
user.setUsername('Alice');
|
||||||
|
user.setPassword('sekrit');
|
||||||
|
user.set('email', 'alice@aol.com');
|
||||||
|
user.set('phoneNumber', 8675309);
|
||||||
|
user.set('timeZone', 'America/Los_Angeles');
|
||||||
|
user.set('favoriteColor', 'yellow');
|
||||||
|
user.set('favoriteFood', 'pizza');
|
||||||
|
await user.save();
|
||||||
|
|
||||||
|
const fetched = await new Parse.Query(Parse.User).get(user.id);
|
||||||
|
expect(fetched.has('email')).toBeFalsy();
|
||||||
|
expect(fetched.has('phoneNumber')).toBeFalsy();
|
||||||
|
expect(fetched.has('favoriteColor')).toBeTruthy();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should merge protected and sensitive for extra safety', async function() {
|
||||||
|
const userSensitiveFields = ['phoneNumber', 'timeZone'];
|
||||||
|
|
||||||
|
const protectedFields = { _User: { '*': ['email', 'favoriteFood'] } };
|
||||||
|
|
||||||
|
await reconfigureServer({ userSensitiveFields, protectedFields });
|
||||||
|
const user = new Parse.User();
|
||||||
|
user.setUsername('Alice');
|
||||||
|
user.setPassword('sekrit');
|
||||||
|
user.set('email', 'alice@aol.com');
|
||||||
|
user.set('phoneNumber', 8675309);
|
||||||
|
user.set('timeZone', 'America/Los_Angeles');
|
||||||
|
user.set('favoriteColor', 'yellow');
|
||||||
|
user.set('favoriteFood', 'pizza');
|
||||||
|
await user.save();
|
||||||
|
|
||||||
|
const fetched = await new Parse.Query(Parse.User).get(user.id);
|
||||||
|
expect(fetched.has('email')).toBeFalsy();
|
||||||
|
expect(fetched.has('phoneNumber')).toBeFalsy();
|
||||||
|
expect(fetched.has('favoriteFood')).toBeFalsy();
|
||||||
|
expect(fetched.has('favoriteColor')).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('non user class', function() {
|
||||||
|
it('should hide fields in a non user class', async function() {
|
||||||
|
const protectedFields = {
|
||||||
|
ClassA: { '*': ['foo'] },
|
||||||
|
ClassB: { '*': ['bar'] },
|
||||||
|
};
|
||||||
|
await reconfigureServer({ protectedFields });
|
||||||
|
|
||||||
|
const objA = await new Parse.Object('ClassA')
|
||||||
|
.set('foo', 'zzz')
|
||||||
|
.set('bar', 'yyy')
|
||||||
|
.save();
|
||||||
|
|
||||||
|
const objB = await new Parse.Object('ClassB')
|
||||||
|
.set('foo', 'zzz')
|
||||||
|
.set('bar', 'yyy')
|
||||||
|
.save();
|
||||||
|
|
||||||
|
const [fetchedA, fetchedB] = await Promise.all([
|
||||||
|
new Parse.Query('ClassA').get(objA.id),
|
||||||
|
new Parse.Query('ClassB').get(objB.id),
|
||||||
|
]);
|
||||||
|
|
||||||
|
expect(fetchedA.has('foo')).toBeFalsy();
|
||||||
|
expect(fetchedA.has('bar')).toBeTruthy();
|
||||||
|
|
||||||
|
expect(fetchedB.has('foo')).toBeTruthy();
|
||||||
|
expect(fetchedB.has('bar')).toBeFalsy();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should hide fields in non user class and non standard user field at same time', async function() {
|
||||||
|
const protectedFields = {
|
||||||
|
_User: { '*': ['phoneNumber'] },
|
||||||
|
ClassA: { '*': ['foo'] },
|
||||||
|
ClassB: { '*': ['bar'] },
|
||||||
|
};
|
||||||
|
|
||||||
|
await reconfigureServer({ protectedFields });
|
||||||
|
|
||||||
|
const user = new Parse.User();
|
||||||
|
user.setUsername('Alice');
|
||||||
|
user.setPassword('sekrit');
|
||||||
|
user.set('email', 'alice@aol.com');
|
||||||
|
user.set('phoneNumber', 8675309);
|
||||||
|
user.set('timeZone', 'America/Los_Angeles');
|
||||||
|
user.set('favoriteColor', 'yellow');
|
||||||
|
user.set('favoriteFood', 'pizza');
|
||||||
|
await user.save();
|
||||||
|
|
||||||
|
const objA = await new Parse.Object('ClassA')
|
||||||
|
.set('foo', 'zzz')
|
||||||
|
.set('bar', 'yyy')
|
||||||
|
.save();
|
||||||
|
|
||||||
|
const objB = await new Parse.Object('ClassB')
|
||||||
|
.set('foo', 'zzz')
|
||||||
|
.set('bar', 'yyy')
|
||||||
|
.save();
|
||||||
|
|
||||||
|
const [fetchedUser, fetchedA, fetchedB] = await Promise.all([
|
||||||
|
new Parse.Query(Parse.User).get(user.id),
|
||||||
|
new Parse.Query('ClassA').get(objA.id),
|
||||||
|
new Parse.Query('ClassB').get(objB.id),
|
||||||
|
]);
|
||||||
|
|
||||||
|
expect(fetchedA.has('foo')).toBeFalsy();
|
||||||
|
expect(fetchedA.has('bar')).toBeTruthy();
|
||||||
|
|
||||||
|
expect(fetchedB.has('foo')).toBeTruthy();
|
||||||
|
expect(fetchedB.has('bar')).toBeFalsy();
|
||||||
|
|
||||||
|
expect(fetchedUser.has('email')).toBeFalsy();
|
||||||
|
expect(fetchedUser.has('phoneNumber')).toBeFalsy();
|
||||||
|
expect(fetchedUser.has('favoriteColor')).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -12,37 +12,31 @@ const SSN = '999-99-9999';
|
|||||||
describe('Personally Identifiable Information', () => {
|
describe('Personally Identifiable Information', () => {
|
||||||
let user;
|
let user;
|
||||||
|
|
||||||
beforeEach(done => {
|
beforeEach(async done => {
|
||||||
return Parse.User.signUp('tester', 'abc')
|
user = await Parse.User.signUp('tester', 'abc');
|
||||||
.then(loggedInUser => (user = loggedInUser))
|
user = await Parse.User.logIn(user.get('username'), 'abc');
|
||||||
.then(() => Parse.User.logIn(user.get('username'), 'abc'))
|
await user
|
||||||
.then(() =>
|
.set('email', EMAIL)
|
||||||
user
|
.set('zip', ZIP)
|
||||||
.set('email', EMAIL)
|
.set('ssn', SSN)
|
||||||
.set('zip', ZIP)
|
.save();
|
||||||
.set('ssn', SSN)
|
done();
|
||||||
.save()
|
|
||||||
)
|
|
||||||
.then(() => done());
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should be able to get own PII via API with object', done => {
|
it('should be able to get own PII via API with object', done => {
|
||||||
const userObj = new (Parse.Object.extend(Parse.User))();
|
const userObj = new (Parse.Object.extend(Parse.User))();
|
||||||
userObj.id = user.id;
|
userObj.id = user.id;
|
||||||
userObj
|
return userObj
|
||||||
.fetch()
|
.fetch()
|
||||||
.then(
|
.then(fetchedUser => {
|
||||||
fetchedUser => {
|
expect(fetchedUser.get('email')).toBe(EMAIL);
|
||||||
expect(fetchedUser.get('email')).toBe(EMAIL);
|
})
|
||||||
},
|
|
||||||
e => console.error('error', e)
|
|
||||||
)
|
|
||||||
.then(done)
|
.then(done)
|
||||||
.catch(done.fail);
|
.catch(done.fail);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should not be able to get PII via API with object', done => {
|
it('should not be able to get PII via API with object', done => {
|
||||||
Parse.User.logOut().then(() => {
|
return Parse.User.logOut().then(() => {
|
||||||
const userObj = new (Parse.Object.extend(Parse.User))();
|
const userObj = new (Parse.Object.extend(Parse.User))();
|
||||||
userObj.id = user.id;
|
userObj.id = user.id;
|
||||||
userObj
|
userObj
|
||||||
@@ -60,24 +54,19 @@ describe('Personally Identifiable Information', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should be able to get PII via API with object using master key', done => {
|
it('should be able to get PII via API with object using master key', done => {
|
||||||
Parse.User.logOut().then(() => {
|
return Parse.User.logOut().then(() => {
|
||||||
const userObj = new (Parse.Object.extend(Parse.User))();
|
const userObj = new (Parse.Object.extend(Parse.User))();
|
||||||
userObj.id = user.id;
|
userObj.id = user.id;
|
||||||
userObj
|
userObj
|
||||||
.fetch({ useMasterKey: true })
|
.fetch({ useMasterKey: true })
|
||||||
.then(
|
.then(fetchedUser => expect(fetchedUser.get('email')).toBe(EMAIL))
|
||||||
fetchedUser => {
|
|
||||||
expect(fetchedUser.get('email')).toBe(EMAIL);
|
|
||||||
},
|
|
||||||
e => console.error('error', e)
|
|
||||||
)
|
|
||||||
.then(done)
|
.then(done)
|
||||||
.catch(done.fail);
|
.catch(done.fail);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should be able to get own PII via API with Find', done => {
|
it('should be able to get own PII via API with Find', done => {
|
||||||
new Parse.Query(Parse.User).first().then(fetchedUser => {
|
return new Parse.Query(Parse.User).first().then(fetchedUser => {
|
||||||
expect(fetchedUser.get('email')).toBe(EMAIL);
|
expect(fetchedUser.get('email')).toBe(EMAIL);
|
||||||
expect(fetchedUser.get('zip')).toBe(ZIP);
|
expect(fetchedUser.get('zip')).toBe(ZIP);
|
||||||
expect(fetchedUser.get('ssn')).toBe(SSN);
|
expect(fetchedUser.get('ssn')).toBe(SSN);
|
||||||
@@ -86,7 +75,7 @@ describe('Personally Identifiable Information', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should not get PII via API with Find', done => {
|
it('should not get PII via API with Find', done => {
|
||||||
Parse.User.logOut().then(() =>
|
return Parse.User.logOut().then(() =>
|
||||||
new Parse.Query(Parse.User).first().then(fetchedUser => {
|
new Parse.Query(Parse.User).first().then(fetchedUser => {
|
||||||
expect(fetchedUser.get('email')).toBe(undefined);
|
expect(fetchedUser.get('email')).toBe(undefined);
|
||||||
expect(fetchedUser.get('zip')).toBe(ZIP);
|
expect(fetchedUser.get('zip')).toBe(ZIP);
|
||||||
@@ -97,7 +86,7 @@ describe('Personally Identifiable Information', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should get PII via API with Find using master key', done => {
|
it('should get PII via API with Find using master key', done => {
|
||||||
Parse.User.logOut().then(() =>
|
return Parse.User.logOut().then(() =>
|
||||||
new Parse.Query(Parse.User)
|
new Parse.Query(Parse.User)
|
||||||
.first({ useMasterKey: true })
|
.first({ useMasterKey: true })
|
||||||
.then(fetchedUser => {
|
.then(fetchedUser => {
|
||||||
@@ -110,7 +99,7 @@ describe('Personally Identifiable Information', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should be able to get own PII via API with Get', done => {
|
it('should be able to get own PII via API with Get', done => {
|
||||||
new Parse.Query(Parse.User).get(user.id).then(fetchedUser => {
|
return new Parse.Query(Parse.User).get(user.id).then(fetchedUser => {
|
||||||
expect(fetchedUser.get('email')).toBe(EMAIL);
|
expect(fetchedUser.get('email')).toBe(EMAIL);
|
||||||
expect(fetchedUser.get('zip')).toBe(ZIP);
|
expect(fetchedUser.get('zip')).toBe(ZIP);
|
||||||
expect(fetchedUser.get('ssn')).toBe(SSN);
|
expect(fetchedUser.get('ssn')).toBe(SSN);
|
||||||
@@ -119,7 +108,7 @@ describe('Personally Identifiable Information', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should not get PII via API with Get', done => {
|
it('should not get PII via API with Get', done => {
|
||||||
Parse.User.logOut().then(() =>
|
return Parse.User.logOut().then(() =>
|
||||||
new Parse.Query(Parse.User).get(user.id).then(fetchedUser => {
|
new Parse.Query(Parse.User).get(user.id).then(fetchedUser => {
|
||||||
expect(fetchedUser.get('email')).toBe(undefined);
|
expect(fetchedUser.get('email')).toBe(undefined);
|
||||||
expect(fetchedUser.get('zip')).toBe(ZIP);
|
expect(fetchedUser.get('zip')).toBe(ZIP);
|
||||||
@@ -130,7 +119,7 @@ describe('Personally Identifiable Information', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should get PII via API with Get using master key', done => {
|
it('should get PII via API with Get using master key', done => {
|
||||||
Parse.User.logOut().then(() =>
|
return Parse.User.logOut().then(() =>
|
||||||
new Parse.Query(Parse.User)
|
new Parse.Query(Parse.User)
|
||||||
.get(user.id, { useMasterKey: true })
|
.get(user.id, { useMasterKey: true })
|
||||||
.then(fetchedUser => {
|
.then(fetchedUser => {
|
||||||
@@ -143,28 +132,25 @@ describe('Personally Identifiable Information', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should not get PII via REST', done => {
|
it('should not get PII via REST', done => {
|
||||||
request({
|
return request({
|
||||||
url: 'http://localhost:8378/1/classes/_User',
|
url: 'http://localhost:8378/1/classes/_User',
|
||||||
headers: {
|
headers: {
|
||||||
'X-Parse-Application-Id': 'test',
|
'X-Parse-Application-Id': 'test',
|
||||||
'X-Parse-Javascript-Key': 'test',
|
'X-Parse-Javascript-Key': 'test',
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
.then(
|
.then(response => {
|
||||||
response => {
|
const result = response.data;
|
||||||
const result = response.data;
|
const fetchedUser = result.results[0];
|
||||||
const fetchedUser = result.results[0];
|
expect(fetchedUser.zip).toBe(ZIP);
|
||||||
expect(fetchedUser.zip).toBe(ZIP);
|
return expect(fetchedUser.email).toBe(undefined);
|
||||||
expect(fetchedUser.email).toBe(undefined);
|
})
|
||||||
},
|
|
||||||
e => console.error('error', e.message)
|
|
||||||
)
|
|
||||||
.then(done)
|
.then(done)
|
||||||
.catch(done.fail);
|
.catch(done.fail);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should get PII via REST with self credentials', done => {
|
it('should get PII via REST with self credentials', done => {
|
||||||
request({
|
return request({
|
||||||
url: 'http://localhost:8378/1/classes/_User',
|
url: 'http://localhost:8378/1/classes/_User',
|
||||||
json: true,
|
json: true,
|
||||||
headers: {
|
headers: {
|
||||||
@@ -173,16 +159,14 @@ describe('Personally Identifiable Information', () => {
|
|||||||
'X-Parse-Session-Token': user.getSessionToken(),
|
'X-Parse-Session-Token': user.getSessionToken(),
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
.then(
|
.then(response => {
|
||||||
response => {
|
const result = response.data;
|
||||||
const result = response.data;
|
const fetchedUser = result.results[0];
|
||||||
const fetchedUser = result.results[0];
|
expect(fetchedUser.zip).toBe(ZIP);
|
||||||
expect(fetchedUser.zip).toBe(ZIP);
|
return expect(fetchedUser.email).toBe(EMAIL);
|
||||||
expect(fetchedUser.email).toBe(EMAIL);
|
})
|
||||||
},
|
.then(done)
|
||||||
e => console.error('error', e.message)
|
.catch(done.fail);
|
||||||
)
|
|
||||||
.then(done);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should get PII via REST using master key', done => {
|
it('should get PII via REST using master key', done => {
|
||||||
@@ -194,16 +178,14 @@ describe('Personally Identifiable Information', () => {
|
|||||||
'X-Parse-Master-Key': 'test',
|
'X-Parse-Master-Key': 'test',
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
.then(
|
.then(response => {
|
||||||
response => {
|
const result = response.data;
|
||||||
const result = response.data;
|
const fetchedUser = result.results[0];
|
||||||
const fetchedUser = result.results[0];
|
expect(fetchedUser.zip).toBe(ZIP);
|
||||||
expect(fetchedUser.zip).toBe(ZIP);
|
return expect(fetchedUser.email).toBe(EMAIL);
|
||||||
expect(fetchedUser.email).toBe(EMAIL);
|
})
|
||||||
},
|
.then(done)
|
||||||
e => console.error('error', e.message)
|
.catch(done.fail);
|
||||||
)
|
|
||||||
.then(() => done());
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should not get PII via REST by ID', done => {
|
it('should not get PII via REST by ID', done => {
|
||||||
@@ -235,16 +217,14 @@ describe('Personally Identifiable Information', () => {
|
|||||||
'X-Parse-Session-Token': user.getSessionToken(),
|
'X-Parse-Session-Token': user.getSessionToken(),
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
.then(
|
.then(response => {
|
||||||
response => {
|
const result = response.data;
|
||||||
const result = response.data;
|
const fetchedUser = result;
|
||||||
const fetchedUser = result;
|
expect(fetchedUser.zip).toBe(ZIP);
|
||||||
expect(fetchedUser.zip).toBe(ZIP);
|
return expect(fetchedUser.email).toBe(EMAIL);
|
||||||
expect(fetchedUser.email).toBe(EMAIL);
|
})
|
||||||
},
|
.then(done)
|
||||||
e => console.error('error', e.message)
|
.catch(done.fail);
|
||||||
)
|
|
||||||
.then(() => done());
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should get PII via REST by ID with master key', done => {
|
it('should get PII via REST by ID with master key', done => {
|
||||||
@@ -257,37 +237,35 @@ describe('Personally Identifiable Information', () => {
|
|||||||
'X-Parse-Master-Key': 'test',
|
'X-Parse-Master-Key': 'test',
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
.then(
|
.then(response => {
|
||||||
response => {
|
const result = response.data;
|
||||||
const result = response.data;
|
const fetchedUser = result;
|
||||||
const fetchedUser = result;
|
expect(fetchedUser.zip).toBe(ZIP);
|
||||||
expect(fetchedUser.zip).toBe(ZIP);
|
expect(fetchedUser.email).toBe(EMAIL);
|
||||||
expect(fetchedUser.email).toBe(EMAIL);
|
})
|
||||||
},
|
.then(done)
|
||||||
e => console.error('error', e.message)
|
.catch(done.fail);
|
||||||
)
|
|
||||||
.then(() => done());
|
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('with deprecated configured sensitive fields', () => {
|
describe('with deprecated configured sensitive fields', () => {
|
||||||
beforeEach(done => {
|
beforeEach(done => {
|
||||||
reconfigureServer({ userSensitiveFields: ['ssn', 'zip'] }).then(() =>
|
return reconfigureServer({ userSensitiveFields: ['ssn', 'zip'] }).then(
|
||||||
done()
|
done
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should be able to get own PII via API with object', done => {
|
it('should be able to get own PII via API with object', done => {
|
||||||
const userObj = new (Parse.Object.extend(Parse.User))();
|
const userObj = new (Parse.Object.extend(Parse.User))();
|
||||||
userObj.id = user.id;
|
userObj.id = user.id;
|
||||||
userObj.fetch().then(
|
return userObj
|
||||||
fetchedUser => {
|
.fetch()
|
||||||
|
.then(fetchedUser => {
|
||||||
expect(fetchedUser.get('email')).toBe(EMAIL);
|
expect(fetchedUser.get('email')).toBe(EMAIL);
|
||||||
expect(fetchedUser.get('zip')).toBe(ZIP);
|
expect(fetchedUser.get('zip')).toBe(ZIP);
|
||||||
expect(fetchedUser.get('ssn')).toBe(SSN);
|
expect(fetchedUser.get('ssn')).toBe(SSN);
|
||||||
done();
|
done();
|
||||||
},
|
})
|
||||||
e => done.fail(e)
|
.catch(done.fail);
|
||||||
);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should not be able to get PII via API with object', done => {
|
it('should not be able to get PII via API with object', done => {
|
||||||
@@ -296,14 +274,11 @@ describe('Personally Identifiable Information', () => {
|
|||||||
userObj.id = user.id;
|
userObj.id = user.id;
|
||||||
userObj
|
userObj
|
||||||
.fetch()
|
.fetch()
|
||||||
.then(
|
.then(fetchedUser => {
|
||||||
fetchedUser => {
|
expect(fetchedUser.get('email')).toBe(undefined);
|
||||||
expect(fetchedUser.get('email')).toBe(undefined);
|
expect(fetchedUser.get('zip')).toBe(undefined);
|
||||||
expect(fetchedUser.get('zip')).toBe(undefined);
|
expect(fetchedUser.get('ssn')).toBe(undefined);
|
||||||
expect(fetchedUser.get('ssn')).toBe(undefined);
|
})
|
||||||
},
|
|
||||||
e => console.error('error', e)
|
|
||||||
)
|
|
||||||
.then(done)
|
.then(done)
|
||||||
.catch(done.fail);
|
.catch(done.fail);
|
||||||
});
|
});
|
||||||
@@ -420,16 +395,13 @@ describe('Personally Identifiable Information', () => {
|
|||||||
'X-Parse-Session-Token': user.getSessionToken(),
|
'X-Parse-Session-Token': user.getSessionToken(),
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
.then(
|
.then(response => {
|
||||||
response => {
|
const result = response.data;
|
||||||
const result = response.data;
|
const fetchedUser = result.results[0];
|
||||||
const fetchedUser = result.results[0];
|
expect(fetchedUser.zip).toBe(ZIP);
|
||||||
expect(fetchedUser.zip).toBe(ZIP);
|
expect(fetchedUser.email).toBe(EMAIL);
|
||||||
expect(fetchedUser.email).toBe(EMAIL);
|
return expect(fetchedUser.ssn).toBe(SSN);
|
||||||
expect(fetchedUser.ssn).toBe(SSN);
|
})
|
||||||
},
|
|
||||||
() => {}
|
|
||||||
)
|
|
||||||
.then(done)
|
.then(done)
|
||||||
.catch(done.fail);
|
.catch(done.fail);
|
||||||
});
|
});
|
||||||
@@ -553,7 +525,7 @@ describe('Personally Identifiable Information', () => {
|
|||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('privilaged user should not be able to get user PII via API with object', done => {
|
it('privileged user should not be able to get user PII via API with object', done => {
|
||||||
const userObj = new (Parse.Object.extend(Parse.User))();
|
const userObj = new (Parse.Object.extend(Parse.User))();
|
||||||
userObj.id = user.id;
|
userObj.id = user.id;
|
||||||
userObj
|
userObj
|
||||||
@@ -565,7 +537,7 @@ describe('Personally Identifiable Information', () => {
|
|||||||
.catch(done.fail);
|
.catch(done.fail);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('privilaged user should not be able to get user PII via API with Find', done => {
|
it('privileged user should not be able to get user PII via API with Find', done => {
|
||||||
new Parse.Query(Parse.User)
|
new Parse.Query(Parse.User)
|
||||||
.equalTo('objectId', user.id)
|
.equalTo('objectId', user.id)
|
||||||
.find()
|
.find()
|
||||||
@@ -579,7 +551,7 @@ describe('Personally Identifiable Information', () => {
|
|||||||
.catch(done.fail);
|
.catch(done.fail);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('privilaged user should not be able to get user PII via API with Get', done => {
|
it('privileged user should not be able to get user PII via API with Get', done => {
|
||||||
new Parse.Query(Parse.User)
|
new Parse.Query(Parse.User)
|
||||||
.get(user.id)
|
.get(user.id)
|
||||||
.then(fetchedUser => {
|
.then(fetchedUser => {
|
||||||
@@ -591,7 +563,7 @@ describe('Personally Identifiable Information', () => {
|
|||||||
.catch(done.fail);
|
.catch(done.fail);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('privilaged user should not get user PII via REST by ID', done => {
|
it('privileged user should not get user PII via REST by ID', done => {
|
||||||
request({
|
request({
|
||||||
url: `http://localhost:8378/1/classes/_User/${user.id}`,
|
url: `http://localhost:8378/1/classes/_User/${user.id}`,
|
||||||
json: true,
|
json: true,
|
||||||
@@ -601,15 +573,12 @@ describe('Personally Identifiable Information', () => {
|
|||||||
'X-Parse-Session-Token': adminUser.getSessionToken(),
|
'X-Parse-Session-Token': adminUser.getSessionToken(),
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
.then(
|
.then(response => {
|
||||||
response => {
|
const result = response.data;
|
||||||
const result = response.data;
|
const fetchedUser = result;
|
||||||
const fetchedUser = result;
|
expect(fetchedUser.zip).toBe(undefined);
|
||||||
expect(fetchedUser.zip).toBe(undefined);
|
expect(fetchedUser.email).toBe(undefined);
|
||||||
expect(fetchedUser.email).toBe(undefined);
|
})
|
||||||
},
|
|
||||||
e => console.error('error', e.message)
|
|
||||||
)
|
|
||||||
.then(() => done())
|
.then(() => done())
|
||||||
.catch(done.fail);
|
.catch(done.fail);
|
||||||
});
|
});
|
||||||
@@ -703,12 +672,9 @@ describe('Personally Identifiable Information', () => {
|
|||||||
userObj.id = user.id;
|
userObj.id = user.id;
|
||||||
userObj
|
userObj
|
||||||
.fetch()
|
.fetch()
|
||||||
.then(
|
.then(fetchedUser => {
|
||||||
fetchedUser => {
|
expect(fetchedUser.get('email')).toBe(undefined);
|
||||||
expect(fetchedUser.get('email')).toBe(undefined);
|
})
|
||||||
},
|
|
||||||
e => console.error('error', e)
|
|
||||||
)
|
|
||||||
.then(done)
|
.then(done)
|
||||||
.catch(done.fail);
|
.catch(done.fail);
|
||||||
});
|
});
|
||||||
@@ -768,14 +734,11 @@ describe('Personally Identifiable Information', () => {
|
|||||||
userObj.id = user.id;
|
userObj.id = user.id;
|
||||||
userObj
|
userObj
|
||||||
.fetch()
|
.fetch()
|
||||||
.then(
|
.then(fetchedUser => {
|
||||||
fetchedUser => {
|
expect(fetchedUser.get('email')).toBe(undefined);
|
||||||
expect(fetchedUser.get('email')).toBe(undefined);
|
expect(fetchedUser.get('zip')).toBe(undefined);
|
||||||
expect(fetchedUser.get('zip')).toBe(undefined);
|
expect(fetchedUser.get('ssn')).toBe(undefined);
|
||||||
expect(fetchedUser.get('ssn')).toBe(undefined);
|
})
|
||||||
},
|
|
||||||
e => console.error('error', e)
|
|
||||||
)
|
|
||||||
.then(done)
|
.then(done)
|
||||||
.catch(done.fail);
|
.catch(done.fail);
|
||||||
});
|
});
|
||||||
@@ -995,7 +958,7 @@ describe('Personally Identifiable Information', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Explicit ACL should be able to read sensitive information
|
// Explicit ACL should be able to read sensitive information
|
||||||
describe('with privilaged user CLP', () => {
|
describe('with privileged user CLP', () => {
|
||||||
let adminUser;
|
let adminUser;
|
||||||
|
|
||||||
beforeEach(async done => {
|
beforeEach(async done => {
|
||||||
@@ -1025,7 +988,7 @@ describe('Personally Identifiable Information', () => {
|
|||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('privilaged user should be able to get user PII via API with object', done => {
|
it('privileged user should be able to get user PII via API with object', done => {
|
||||||
const userObj = new (Parse.Object.extend(Parse.User))();
|
const userObj = new (Parse.Object.extend(Parse.User))();
|
||||||
userObj.id = user.id;
|
userObj.id = user.id;
|
||||||
userObj
|
userObj
|
||||||
@@ -1037,7 +1000,7 @@ describe('Personally Identifiable Information', () => {
|
|||||||
.catch(done.fail);
|
.catch(done.fail);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('privilaged user should be able to get user PII via API with Find', done => {
|
it('privileged user should be able to get user PII via API with Find', done => {
|
||||||
new Parse.Query(Parse.User)
|
new Parse.Query(Parse.User)
|
||||||
.equalTo('objectId', user.id)
|
.equalTo('objectId', user.id)
|
||||||
.find()
|
.find()
|
||||||
@@ -1051,7 +1014,7 @@ describe('Personally Identifiable Information', () => {
|
|||||||
.catch(done.fail);
|
.catch(done.fail);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('privilaged user should be able to get user PII via API with Get', done => {
|
it('privileged user should be able to get user PII via API with Get', done => {
|
||||||
new Parse.Query(Parse.User)
|
new Parse.Query(Parse.User)
|
||||||
.get(user.id)
|
.get(user.id)
|
||||||
.then(fetchedUser => {
|
.then(fetchedUser => {
|
||||||
@@ -1063,7 +1026,7 @@ describe('Personally Identifiable Information', () => {
|
|||||||
.catch(done.fail);
|
.catch(done.fail);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('privilaged user should get user PII via REST by ID', done => {
|
it('privileged user should get user PII via REST by ID', done => {
|
||||||
request({
|
request({
|
||||||
url: `http://localhost:8378/1/classes/_User/${user.id}`,
|
url: `http://localhost:8378/1/classes/_User/${user.id}`,
|
||||||
json: true,
|
json: true,
|
||||||
@@ -1073,16 +1036,13 @@ describe('Personally Identifiable Information', () => {
|
|||||||
'X-Parse-Session-Token': adminUser.getSessionToken(),
|
'X-Parse-Session-Token': adminUser.getSessionToken(),
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
.then(
|
.then(response => {
|
||||||
response => {
|
const result = response.data;
|
||||||
const result = response.data;
|
const fetchedUser = result;
|
||||||
const fetchedUser = result;
|
expect(fetchedUser.zip).toBe(ZIP);
|
||||||
expect(fetchedUser.zip).toBe(ZIP);
|
expect(fetchedUser.email).toBe(EMAIL);
|
||||||
expect(fetchedUser.email).toBe(EMAIL);
|
})
|
||||||
},
|
.then(done)
|
||||||
e => console.error('error', e.message)
|
|
||||||
)
|
|
||||||
.then(() => done())
|
|
||||||
.catch(done.fail);
|
.catch(done.fail);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -1175,12 +1135,9 @@ describe('Personally Identifiable Information', () => {
|
|||||||
userObj.id = user.id;
|
userObj.id = user.id;
|
||||||
userObj
|
userObj
|
||||||
.fetch()
|
.fetch()
|
||||||
.then(
|
.then(fetchedUser => {
|
||||||
fetchedUser => {
|
expect(fetchedUser.get('email')).toBe(undefined);
|
||||||
expect(fetchedUser.get('email')).toBe(undefined);
|
})
|
||||||
},
|
|
||||||
e => console.error('error', e)
|
|
||||||
)
|
|
||||||
.then(done)
|
.then(done)
|
||||||
.catch(done.fail);
|
.catch(done.fail);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -333,8 +333,6 @@ function addParseCloud() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function injectDefaults(options: ParseServerOptions) {
|
function injectDefaults(options: ParseServerOptions) {
|
||||||
const hasProtectedFields = !!options.protectedFields;
|
|
||||||
|
|
||||||
Object.keys(defaults).forEach(key => {
|
Object.keys(defaults).forEach(key => {
|
||||||
if (!options.hasOwnProperty(key)) {
|
if (!options.hasOwnProperty(key)) {
|
||||||
options[key] = defaults[key];
|
options[key] = defaults[key];
|
||||||
@@ -346,7 +344,7 @@ function injectDefaults(options: ParseServerOptions) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Backwards compatibility
|
// Backwards compatibility
|
||||||
if (!hasProtectedFields && options.userSensitiveFields) {
|
if (options.userSensitiveFields) {
|
||||||
/* eslint-disable no-console */
|
/* eslint-disable no-console */
|
||||||
!process.env.TESTING &&
|
!process.env.TESTING &&
|
||||||
console.warn(
|
console.warn(
|
||||||
@@ -361,7 +359,23 @@ function injectDefaults(options: ParseServerOptions) {
|
|||||||
])
|
])
|
||||||
);
|
);
|
||||||
|
|
||||||
options.protectedFields = { _User: { '*': userSensitiveFields } };
|
// If the options.protectedFields is unset,
|
||||||
|
// it'll be assigned the default above.
|
||||||
|
// Here, protect against the case where protectedFields
|
||||||
|
// is set, but doesn't have _User.
|
||||||
|
if (!('_User' in options.protectedFields)) {
|
||||||
|
options.protectedFields = Object.assign(
|
||||||
|
{ _User: [] },
|
||||||
|
options.protectedFields
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
options.protectedFields['_User']['*'] = Array.from(
|
||||||
|
new Set([
|
||||||
|
...(options.protectedFields['_User']['*'] || []),
|
||||||
|
...userSensitiveFields,
|
||||||
|
])
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Merge protectedFields options with defaults.
|
// Merge protectedFields options with defaults.
|
||||||
|
|||||||
Reference in New Issue
Block a user