Store emails in lowercase - #888
Conversation
plouka13
left a comment
There was a problem hiding this comment.
Hey Iggy! This is great!
There is one path that I believe is still missing and it's the CSV Import page.
See images where I was able to add an uppercase and lowercase version of the same email without it flagging them as not unique.

and here where the emails are in the invite modal without being forced to lowercase.

However! When continuing through the invite flow, the emails are normalised as expected and the actual invites that get sent out are correctly filtered on unique emails.
See email sending logs (although it failed all emails because I didn't have smtp setup).
[backend]: {
[backend]: message: {
[backend]: resendEmailRequestCount: 6,
[backend]: newInvitesCount: 6,
[backend]: emailsResentCount: 0,
[backend]: alreadyAcceptedCount: 0,
[backend]: failedEmailsCount: 6,
[backend]: failedEmails: [
[backend]: 'example@fuuhyuhfjenc.com',
[backend]: 'example@qwdsa.com',
[backend]: 'example2@example.com',
[backend]: 'feujjisf@example.com',
[backend]: 'uppercase@email.com',
[backend]: 'example@exewample.com'
[backend]: ]
[backend]: },
[backend]: level: 'info',
[backend]: timestamp: '2026-08-04T00:03:25.083Z'
[backend]: }
|
@ignatiusm Quick note on issue #915. I haven't touched these three files since your #888 PR covers them: The |
Resolves #825 and resolves #542
Context
This PR has a bit of a strange origin story:
Last year, I was doing some testing and was able to create separate accounts for: joe@test.com; Joe@test.com; and joe@Test.com: #542 At some part of the app there was a search for duplicate emails, and given I was was able to create separate accounts I figured the duplicate email search should be case sensitive (backed up by some stackoverflow answers on a related question - it turns out the spec for emails is not very specific).
However, when we were getting CTRL Pen tested I encountered an issue of incompatibility with Auth0's behaviour of saving emails as lowercase: #825
On the basis of this we decided to also store emails as lowercase in CTRL. Emails are encypted at rest (using the prisma-field-encryption library. There is also an
emailHashfield to stores a hash of the email to allow for index creation and unique checks: e.g.CREATE UNIQUE INDEX "User_emailHash_key" ON "User"("emailHash");Tests and code fixes
AuthController
application/backend/src/controllers/AuthController.test.tsto check that registering an admin fails withemailHash already in usewhen an existing admin exists with an uppercase version of the email. Evidence of failing Auth test:application/backend/prisma/schema.prismato normalise the UseremailHash, but an explanatory note is also included inapplication/backend/src/controllers/AuthController.tsParticipantsController
application/backend/src/controllers/ParticipantsController.test.tsto check that when creating a batch of invites, emails with different cases do not result in two separate invites.Key fixes are in:
application/backend/src/controllers/ParticipantsController.tsto normalise email to lowercase when creating Invites for participantsapplication/backend/prisma/schema.prismato normalise the InvitesemailHashAdmin-portal invite Modal
application/admin-client/cypress/e2e/invites.cy.jstest to ensure that only lowercase emails are added to recipients list by typing and pasting.application/admin-client/src/components/InviteModal.tsxI did a bit of a refactor to simplify and clarify the logic for adding by typing vs adding by pasting and carve out some helper functions.Note: if you do not
make cleanthenyarn devandmake seedthen you may encounter errors due to prisma schema changes. You might need to runyarn prisma:generateto recreate the prisma client.I also created another issue (#890) to add invites for dev and test users. Without invites there is a chance for weird states to exist (e.g. a users should have an 'Accepted' invite) and we probably need tests for them!