From c729f514cfc32caf7c3ec6589edda71a0c5b49aa Mon Sep 17 00:00:00 2001 From: Christopher Kolstad Date: Fri, 23 Apr 2021 15:30:23 +0200 Subject: [PATCH] fix: make users emails case-insensitive (#804) --- src/lib/db/user-store.ts | 6 ++- .../20210423103647-lowercase-all-emails.js | 15 +++++++ src/test/e2e/stores/user-store.e2e.test.js | 39 ++++++++++++++++++- 3 files changed, 57 insertions(+), 3 deletions(-) create mode 100644 src/migrations/20210423103647-lowercase-all-emails.js diff --git a/src/lib/db/user-store.ts b/src/lib/db/user-store.ts index c2bc9327d0..e2990b5efa 100644 --- a/src/lib/db/user-store.ts +++ b/src/lib/db/user-store.ts @@ -28,10 +28,12 @@ const emptify = value => { return value; }; +const safeToLower = (s?: string) => (s ? s.toLowerCase() : s); + const mapUserToColumns = (user: ICreateUser) => ({ name: user.name, username: user.username, - email: user.email, + email: safeToLower(user.email), image_url: user.imageUrl, }); @@ -114,7 +116,7 @@ class UserStore { return query.where('id', q.id); } if (q.email) { - return query.where('email', q.email); + return query.where('email', safeToLower(q.email)); } if (q.username) { return query.where('username', q.username); diff --git a/src/migrations/20210423103647-lowercase-all-emails.js b/src/migrations/20210423103647-lowercase-all-emails.js new file mode 100644 index 0000000000..eddc78daa7 --- /dev/null +++ b/src/migrations/20210423103647-lowercase-all-emails.js @@ -0,0 +1,15 @@ +exports.up = function(db, cb) { + db.runSql( + ` + DELETE FROM users WHERE id IN + (SELECT id FROM + (SELECT id, lower(email) as email, row_number() over (PARTITION BY lower(email) ORDER BY id desc) as Row FROM users) as dupes + WHERE email IS NOT NULL AND dupes.Row > 1); + UPDATE users SET email = LOWER(email); + + `, + cb, + ); +}; + +exports.down = function() {}; diff --git a/src/test/e2e/stores/user-store.e2e.test.js b/src/test/e2e/stores/user-store.e2e.test.js index bb3b9a2292..750a0d383c 100644 --- a/src/test/e2e/stores/user-store.e2e.test.js +++ b/src/test/e2e/stores/user-store.e2e.test.js @@ -128,7 +128,7 @@ test.serial('should reset user after successful login', async t => { test.serial('should only update specified fields on user', async t => { const store = stores.userStore; - const email = 'userTobeUpdated@mail.com'; + const email = 'usertobeupdated@mail.com'; const user = { email, username: 'test', @@ -143,3 +143,40 @@ test.serial('should only update specified fields on user', async t => { t.deepEqual(storedUser.email, user.email); t.deepEqual(storedUser.username, user.username); }); + +test.serial('should always lowercase emails on inserts', async t => { + const store = stores.userStore; + const email = 'someCrazyCasingGoingOn@mail.com'; + const user = { + email, + }; + + await store.upsert(user); + + const storedUser = await store.get({ email }); + + t.deepEqual(storedUser.email, user.email.toLowerCase()); +}); + +test.serial('should always lowercase emails on updates', async t => { + const store = stores.userStore; + const email = 'someCrazyCasingGoingOn@mail.com'; + const user = { + email, + }; + + await store.upsert(user); + + let storedUser = await store.get({ email }); + + t.deepEqual(storedUser.email, user.email.toLowerCase()); + + const updatedUser = { + id: storedUser.id, + email: 'SomeOtherCasing@hotmail.com', + }; + await store.upsert(updatedUser); + + storedUser = await store.get({ id: storedUser.id }); + t.is(storedUser.email, updatedUser.email.toLowerCase()); +});