Skip to content

Commit 6149c86

Browse files
committed
More case sensitivity
1. also make email validation case insensitive 2. update comments to reflect what this change does
1 parent 0c91c3c commit 6149c86

File tree

2 files changed

+87
-5
lines changed

2 files changed

+87
-5
lines changed

spec/ParseUser.spec.js

+59-1
Original file line numberDiff line numberDiff line change
@@ -2166,7 +2166,7 @@ describe('Parse.User testing', () => {
21662166
});
21672167

21682168
describe('case insensitive signup not allowed', () => {
2169-
it('user should fail with duplicate insensitive username', async () => {
2169+
it('signup should fail with duplicate case insensitive username with basic setter', async () => {
21702170
const user = new Parse.User();
21712171
user.set('username', 'test1');
21722172
user.set('password', 'test');
@@ -2182,6 +2182,64 @@ describe('Parse.User testing', () => {
21822182
)
21832183
);
21842184
});
2185+
2186+
it('signup should fail with duplicate case insensitive username with field specific setter', async () => {
2187+
const user = new Parse.User();
2188+
user.setUsername('test1');
2189+
user.setPassword('test');
2190+
await user.signUp();
2191+
2192+
const user2 = new Parse.User();
2193+
user2.setUsername('Test1');
2194+
user2.setPassword('test');
2195+
await expectAsync(user2.signUp()).toBeRejectedWith(
2196+
new Parse.Error(
2197+
Parse.Error.USERNAME_TAKEN,
2198+
'Account already exists for this username.'
2199+
)
2200+
);
2201+
});
2202+
2203+
it('signup should fail with duplicate case insensitive email', async() => {
2204+
const user = new Parse.User();
2205+
user.setUsername('test1');
2206+
user.setPassword('test');
2207+
user.setEmail('[email protected]');
2208+
await user.signUp();
2209+
2210+
const user2 = new Parse.User();
2211+
user2.setUsername('test2');
2212+
user2.setPassword('test');
2213+
user2.setEmail('[email protected]');
2214+
await expectAsync(user2.signUp()).toBeRejectedWith(
2215+
new Parse.Error(
2216+
Parse.Error.EMAIL_TAKEN,
2217+
'Account already exists for this email address.'
2218+
)
2219+
);
2220+
});
2221+
2222+
it('edit should fail with duplicate case insensitive email', async() => {
2223+
const user = new Parse.User();
2224+
user.setUsername('test1');
2225+
user.setPassword('test');
2226+
user.setEmail('[email protected]');
2227+
await user.signUp();
2228+
2229+
const user2 = new Parse.User();
2230+
user2.setUsername('test2');
2231+
user2.setPassword('test');
2232+
user2.setEmail('[email protected]');
2233+
await user2.signUp();
2234+
2235+
user2.setEmail('[email protected]')
2236+
await expectAsync(user2.save()).toBeRejectedWith(
2237+
new Parse.Error(
2238+
Parse.Error.EMAIL_TAKEN,
2239+
'Account already exists for this email address.'
2240+
)
2241+
);
2242+
});
21852243
});
21862244

21872245
it('user cannot update email to existing user', done => {

src/RestWrite.js

+28-4
Original file line numberDiff line numberDiff line change
@@ -619,8 +619,18 @@ RestWrite.prototype._validateUserName = function() {
619619
}
620620
return Promise.resolve();
621621
}
622-
// We need to a find to check for duplicate username in case they are missing the unique index on usernames
623-
// TODO: Check if there is a unique index, and if so, skip this query.
622+
/*
623+
Username's should be unique when compared case insensitively
624+
625+
User's should be able to make case sensitive usernames and
626+
login using the case they entered. I.e. 'Snoopy' should preclude
627+
'snoopy' as a valid username.
628+
629+
Users that use authentication adapters should enforce unique ids
630+
through a unique index on username. Failure to enforce through an index
631+
allows for a potential collision for adapter users (a low probability outcome)
632+
but more importantly will have poor performance on this validation.
633+
*/
624634
return this.config.database
625635
.find(
626636
this.className,
@@ -644,6 +654,18 @@ RestWrite.prototype._validateUserName = function() {
644654
});
645655
};
646656

657+
/*
658+
As with username's, parse should not allow case insensitive collisions of email
659+
unlike with usernames (which can have case insensitive collisions) emails should
660+
never have a case insensitive collision.
661+
662+
This behavior can be enforced through a properly configured index see:
663+
https://docs.mongodb.com/manual/core/index-case-insensitive/#create-a-case-insensitive-index
664+
which could be implemented instead of this code based validation.
665+
666+
Given that this lookup should be a relatively low use case and that the case sensitive
667+
unique index will be used by the db for the query, this is an adequate solution.
668+
*/
647669
RestWrite.prototype._validateEmail = function() {
648670
if (!this.data.email || this.data.email.__op === 'Delete') {
649671
return Promise.resolve();
@@ -657,11 +679,13 @@ RestWrite.prototype._validateEmail = function() {
657679
)
658680
);
659681
}
660-
// Same problem for email as above for username
682+
// Case insensitive match, see note above function.
661683
return this.config.database
662684
.find(
663685
this.className,
664-
{ email: this.data.email, objectId: { $ne: this.objectId() } },
686+
{
687+
email: { $regex: `^${this.data.email}$`, $options: 'i' },
688+
objectId: { $ne: this.objectId() } },
665689
{ limit: 1 },
666690
{},
667691
this.validSchemaController

0 commit comments

Comments
 (0)