fix(auth): generate new recovery codes when enabling mfa (#964)

This commit is contained in:
Karol Sójko 2023-12-11 13:59:57 +01:00 committed by GitHub
parent 948e843ad6
commit 031fa71e7d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 35 additions and 1 deletions

View file

@ -1269,6 +1269,7 @@ export class ContainerConfigLoader {
container.get<DomainEventPublisherInterface>(TYPES.Auth_DomainEventPublisher),
container.get<DomainEventFactoryInterface>(TYPES.Auth_DomainEventFactory),
container.get<TriggerEmailBackupForUser>(TYPES.Auth_TriggerEmailBackupForUser),
container.get<GenerateRecoveryCodes>(TYPES.Auth_GenerateRecoveryCodes),
),
)
container

View file

@ -7,6 +7,7 @@ import {
import { EmailBackupFrequency, LogSessionUserAgentOption, MuteMarketingEmailsOption } from '@standardnotes/settings'
import { SettingName, Result } from '@standardnotes/domain-core'
import { GenerateRecoveryCodes } from '../GenerateRecoveryCodes/GenerateRecoveryCodes'
import { TriggerPostSettingUpdateActions } from './TriggerPostSettingUpdateActions'
import { DomainEventFactoryInterface } from '../../Event/DomainEventFactoryInterface'
import { TriggerEmailBackupForUser } from '../TriggerEmailBackupForUser/TriggerEmailBackupForUser'
@ -15,11 +16,20 @@ describe('TriggerPostSettingUpdateActions', () => {
let domainEventPublisher: DomainEventPublisherInterface
let domainEventFactory: DomainEventFactoryInterface
let triggerEmailBackupForUser: TriggerEmailBackupForUser
let generateRecoveryCodes: GenerateRecoveryCodes
const createUseCase = () =>
new TriggerPostSettingUpdateActions(domainEventPublisher, domainEventFactory, triggerEmailBackupForUser)
new TriggerPostSettingUpdateActions(
domainEventPublisher,
domainEventFactory,
triggerEmailBackupForUser,
generateRecoveryCodes,
)
beforeEach(() => {
generateRecoveryCodes = {} as jest.Mocked<GenerateRecoveryCodes>
generateRecoveryCodes.execute = jest.fn().mockReturnValue(Result.ok())
triggerEmailBackupForUser = {} as jest.Mocked<TriggerEmailBackupForUser>
triggerEmailBackupForUser.execute = jest.fn().mockReturnValue(Result.ok())
@ -101,4 +111,15 @@ describe('TriggerPostSettingUpdateActions', () => {
username: 'test@test.te',
})
})
it('should generate new recovery codes upon enabling mfa setting', async () => {
await createUseCase().execute({
updatedSettingName: SettingName.NAMES.MfaSecret,
userUuid: '4-5-6',
userEmail: 'test@test.te',
unencryptedValue: '123',
})
expect(generateRecoveryCodes.execute).toHaveBeenCalled()
})
})

View file

@ -5,6 +5,7 @@ import { EmailBackupFrequency, LogSessionUserAgentOption } from '@standardnotes/
import { TriggerPostSettingUpdateActionsDTO } from './TriggerPostSettingUpdateActionsDTO'
import { DomainEventFactoryInterface } from '../../Event/DomainEventFactoryInterface'
import { TriggerEmailBackupForUser } from '../TriggerEmailBackupForUser/TriggerEmailBackupForUser'
import { GenerateRecoveryCodes } from '../GenerateRecoveryCodes/GenerateRecoveryCodes'
export class TriggerPostSettingUpdateActions implements UseCaseInterface<void> {
private readonly emailSettingToSubscriptionRejectionLevelMap: Map<string, string> = new Map([
@ -18,6 +19,7 @@ export class TriggerPostSettingUpdateActions implements UseCaseInterface<void> {
private domainEventPublisher: DomainEventPublisherInterface,
private domainEventFactory: DomainEventFactoryInterface,
private triggerEmailBackupForUser: TriggerEmailBackupForUser,
private generateRecoveryCodes: GenerateRecoveryCodes,
) {}
async execute(dto: TriggerPostSettingUpdateActionsDTO): Promise<Result<void>> {
@ -35,6 +37,12 @@ export class TriggerPostSettingUpdateActions implements UseCaseInterface<void> {
await this.triggerSessionUserAgentCleanup(dto.userEmail, dto.userUuid)
}
if (this.isEnablingMFASetting(dto.updatedSettingName, dto.unencryptedValue)) {
await this.generateRecoveryCodes.execute({
userUuid: dto.userUuid,
})
}
return Result.ok()
}
@ -54,6 +62,10 @@ export class TriggerPostSettingUpdateActions implements UseCaseInterface<void> {
)
}
private isEnablingMFASetting(settingName: string, newValue: string | null): boolean {
return settingName === SettingName.NAMES.MfaSecret && newValue !== null
}
private isDisablingSessionUserAgentLogging(settingName: string, newValue: string | null): boolean {
return SettingName.NAMES.LogSessionUserAgent === settingName && LogSessionUserAgentOption.Disabled === newValue
}