Case insensitive signup (#5634)

* Always delete data after each, even for mongo.

* Add failing simple case test

* run all tests

* 1. when validating username be case insensitive

2. add _auth_data_anonymous to specialQueryKeys...whatever that is!

* More case sensitivity

1. also make email validation case insensitive
2. update comments to reflect what this change does

* wordsmithery and grammar

* first pass at a preformant case insensitive query.  mongo only so far.

* change name of parameter from insensitive to
caseInsensitive

* Postgres support

* properly handle auth data null

* wip

* use 'caseInsensitive' instead of 'insensitive' in all places.

* update commenet to reclect current plan

* skip the mystery test for now

* create case insensitive indecies for
mongo to support case insensitive
checks for email and username

* remove unneeded specialKey

* pull collation out to a function.

* not sure what i planned
to do with this test.
removing.

* remove typo

* remove another unused flag

* maintain order

* maintain order of params

* boil the ocean on param sequence
i like having explain last cause it seems
like something you would
change/remove after getting what you want
from the explain?

* add test to verify creation
and use of caseInsensitive index

* add no op func to prostgress

* get collation object from mongocollection
make flow lint happy by declaring things Object.

* fix typo

* add changelog

* kick travis

* properly reference static method

* add a test to confirm that anonymous users with
unique username that do collide when compared
insensitively can still be created.

* minot doc nits

* add a few tests to make sure our spy is working as expected
wordsmith the changelog

Co-authored-by: Diamond Lewis <findlewis@gmail.com>
This commit is contained in:
Arthur Cinader
2020-02-14 09:44:51 -08:00
committed by GitHub
parent 1ea3f864a8
commit fd0b535159
10 changed files with 413 additions and 35 deletions

View File

@@ -15,7 +15,17 @@ export default class MongoCollection {
// idea. Or even if this behavior is a good idea.
find(
query,
{ skip, limit, sort, keys, maxTimeMS, readPreference, hint, explain } = {}
{
skip,
limit,
sort,
keys,
maxTimeMS,
readPreference,
hint,
caseInsensitive,
explain,
} = {}
) {
// Support for Full Text Search - $text
if (keys && keys.$score) {
@@ -30,6 +40,7 @@ export default class MongoCollection {
maxTimeMS,
readPreference,
hint,
caseInsensitive,
explain,
}).catch(error => {
// Check for "no geoindex" error
@@ -60,6 +71,7 @@ export default class MongoCollection {
maxTimeMS,
readPreference,
hint,
caseInsensitive,
explain,
})
)
@@ -67,9 +79,26 @@ export default class MongoCollection {
});
}
/**
* Collation to support case insensitive queries
*/
static caseInsensitiveCollation() {
return { locale: 'en_US', strength: 2 };
}
_rawFind(
query,
{ skip, limit, sort, keys, maxTimeMS, readPreference, hint, explain } = {}
{
skip,
limit,
sort,
keys,
maxTimeMS,
readPreference,
hint,
caseInsensitive,
explain,
} = {}
) {
let findOperation = this._mongoCollection.find(query, {
skip,
@@ -83,6 +112,12 @@ export default class MongoCollection {
findOperation = findOperation.project(keys);
}
if (caseInsensitive) {
findOperation = findOperation.collation(
MongoCollection.caseInsensitiveCollation()
);
}
if (maxTimeMS) {
findOperation = findOperation.maxTimeMS(maxTimeMS);
}

View File

@@ -620,7 +620,16 @@ export class MongoStorageAdapter implements StorageAdapter {
className: string,
schema: SchemaType,
query: QueryType,
{ skip, limit, sort, keys, readPreference, hint, explain }: QueryOptions
{
skip,
limit,
sort,
keys,
readPreference,
hint,
caseInsensitive,
explain,
}: QueryOptions
): Promise<any> {
schema = convertParseSchemaToMongoSchema(schema);
const mongoWhere = transformWhere(className, query, schema);
@@ -653,6 +662,7 @@ export class MongoStorageAdapter implements StorageAdapter {
maxTimeMS: this._maxTimeMS,
readPreference,
hint,
caseInsensitive,
explain,
})
)
@@ -667,6 +677,47 @@ export class MongoStorageAdapter implements StorageAdapter {
.catch(err => this.handleError(err));
}
ensureIndex(
className: string,
schema: SchemaType,
fieldNames: string[],
indexName: ?string,
caseInsensitive: boolean = false
): Promise<any> {
schema = convertParseSchemaToMongoSchema(schema);
const indexCreationRequest = {};
const mongoFieldNames = fieldNames.map(fieldName =>
transformKey(className, fieldName, schema)
);
mongoFieldNames.forEach(fieldName => {
indexCreationRequest[fieldName] = 1;
});
const defaultOptions: Object = { background: true, sparse: true };
const indexNameOptions: Object = indexName ? { name: indexName } : {};
const caseInsensitiveOptions: Object = caseInsensitive
? { collation: MongoCollection.caseInsensitiveCollation() }
: {};
const indexOptions: Object = {
...defaultOptions,
...caseInsensitiveOptions,
...indexNameOptions,
};
return this._adaptiveCollection(className)
.then(
collection =>
new Promise((resolve, reject) =>
collection._mongoCollection.createIndex(
indexCreationRequest,
indexOptions,
error => (error ? reject(error) : resolve())
)
)
)
.catch(err => this.handleError(err));
}
// Create a unique index. Unique indexes on nullable fields are not allowed. Since we don't
// currently know which fields are nullable and which aren't, we ignore that criteria.
// As such, we shouldn't expose this function to users of parse until we have an out-of-band