fix: trim/lowercase email on email change (#2886)
This commit is contained in:
@@ -40,6 +40,10 @@ import { EncryptionProviderInterface } from '../Encryption/EncryptionProviderInt
|
||||
import { ReencryptTypeAItems } from '../Encryption/UseCase/TypeA/ReencryptTypeAItems'
|
||||
import { DecryptErroredPayloads } from '../Encryption/UseCase/DecryptErroredPayloads'
|
||||
|
||||
const cleanedEmailString = (email: string) => {
|
||||
return email.trim().toLowerCase()
|
||||
}
|
||||
|
||||
export class UserService
|
||||
extends AbstractService<AccountEvent, AccountEventData>
|
||||
implements UserServiceInterface, InternalEventHandlerInterface
|
||||
@@ -593,13 +597,15 @@ export class UserService
|
||||
}
|
||||
}
|
||||
|
||||
const newEmail = parameters.newEmail ? cleanedEmailString(parameters.newEmail) : undefined
|
||||
|
||||
const user = this.sessions.getUser() as User
|
||||
const currentEmail = user.email
|
||||
const { currentRootKey, newRootKey } = await this.recomputeRootKeysForCredentialChange({
|
||||
currentPassword: parameters.currentPassword,
|
||||
currentEmail,
|
||||
origination: parameters.origination,
|
||||
newEmail: parameters.newEmail,
|
||||
newEmail: newEmail,
|
||||
newPassword: parameters.newPassword,
|
||||
})
|
||||
|
||||
@@ -609,7 +615,7 @@ export class UserService
|
||||
currentServerPassword: currentRootKey.serverPassword as string,
|
||||
newRootKey: newRootKey,
|
||||
wrappingKey,
|
||||
newEmail: parameters.newEmail,
|
||||
newEmail: newEmail,
|
||||
})
|
||||
|
||||
this.unlockSyncing()
|
||||
|
||||
@@ -70,15 +70,12 @@ import {
|
||||
UserApiServiceInterface,
|
||||
UserRegistrationResponseBody,
|
||||
} from '@standardnotes/api'
|
||||
import { cleanedEmailString } from './cleanedEmailString'
|
||||
|
||||
export const MINIMUM_PASSWORD_LENGTH = 8
|
||||
export const MissingAccountParams = 'missing-params'
|
||||
const ThirtyMinutes = 30 * 60 * 1000
|
||||
|
||||
const cleanedEmailString = (email: string) => {
|
||||
return email.trim().toLowerCase()
|
||||
}
|
||||
|
||||
/**
|
||||
* The session manager is responsible for loading initial user state, and any relevant
|
||||
* server credentials, such as the session token. It also exposes methods for registering
|
||||
@@ -659,7 +656,7 @@ export class SessionManager
|
||||
currentServerPassword: parameters.currentServerPassword,
|
||||
newServerPassword: parameters.newRootKey.serverPassword as string,
|
||||
newKeyParams: parameters.newRootKey.keyParams,
|
||||
newEmail: parameters.newEmail,
|
||||
newEmail: parameters.newEmail ? cleanedEmailString(parameters.newEmail) : undefined,
|
||||
})
|
||||
|
||||
const oldKeys = this._getKeyPairs.execute()
|
||||
|
||||
3
packages/snjs/lib/Services/Session/cleanedEmailString.ts
Normal file
3
packages/snjs/lib/Services/Session/cleanedEmailString.ts
Normal file
@@ -0,0 +1,3 @@
|
||||
export const cleanedEmailString = (email: string) => {
|
||||
return email.trim().toLowerCase()
|
||||
}
|
||||
@@ -453,6 +453,37 @@ describe('keys', function () {
|
||||
await Factory.safeDeinit(application)
|
||||
})
|
||||
|
||||
it('changing email to all uppercase should allow sign in with lowercase', async function () {
|
||||
await Factory.safeDeinit(application)
|
||||
const realCryptoContext = await Factory.createAppContextWithRealCrypto()
|
||||
await realCryptoContext.launch()
|
||||
|
||||
application = realCryptoContext.application
|
||||
|
||||
await Factory.registerUserToApplication({
|
||||
application: application,
|
||||
email: email,
|
||||
password: password,
|
||||
})
|
||||
const mixedCaseEmail = `TheFooBar@bar.${UuidGenerator.GenerateUuid()}`
|
||||
|
||||
const changeEmailResponse = await application.changeEmail(mixedCaseEmail, password)
|
||||
|
||||
expect(changeEmailResponse.error).to.not.be.ok
|
||||
|
||||
application = await Factory.signOutApplicationAndReturnNew(application)
|
||||
const loginResponse = await Factory.loginToApplication({
|
||||
application: application,
|
||||
email: mixedCaseEmail.toLowerCase(),
|
||||
password: password,
|
||||
})
|
||||
|
||||
expect(loginResponse).to.be.ok
|
||||
expect(loginResponse.status).to.equal(200)
|
||||
|
||||
await Factory.safeDeinit(application)
|
||||
}).timeout(Factory.TwentySecondTimeout)
|
||||
|
||||
it('compares root keys', async function () {
|
||||
const keyParams = {}
|
||||
const a1 = await CreateNewRootKey({
|
||||
|
||||
@@ -51,7 +51,14 @@ export async function createAppContextWithRealCrypto(identifier) {
|
||||
return createAppContext({ identifier, crypto: new SNWebCrypto() })
|
||||
}
|
||||
|
||||
export async function createAppContext({ identifier, crypto, email, password, host, syncCallsThresholdPerMinute } = {}) {
|
||||
export async function createAppContext({
|
||||
identifier,
|
||||
crypto,
|
||||
email,
|
||||
password,
|
||||
host,
|
||||
syncCallsThresholdPerMinute,
|
||||
} = {}) {
|
||||
const context = new AppContext({ identifier, crypto, email, password, host, syncCallsThresholdPerMinute })
|
||||
await context.initialize()
|
||||
return context
|
||||
@@ -250,7 +257,14 @@ export async function awaitFunctionInvokation(object, functionName) {
|
||||
* A new one must be created.
|
||||
*/
|
||||
export async function signOutApplicationAndReturnNew(application) {
|
||||
const isRealCrypto = application.crypto instanceof SNWebCrypto
|
||||
if (!application) {
|
||||
throw Error('[signOutApplicationAndReturnNew] Application is undefined')
|
||||
}
|
||||
if (!application.options.crypto) {
|
||||
throw Error('[signOutApplicationAndReturnNew] Application.options.crypto is undefined')
|
||||
}
|
||||
|
||||
const isRealCrypto = application.options.crypto instanceof SNWebCrypto
|
||||
await application.user.signOut()
|
||||
if (isRealCrypto) {
|
||||
return createInitAppWithRealCrypto()
|
||||
@@ -260,7 +274,7 @@ export async function signOutApplicationAndReturnNew(application) {
|
||||
}
|
||||
|
||||
export async function signOutAndBackIn(application, email, password) {
|
||||
const isRealCrypto = application.crypto instanceof SNWebCrypto
|
||||
const isRealCrypto = application.options.crypto instanceof SNWebCrypto
|
||||
await application.user.signOut()
|
||||
const newApplication = isRealCrypto ? await createInitAppWithRealCrypto() : await createInitAppWithFakeCrypto()
|
||||
await this.loginToApplication({
|
||||
|
||||
Reference in New Issue
Block a user