mirror of
https://github.com/standardnotes/server
synced 2026-10-16 18:13:09 -04:00
feat: sign in setting refactor (#472)
* fix(auth): refactor setting names into domain core value objects * fix(auth): refactor specs with setting name value objects * feat(auth): move mute sign in emails to a subscription kind of setting * feat(auth): add migration script to change sign in email settings to subscription settings * chore: fix setting name usage * fix(auth): upper casing setting names --------- Co-authored-by: Karol Sójko <[email protected]>
This commit is contained in:
co-authored by
Karol Sójko
parent
ec0fb7e0b9
commit
27cf093f85
@@ -3,7 +3,7 @@ import { SubscriptionName } from '@standardnotes/common'
|
||||
import { TimerInterface } from '@standardnotes/time'
|
||||
import { TokenEncoderInterface, ValetTokenData } from '@standardnotes/security'
|
||||
import { CreateValetTokenPayload, CreateValetTokenResponseData } from '@standardnotes/responses'
|
||||
import { SubscriptionSettingName } from '@standardnotes/settings'
|
||||
import { SettingName } from '@standardnotes/settings'
|
||||
|
||||
import TYPES from '../../../Bootstrap/Types'
|
||||
import { UseCaseInterface } from '../UseCaseInterface'
|
||||
@@ -56,7 +56,7 @@ export class CreateValetToken implements UseCaseInterface {
|
||||
const uploadBytesUsedSetting = await this.subscriptionSettingService.findSubscriptionSettingWithDecryptedValue({
|
||||
userUuid: regularSubscriptionUserUuid,
|
||||
userSubscriptionUuid: regularSubscription.uuid,
|
||||
subscriptionSettingName: SubscriptionSettingName.FileUploadBytesUsed,
|
||||
subscriptionSettingName: SettingName.create(SettingName.NAMES.FileUploadBytesUsed).getValue(),
|
||||
})
|
||||
if (uploadBytesUsedSetting !== null) {
|
||||
uploadBytesUsed = +(uploadBytesUsedSetting.value as string)
|
||||
@@ -70,7 +70,7 @@ export class CreateValetToken implements UseCaseInterface {
|
||||
await this.subscriptionSettingService.findSubscriptionSettingWithDecryptedValue({
|
||||
userUuid: regularSubscriptionUserUuid,
|
||||
userSubscriptionUuid: regularSubscription.uuid,
|
||||
subscriptionSettingName: SubscriptionSettingName.FileUploadBytesLimit,
|
||||
subscriptionSettingName: SettingName.create(SettingName.NAMES.FileUploadBytesLimit).getValue(),
|
||||
})
|
||||
if (overwriteWithUserUploadBytesLimitSetting !== null) {
|
||||
uploadBytesLimit = +(overwriteWithUserUploadBytesLimitSetting.value as string)
|
||||
|
||||
@@ -35,7 +35,7 @@ export class GenerateRecoveryCodes implements UseCaseInterface<string> {
|
||||
await this.settingService.createOrReplace({
|
||||
user,
|
||||
props: {
|
||||
name: SettingName.RecoveryCodes,
|
||||
name: SettingName.NAMES.RecoveryCodes,
|
||||
unencryptedValue: recoveryCodes,
|
||||
serverEncryptionVersion: EncryptionVersion.Default,
|
||||
sensitive: false,
|
||||
|
||||
@@ -1,75 +1,239 @@
|
||||
import { SettingName } from '@standardnotes/settings'
|
||||
import 'reflect-metadata'
|
||||
|
||||
import { SettingName } from '@standardnotes/settings'
|
||||
|
||||
import { SettingProjector } from '../../../Projection/SettingProjector'
|
||||
import { Setting } from '../../Setting/Setting'
|
||||
import { SettingServiceInterface } from '../../Setting/SettingServiceInterface'
|
||||
|
||||
import { GetSetting } from './GetSetting'
|
||||
import { UserSubscriptionServiceInterface } from '../../Subscription/UserSubscriptionServiceInterface'
|
||||
import { SubscriptionSettingProjector } from '../../../Projection/SubscriptionSettingProjector'
|
||||
import { SubscriptionSettingServiceInterface } from '../../Setting/SubscriptionSettingServiceInterface'
|
||||
import { SubscriptionSetting } from '../../Setting/SubscriptionSetting'
|
||||
import { UserSubscription } from '../../Subscription/UserSubscription'
|
||||
import { UserSubscriptionType } from '../../Subscription/UserSubscriptionType'
|
||||
|
||||
describe('GetSetting', () => {
|
||||
let settingProjector: SettingProjector
|
||||
let setting: Setting
|
||||
let subscriptionSetting: SubscriptionSetting
|
||||
let settingService: SettingServiceInterface
|
||||
let userSubscriptionService: UserSubscriptionServiceInterface
|
||||
let subscriptionSettingProjector: SubscriptionSettingProjector
|
||||
let subscriptionSettingService: SubscriptionSettingServiceInterface
|
||||
let regularSubscription: UserSubscription
|
||||
let sharedSubscription: UserSubscription
|
||||
|
||||
const createUseCase = () => new GetSetting(settingProjector, settingService)
|
||||
const createUseCase = () =>
|
||||
new GetSetting(
|
||||
settingProjector,
|
||||
subscriptionSettingProjector,
|
||||
settingService,
|
||||
subscriptionSettingService,
|
||||
userSubscriptionService,
|
||||
)
|
||||
|
||||
beforeEach(() => {
|
||||
setting = {} as jest.Mocked<Setting>
|
||||
|
||||
subscriptionSetting = {
|
||||
sensitive: false,
|
||||
} as jest.Mocked<SubscriptionSetting>
|
||||
|
||||
settingService = {} as jest.Mocked<SettingServiceInterface>
|
||||
settingService.findSettingWithDecryptedValue = jest.fn().mockReturnValue(setting)
|
||||
|
||||
settingProjector = {} as jest.Mocked<SettingProjector>
|
||||
settingProjector.projectSimple = jest.fn().mockReturnValue({ foo: 'bar' })
|
||||
|
||||
subscriptionSettingService = {} as jest.Mocked<SubscriptionSettingServiceInterface>
|
||||
subscriptionSettingService.findSubscriptionSettingWithDecryptedValue = jest
|
||||
.fn()
|
||||
.mockReturnValue(subscriptionSetting)
|
||||
|
||||
regularSubscription = {
|
||||
uuid: '1-2-3',
|
||||
subscriptionType: UserSubscriptionType.Regular,
|
||||
} as jest.Mocked<UserSubscription>
|
||||
|
||||
sharedSubscription = {
|
||||
uuid: '2-3-4',
|
||||
subscriptionType: UserSubscriptionType.Shared,
|
||||
} as jest.Mocked<UserSubscription>
|
||||
|
||||
userSubscriptionService = {} as jest.Mocked<UserSubscriptionServiceInterface>
|
||||
userSubscriptionService.findRegularSubscriptionForUserUuid = jest
|
||||
.fn()
|
||||
.mockReturnValue({ regularSubscription: null, sharedSubscription: null })
|
||||
|
||||
subscriptionSettingProjector = {} as jest.Mocked<SubscriptionSettingProjector>
|
||||
subscriptionSettingProjector.projectSimple = jest.fn().mockReturnValue({ foo: 'sub-bar' })
|
||||
})
|
||||
|
||||
it('should find a setting for user', async () => {
|
||||
expect(await createUseCase().execute({ userUuid: '1-2-3', settingName: 'test' })).toEqual({
|
||||
success: true,
|
||||
userUuid: '1-2-3',
|
||||
setting: { foo: 'bar' },
|
||||
describe('no subscription', () => {
|
||||
it('should find a setting for user', async () => {
|
||||
expect(
|
||||
await createUseCase().execute({ userUuid: '1-2-3', settingName: SettingName.NAMES.DropboxBackupFrequency }),
|
||||
).toEqual({
|
||||
success: true,
|
||||
userUuid: '1-2-3',
|
||||
setting: { foo: 'bar' },
|
||||
})
|
||||
})
|
||||
|
||||
it('should not find a setting if the setting name is invalid', async () => {
|
||||
expect(await createUseCase().execute({ userUuid: '1-2-3', settingName: 'invalid' })).toEqual({
|
||||
success: false,
|
||||
error: {
|
||||
message: 'Invalid setting name: invalid',
|
||||
},
|
||||
})
|
||||
})
|
||||
|
||||
it('should not get a setting for user if it does not exist', async () => {
|
||||
settingService.findSettingWithDecryptedValue = jest.fn().mockReturnValue(null)
|
||||
|
||||
expect(
|
||||
await createUseCase().execute({ userUuid: '1-2-3', settingName: SettingName.NAMES.DropboxBackupFrequency }),
|
||||
).toEqual({
|
||||
success: false,
|
||||
error: {
|
||||
message: 'Setting DROPBOX_BACKUP_FREQUENCY for user 1-2-3 not found!',
|
||||
},
|
||||
})
|
||||
})
|
||||
|
||||
it('should not retrieve a sensitive setting for user', async () => {
|
||||
setting = {
|
||||
sensitive: true,
|
||||
name: SettingName.NAMES.MfaSecret,
|
||||
} as jest.Mocked<Setting>
|
||||
|
||||
settingService.findSettingWithDecryptedValue = jest.fn().mockReturnValue(setting)
|
||||
|
||||
expect(await createUseCase().execute({ userUuid: '1-2-3', settingName: SettingName.NAMES.MfaSecret })).toEqual({
|
||||
success: true,
|
||||
sensitive: true,
|
||||
})
|
||||
})
|
||||
|
||||
it('should not retrieve a subscription setting for user', async () => {
|
||||
expect(
|
||||
await createUseCase().execute({ userUuid: '1-2-3', settingName: SettingName.NAMES.MuteSignInEmails }),
|
||||
).toEqual({
|
||||
success: false,
|
||||
error: {
|
||||
message: 'No subscription found.',
|
||||
},
|
||||
})
|
||||
})
|
||||
|
||||
it('should retrieve a sensitive setting for user if explicitly told to', async () => {
|
||||
setting = {
|
||||
sensitive: true,
|
||||
name: SettingName.NAMES.MfaSecret,
|
||||
} as jest.Mocked<Setting>
|
||||
|
||||
settingService.findSettingWithDecryptedValue = jest.fn().mockReturnValue(setting)
|
||||
|
||||
expect(
|
||||
await createUseCase().execute({
|
||||
userUuid: '1-2-3',
|
||||
settingName: SettingName.NAMES.MfaSecret,
|
||||
allowSensitiveRetrieval: true,
|
||||
}),
|
||||
).toEqual({
|
||||
success: true,
|
||||
userUuid: '1-2-3',
|
||||
setting: { foo: 'bar' },
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
it('should not get a setting for user if it does not exist', async () => {
|
||||
settingService.findSettingWithDecryptedValue = jest.fn().mockReturnValue(null)
|
||||
describe('regular subscription', () => {
|
||||
beforeEach(() => {
|
||||
userSubscriptionService.findRegularSubscriptionForUserUuid = jest
|
||||
.fn()
|
||||
.mockReturnValue({ regularSubscription, sharedSubscription: null })
|
||||
})
|
||||
|
||||
expect(await createUseCase().execute({ userUuid: '1-2-3', settingName: 'test' })).toEqual({
|
||||
success: false,
|
||||
error: {
|
||||
message: 'Setting test for user 1-2-3 not found!',
|
||||
},
|
||||
it('should find a setting for user', async () => {
|
||||
expect(
|
||||
await createUseCase().execute({ userUuid: '1-2-3', settingName: SettingName.NAMES.MuteSignInEmails }),
|
||||
).toEqual({
|
||||
success: true,
|
||||
userUuid: '1-2-3',
|
||||
setting: { foo: 'sub-bar' },
|
||||
})
|
||||
})
|
||||
|
||||
it('should not get a suscription setting for user if it does not exist', async () => {
|
||||
subscriptionSettingService.findSubscriptionSettingWithDecryptedValue = jest.fn().mockReturnValue(null)
|
||||
|
||||
expect(
|
||||
await createUseCase().execute({ userUuid: '1-2-3', settingName: SettingName.NAMES.MuteSignInEmails }),
|
||||
).toEqual({
|
||||
success: false,
|
||||
error: {
|
||||
message: 'Subscription setting MUTE_SIGN_IN_EMAILS for user 1-2-3 not found!',
|
||||
},
|
||||
})
|
||||
})
|
||||
|
||||
it('should not retrieve a sensitive subscription setting for user', async () => {
|
||||
subscriptionSetting.sensitive = true
|
||||
|
||||
subscriptionSettingService.findSubscriptionSettingWithDecryptedValue = jest
|
||||
.fn()
|
||||
.mockReturnValue(subscriptionSetting)
|
||||
|
||||
expect(
|
||||
await createUseCase().execute({ userUuid: '1-2-3', settingName: SettingName.NAMES.MuteSignInEmails }),
|
||||
).toEqual({
|
||||
success: true,
|
||||
sensitive: true,
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
it('should not retrieve a sensitive setting for user', async () => {
|
||||
setting = {
|
||||
sensitive: true,
|
||||
name: SettingName.MfaSecret,
|
||||
} as jest.Mocked<Setting>
|
||||
|
||||
settingService.findSettingWithDecryptedValue = jest.fn().mockReturnValue(setting)
|
||||
|
||||
expect(await createUseCase().execute({ userUuid: '1-2-3', settingName: SettingName.MfaSecret })).toEqual({
|
||||
success: true,
|
||||
sensitive: true,
|
||||
describe('shared subscription', () => {
|
||||
beforeEach(() => {
|
||||
userSubscriptionService.findRegularSubscriptionForUserUuid = jest
|
||||
.fn()
|
||||
.mockReturnValue({ regularSubscription, sharedSubscription })
|
||||
})
|
||||
})
|
||||
|
||||
it('should retrieve a sensitive setting for user if explicitly told to', async () => {
|
||||
setting = {
|
||||
sensitive: true,
|
||||
name: SettingName.MfaSecret,
|
||||
} as jest.Mocked<Setting>
|
||||
it('should find a setting for user', async () => {
|
||||
expect(
|
||||
await createUseCase().execute({ userUuid: '1-2-3', settingName: SettingName.NAMES.MuteSignInEmails }),
|
||||
).toEqual({
|
||||
success: true,
|
||||
userUuid: '1-2-3',
|
||||
setting: { foo: 'sub-bar' },
|
||||
})
|
||||
|
||||
settingService.findSettingWithDecryptedValue = jest.fn().mockReturnValue(setting)
|
||||
expect(subscriptionSettingService.findSubscriptionSettingWithDecryptedValue).toHaveBeenCalledWith({
|
||||
subscriptionSettingName: SettingName.create(SettingName.NAMES.MuteSignInEmails).getValue(),
|
||||
userSubscriptionUuid: '2-3-4',
|
||||
userUuid: '1-2-3',
|
||||
})
|
||||
})
|
||||
|
||||
expect(
|
||||
await createUseCase().execute({ userUuid: '1-2-3', settingName: 'MFA_SECRET', allowSensitiveRetrieval: true }),
|
||||
).toEqual({
|
||||
success: true,
|
||||
userUuid: '1-2-3',
|
||||
setting: { foo: 'bar' },
|
||||
it('should find a regular subscription only setting for user', async () => {
|
||||
expect(
|
||||
await createUseCase().execute({ userUuid: '1-2-3', settingName: SettingName.NAMES.FileUploadBytesLimit }),
|
||||
).toEqual({
|
||||
success: true,
|
||||
userUuid: '1-2-3',
|
||||
setting: { foo: 'sub-bar' },
|
||||
})
|
||||
|
||||
expect(subscriptionSettingService.findSubscriptionSettingWithDecryptedValue).toHaveBeenCalledWith({
|
||||
subscriptionSettingName: SettingName.create(SettingName.NAMES.FileUploadBytesLimit).getValue(),
|
||||
userSubscriptionUuid: '1-2-3',
|
||||
userUuid: '1-2-3',
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@@ -1,32 +1,100 @@
|
||||
import { SettingName } from '@standardnotes/settings'
|
||||
import { inject, injectable } from 'inversify'
|
||||
import { GetSettingDto } from './GetSettingDto'
|
||||
import { GetSettingResponse } from './GetSettingResponse'
|
||||
|
||||
import { UseCaseInterface } from '../UseCaseInterface'
|
||||
import TYPES from '../../../Bootstrap/Types'
|
||||
import { SettingProjector } from '../../../Projection/SettingProjector'
|
||||
import { SettingServiceInterface } from '../../Setting/SettingServiceInterface'
|
||||
import { SubscriptionSettingServiceInterface } from '../../Setting/SubscriptionSettingServiceInterface'
|
||||
import { SubscriptionSettingProjector } from '../../../Projection/SubscriptionSettingProjector'
|
||||
import { UserSubscriptionServiceInterface } from '../../Subscription/UserSubscriptionServiceInterface'
|
||||
|
||||
import { GetSettingDto } from './GetSettingDto'
|
||||
import { GetSettingResponse } from './GetSettingResponse'
|
||||
import { UserSubscription } from '../../Subscription/UserSubscription'
|
||||
|
||||
@injectable()
|
||||
export class GetSetting implements UseCaseInterface {
|
||||
constructor(
|
||||
@inject(TYPES.SettingProjector) private settingProjector: SettingProjector,
|
||||
@inject(TYPES.SubscriptionSettingProjector) private subscriptionSettingProjector: SubscriptionSettingProjector,
|
||||
@inject(TYPES.SettingService) private settingService: SettingServiceInterface,
|
||||
@inject(TYPES.SubscriptionSettingService) private subscriptionSettingService: SubscriptionSettingServiceInterface,
|
||||
@inject(TYPES.UserSubscriptionService) private userSubscriptionService: UserSubscriptionServiceInterface,
|
||||
) {}
|
||||
|
||||
async execute(dto: GetSettingDto): Promise<GetSettingResponse> {
|
||||
const { userUuid, settingName } = dto
|
||||
const settingNameOrError = SettingName.create(dto.settingName)
|
||||
if (settingNameOrError.isFailed()) {
|
||||
return {
|
||||
success: false,
|
||||
error: {
|
||||
message: settingNameOrError.getError(),
|
||||
},
|
||||
}
|
||||
}
|
||||
const settingName = settingNameOrError.getValue()
|
||||
|
||||
if (settingName.isASubscriptionSetting()) {
|
||||
const { regularSubscription, sharedSubscription } =
|
||||
await this.userSubscriptionService.findRegularSubscriptionForUserUuid(dto.userUuid)
|
||||
let subscription: UserSubscription | null
|
||||
if (settingName.isARegularOnlySubscriptionSetting()) {
|
||||
subscription = regularSubscription
|
||||
} else {
|
||||
subscription = sharedSubscription ?? regularSubscription
|
||||
}
|
||||
|
||||
if (!subscription) {
|
||||
return {
|
||||
success: false,
|
||||
error: {
|
||||
message: 'No subscription found.',
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
const subscriptionSetting = await this.subscriptionSettingService.findSubscriptionSettingWithDecryptedValue({
|
||||
userUuid: dto.userUuid,
|
||||
subscriptionSettingName: settingName,
|
||||
userSubscriptionUuid: subscription.uuid,
|
||||
})
|
||||
|
||||
if (subscriptionSetting === null) {
|
||||
return {
|
||||
success: false,
|
||||
error: {
|
||||
message: `Subscription setting ${settingName.value} for user ${dto.userUuid} not found!`,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
if (subscriptionSetting.sensitive && !dto.allowSensitiveRetrieval) {
|
||||
return {
|
||||
success: true,
|
||||
sensitive: true,
|
||||
}
|
||||
}
|
||||
|
||||
const simpleSubscriptionSetting = await this.subscriptionSettingProjector.projectSimple(subscriptionSetting)
|
||||
|
||||
return {
|
||||
success: true,
|
||||
userUuid: dto.userUuid,
|
||||
setting: simpleSubscriptionSetting,
|
||||
}
|
||||
}
|
||||
|
||||
const setting = await this.settingService.findSettingWithDecryptedValue({
|
||||
userUuid,
|
||||
settingName: settingName as SettingName,
|
||||
userUuid: dto.userUuid,
|
||||
settingName,
|
||||
})
|
||||
|
||||
if (setting === null) {
|
||||
return {
|
||||
success: false,
|
||||
error: {
|
||||
message: `Setting ${settingName} for user ${userUuid} not found!`,
|
||||
message: `Setting ${settingName.value} for user ${dto.userUuid} not found!`,
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -42,7 +110,7 @@ export class GetSetting implements UseCaseInterface {
|
||||
|
||||
return {
|
||||
success: true,
|
||||
userUuid,
|
||||
userUuid: dto.userUuid,
|
||||
setting: simpleSetting,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,36 +11,84 @@ import { UserRepositoryInterface } from '../../User/UserRepositoryInterface'
|
||||
import { User } from '../../User/User'
|
||||
import { CrypterInterface } from '../../Encryption/CrypterInterface'
|
||||
import { EncryptionVersion } from '../../Encryption/EncryptionVersion'
|
||||
import { SubscriptionSettingRepositoryInterface } from '../../Setting/SubscriptionSettingRepositoryInterface'
|
||||
import { UserSubscriptionServiceInterface } from '../../Subscription/UserSubscriptionServiceInterface'
|
||||
import { SubscriptionSettingProjector } from '../../../Projection/SubscriptionSettingProjector'
|
||||
import { SubscriptionSetting } from '../../Setting/SubscriptionSetting'
|
||||
import { UserSubscription } from '../../Subscription/UserSubscription'
|
||||
import { UserSubscriptionType } from '../../Subscription/UserSubscriptionType'
|
||||
|
||||
describe('GetSettings', () => {
|
||||
let settingRepository: SettingRepositoryInterface
|
||||
let subscriptionSettingRepository: SubscriptionSettingRepositoryInterface
|
||||
let userSubscriptionService: UserSubscriptionServiceInterface
|
||||
let settingProjector: SettingProjector
|
||||
let subscriptionSettingProjector: SubscriptionSettingProjector
|
||||
let setting: Setting
|
||||
let mfaSetting: Setting
|
||||
let signInEmailsSetting: SubscriptionSetting
|
||||
let userRepository: UserRepositoryInterface
|
||||
let user: User
|
||||
let crypter: CrypterInterface
|
||||
let regularSubscription: UserSubscription
|
||||
let sharedSubscription: UserSubscription
|
||||
|
||||
const createUseCase = () => new GetSettings(settingRepository, settingProjector, userRepository, crypter)
|
||||
const createUseCase = () =>
|
||||
new GetSettings(
|
||||
settingRepository,
|
||||
subscriptionSettingRepository,
|
||||
userSubscriptionService,
|
||||
settingProjector,
|
||||
subscriptionSettingProjector,
|
||||
userRepository,
|
||||
crypter,
|
||||
)
|
||||
|
||||
beforeEach(() => {
|
||||
setting = {
|
||||
name: 'test',
|
||||
updatedAt: 345,
|
||||
sensitive: false,
|
||||
} as jest.Mocked<Setting>
|
||||
setting = new Setting()
|
||||
setting.name = 'test'
|
||||
setting.updatedAt = 345
|
||||
setting.sensitive = false
|
||||
|
||||
mfaSetting = {
|
||||
name: SettingName.MfaSecret,
|
||||
updatedAt: 122,
|
||||
sensitive: true,
|
||||
} as jest.Mocked<Setting>
|
||||
mfaSetting = new Setting()
|
||||
mfaSetting.name = SettingName.NAMES.MfaSecret
|
||||
mfaSetting.updatedAt = 122
|
||||
mfaSetting.sensitive = true
|
||||
|
||||
signInEmailsSetting = new SubscriptionSetting()
|
||||
signInEmailsSetting.name = SettingName.NAMES.MuteSignInEmails
|
||||
signInEmailsSetting.updatedAt = 122
|
||||
signInEmailsSetting.sensitive = false
|
||||
signInEmailsSetting.value = 'not_muted'
|
||||
|
||||
settingRepository = {} as jest.Mocked<SettingRepositoryInterface>
|
||||
settingRepository.findAllByUserUuid = jest.fn().mockReturnValue([setting, mfaSetting])
|
||||
|
||||
subscriptionSettingRepository = {} as jest.Mocked<SubscriptionSettingRepositoryInterface>
|
||||
subscriptionSettingRepository.findAllBySubscriptionUuid = jest.fn().mockReturnValue([signInEmailsSetting])
|
||||
|
||||
regularSubscription = {
|
||||
uuid: '1-2-3',
|
||||
subscriptionType: UserSubscriptionType.Regular,
|
||||
user: Promise.resolve(user),
|
||||
} as jest.Mocked<UserSubscription>
|
||||
|
||||
sharedSubscription = {
|
||||
uuid: '2-3-4',
|
||||
subscriptionType: UserSubscriptionType.Shared,
|
||||
user: Promise.resolve(user),
|
||||
} as jest.Mocked<UserSubscription>
|
||||
|
||||
userSubscriptionService = {} as jest.Mocked<UserSubscriptionServiceInterface>
|
||||
userSubscriptionService.findRegularSubscriptionForUserUuid = jest
|
||||
.fn()
|
||||
.mockReturnValue({ regularSubscription: null, sharedSubscription: null })
|
||||
|
||||
settingProjector = {} as jest.Mocked<SettingProjector>
|
||||
settingProjector.projectManySimple = jest.fn().mockReturnValue([{ foo: 'bar' }])
|
||||
settingProjector.projectSimple = jest.fn().mockReturnValue({ foo: 'bar' })
|
||||
|
||||
subscriptionSettingProjector = {} as jest.Mocked<SubscriptionSettingProjector>
|
||||
subscriptionSettingProjector.projectSimple = jest.fn().mockReturnValue({ foo: 'sub-bar' })
|
||||
|
||||
user = {} as jest.Mocked<User>
|
||||
|
||||
@@ -51,83 +99,126 @@ describe('GetSettings', () => {
|
||||
crypter.decryptForUser = jest.fn().mockReturnValue('decrypted')
|
||||
})
|
||||
|
||||
it('should fail if a user is not found', async () => {
|
||||
userRepository.findOneByUuid = jest.fn().mockReturnValue(null)
|
||||
describe('no subscription', () => {
|
||||
it('should fail if a user is not found', async () => {
|
||||
userRepository.findOneByUuid = jest.fn().mockReturnValue(null)
|
||||
|
||||
expect(await createUseCase().execute({ userUuid: '1-2-3' })).toEqual({
|
||||
success: false,
|
||||
error: {
|
||||
message: 'User 1-2-3 not found.',
|
||||
},
|
||||
})
|
||||
})
|
||||
|
||||
it('should return all user settings except mfa', async () => {
|
||||
expect(await createUseCase().execute({ userUuid: '1-2-3' })).toEqual({
|
||||
success: true,
|
||||
userUuid: '1-2-3',
|
||||
settings: [{ foo: 'bar' }],
|
||||
expect(await createUseCase().execute({ userUuid: '1-2-3' })).toEqual({
|
||||
success: false,
|
||||
error: {
|
||||
message: 'User 1-2-3 not found.',
|
||||
},
|
||||
})
|
||||
})
|
||||
|
||||
expect(settingProjector.projectManySimple).toHaveBeenCalledWith([setting])
|
||||
})
|
||||
it('should return all user settings except mfa', async () => {
|
||||
expect(await createUseCase().execute({ userUuid: '1-2-3' })).toEqual({
|
||||
success: true,
|
||||
userUuid: '1-2-3',
|
||||
settings: [{ foo: 'bar' }],
|
||||
})
|
||||
|
||||
it('should return all setting with decrypted values', async () => {
|
||||
setting = {
|
||||
name: 'test',
|
||||
updatedAt: 345,
|
||||
value: 'encrypted',
|
||||
serverEncryptionVersion: EncryptionVersion.Default,
|
||||
} as jest.Mocked<Setting>
|
||||
settingRepository.findAllByUserUuid = jest.fn().mockReturnValue([setting])
|
||||
|
||||
expect(await createUseCase().execute({ userUuid: '1-2-3' })).toEqual({
|
||||
success: true,
|
||||
userUuid: '1-2-3',
|
||||
settings: [{ foo: 'bar' }],
|
||||
expect(settingProjector.projectSimple).toHaveBeenCalledWith(setting)
|
||||
expect(subscriptionSettingProjector.projectSimple).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
expect(settingProjector.projectManySimple).toHaveBeenCalledWith([
|
||||
{
|
||||
it('should return all setting with decrypted values', async () => {
|
||||
setting = {
|
||||
name: 'test',
|
||||
updatedAt: 345,
|
||||
value: 'encrypted',
|
||||
serverEncryptionVersion: EncryptionVersion.Default,
|
||||
} as jest.Mocked<Setting>
|
||||
settingRepository.findAllByUserUuid = jest.fn().mockReturnValue([setting])
|
||||
|
||||
expect(await createUseCase().execute({ userUuid: '1-2-3' })).toEqual({
|
||||
success: true,
|
||||
userUuid: '1-2-3',
|
||||
settings: [{ foo: 'bar' }],
|
||||
})
|
||||
|
||||
expect(settingProjector.projectSimple).toHaveBeenCalledWith({
|
||||
name: 'test',
|
||||
updatedAt: 345,
|
||||
value: 'decrypted',
|
||||
serverEncryptionVersion: 1,
|
||||
},
|
||||
])
|
||||
})
|
||||
|
||||
it('should return all user settings of certain name', async () => {
|
||||
expect(
|
||||
await createUseCase().execute({ userUuid: '1-2-3', settingName: 'test', allowSensitiveRetrieval: true }),
|
||||
).toEqual({
|
||||
success: true,
|
||||
userUuid: '1-2-3',
|
||||
settings: [{ foo: 'bar' }],
|
||||
})
|
||||
})
|
||||
|
||||
expect(settingProjector.projectManySimple).toHaveBeenCalledWith([setting])
|
||||
})
|
||||
it('should return all user settings of certain name', async () => {
|
||||
expect(
|
||||
await createUseCase().execute({ userUuid: '1-2-3', settingName: 'test', allowSensitiveRetrieval: true }),
|
||||
).toEqual({
|
||||
success: true,
|
||||
userUuid: '1-2-3',
|
||||
settings: [{ foo: 'bar' }],
|
||||
})
|
||||
|
||||
it('should return all user settings updated after', async () => {
|
||||
expect(
|
||||
await createUseCase().execute({ userUuid: '1-2-3', allowSensitiveRetrieval: true, updatedAfter: 123 }),
|
||||
).toEqual({
|
||||
success: true,
|
||||
userUuid: '1-2-3',
|
||||
settings: [{ foo: 'bar' }],
|
||||
expect(settingProjector.projectSimple).toHaveBeenCalledWith(setting)
|
||||
})
|
||||
|
||||
expect(settingProjector.projectManySimple).toHaveBeenCalledWith([setting])
|
||||
})
|
||||
it('should return all user settings updated after', async () => {
|
||||
expect(
|
||||
await createUseCase().execute({ userUuid: '1-2-3', allowSensitiveRetrieval: true, updatedAfter: 123 }),
|
||||
).toEqual({
|
||||
success: true,
|
||||
userUuid: '1-2-3',
|
||||
settings: [{ foo: 'bar' }],
|
||||
})
|
||||
|
||||
it('should return all sensitive user settings if explicit', async () => {
|
||||
expect(await createUseCase().execute({ userUuid: '1-2-3', allowSensitiveRetrieval: true })).toEqual({
|
||||
success: true,
|
||||
userUuid: '1-2-3',
|
||||
settings: [{ foo: 'bar' }],
|
||||
expect(settingProjector.projectSimple).toHaveBeenCalledWith(setting)
|
||||
})
|
||||
|
||||
expect(settingProjector.projectManySimple).toHaveBeenCalledWith([setting, mfaSetting])
|
||||
it('should return all sensitive user settings if explicit', async () => {
|
||||
expect(await createUseCase().execute({ userUuid: '1-2-3', allowSensitiveRetrieval: true })).toEqual({
|
||||
success: true,
|
||||
userUuid: '1-2-3',
|
||||
settings: [{ foo: 'bar' }, { foo: 'bar' }],
|
||||
})
|
||||
|
||||
expect(settingProjector.projectSimple).toHaveBeenCalledTimes(2)
|
||||
expect(settingProjector.projectSimple).toHaveBeenNthCalledWith(1, setting)
|
||||
expect(settingProjector.projectSimple).toHaveBeenNthCalledWith(2, mfaSetting)
|
||||
})
|
||||
})
|
||||
|
||||
describe('regular subscription', () => {
|
||||
beforeEach(() => {
|
||||
userSubscriptionService.findRegularSubscriptionForUserUuid = jest
|
||||
.fn()
|
||||
.mockReturnValue({ regularSubscription, sharedSubscription: null })
|
||||
})
|
||||
|
||||
it('should return all user settings except mfa', async () => {
|
||||
expect(await createUseCase().execute({ userUuid: '1-2-3' })).toEqual({
|
||||
success: true,
|
||||
userUuid: '1-2-3',
|
||||
settings: [{ foo: 'bar' }, { foo: 'sub-bar' }],
|
||||
})
|
||||
|
||||
expect(subscriptionSettingRepository.findAllBySubscriptionUuid).toHaveBeenCalledWith('1-2-3')
|
||||
expect(settingProjector.projectSimple).toHaveBeenCalledWith(setting)
|
||||
expect(subscriptionSettingProjector.projectSimple).toHaveBeenCalledWith(signInEmailsSetting)
|
||||
})
|
||||
})
|
||||
|
||||
describe('shared subscription', () => {
|
||||
beforeEach(() => {
|
||||
userSubscriptionService.findRegularSubscriptionForUserUuid = jest
|
||||
.fn()
|
||||
.mockReturnValue({ regularSubscription, sharedSubscription })
|
||||
})
|
||||
|
||||
it('should return all user settings except mfa', async () => {
|
||||
expect(await createUseCase().execute({ userUuid: '1-2-3' })).toEqual({
|
||||
success: true,
|
||||
userUuid: '1-2-3',
|
||||
settings: [{ foo: 'bar' }, { foo: 'sub-bar' }],
|
||||
})
|
||||
|
||||
expect(subscriptionSettingRepository.findAllBySubscriptionUuid).toHaveBeenCalledWith('2-3-4')
|
||||
expect(settingProjector.projectSimple).toHaveBeenCalledWith(setting)
|
||||
expect(subscriptionSettingProjector.projectSimple).toHaveBeenCalledWith(signInEmailsSetting)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@@ -9,12 +9,22 @@ import { Setting } from '../../Setting/Setting'
|
||||
import { UserRepositoryInterface } from '../../User/UserRepositoryInterface'
|
||||
import { CrypterInterface } from '../../Encryption/CrypterInterface'
|
||||
import { EncryptionVersion } from '../../Encryption/EncryptionVersion'
|
||||
import { UserSubscriptionServiceInterface } from '../../Subscription/UserSubscriptionServiceInterface'
|
||||
import { SubscriptionSettingRepositoryInterface } from '../../Setting/SubscriptionSettingRepositoryInterface'
|
||||
import { SubscriptionSetting } from '../../Setting/SubscriptionSetting'
|
||||
import { SimpleSetting } from '../../Setting/SimpleSetting'
|
||||
import { SimpleSubscriptionSetting } from '../../Setting/SimpleSubscriptionSetting'
|
||||
import { SubscriptionSettingProjector } from '../../../Projection/SubscriptionSettingProjector'
|
||||
|
||||
@injectable()
|
||||
export class GetSettings implements UseCaseInterface {
|
||||
constructor(
|
||||
@inject(TYPES.SettingRepository) private settingRepository: SettingRepositoryInterface,
|
||||
@inject(TYPES.SubscriptionSettingRepository)
|
||||
private subscriptionSettingRepository: SubscriptionSettingRepositoryInterface,
|
||||
@inject(TYPES.UserSubscriptionService) private userSubscriptionService: UserSubscriptionServiceInterface,
|
||||
@inject(TYPES.SettingProjector) private settingProjector: SettingProjector,
|
||||
@inject(TYPES.SubscriptionSettingProjector) private subscriptionSettingProjector: SubscriptionSettingProjector,
|
||||
@inject(TYPES.UserRepository) private userRepository: UserRepositoryInterface,
|
||||
@inject(TYPES.Crypter) private crypter: CrypterInterface,
|
||||
) {}
|
||||
@@ -33,27 +43,43 @@ export class GetSettings implements UseCaseInterface {
|
||||
}
|
||||
}
|
||||
|
||||
let settings = await this.settingRepository.findAllByUserUuid(userUuid)
|
||||
let settings: Array<Setting | SubscriptionSetting>
|
||||
settings = await this.settingRepository.findAllByUserUuid(userUuid)
|
||||
|
||||
const { regularSubscription, sharedSubscription } =
|
||||
await this.userSubscriptionService.findRegularSubscriptionForUserUuid(user.uuid)
|
||||
const subscription = sharedSubscription ?? regularSubscription
|
||||
if (subscription) {
|
||||
const subscriptionSettings = await this.subscriptionSettingRepository.findAllBySubscriptionUuid(subscription.uuid)
|
||||
settings = settings.concat(subscriptionSettings)
|
||||
}
|
||||
|
||||
if (dto.settingName !== undefined) {
|
||||
settings = settings.filter((setting: Setting) => setting.name === dto.settingName)
|
||||
settings = settings.filter((setting: Setting | SubscriptionSetting) => setting.name === dto.settingName)
|
||||
}
|
||||
|
||||
if (dto.updatedAfter !== undefined) {
|
||||
settings = settings.filter((setting: Setting) => setting.updatedAt >= (dto.updatedAfter as number))
|
||||
settings = settings.filter(
|
||||
(setting: Setting | SubscriptionSetting) => setting.updatedAt >= (dto.updatedAfter as number),
|
||||
)
|
||||
}
|
||||
|
||||
if (!dto.allowSensitiveRetrieval) {
|
||||
settings = settings.filter((setting: Setting) => !setting.sensitive)
|
||||
settings = settings.filter((setting: Setting | SubscriptionSetting) => !setting.sensitive)
|
||||
}
|
||||
|
||||
const simpleSettings: Array<SimpleSetting | SimpleSubscriptionSetting> = []
|
||||
for (const setting of settings) {
|
||||
if (setting.value !== null && setting.serverEncryptionVersion === EncryptionVersion.Default) {
|
||||
setting.value = await this.crypter.decryptForUser(setting.value, user)
|
||||
}
|
||||
}
|
||||
|
||||
const simpleSettings = await this.settingProjector.projectManySimple(settings)
|
||||
if (setting instanceof SubscriptionSetting) {
|
||||
simpleSettings.push(await this.subscriptionSettingProjector.projectSimple(setting))
|
||||
} else {
|
||||
simpleSettings.push(await this.settingProjector.projectSimple(setting))
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
success: true,
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
import { SimpleSetting } from '../../Setting/SimpleSetting'
|
||||
import { SimpleSubscriptionSetting } from '../../Setting/SimpleSubscriptionSetting'
|
||||
|
||||
export type GetSettingsResponse =
|
||||
| {
|
||||
success: true
|
||||
userUuid: string
|
||||
settings: SimpleSetting[]
|
||||
settings: Array<SimpleSetting | SimpleSubscriptionSetting>
|
||||
}
|
||||
| {
|
||||
success: false
|
||||
|
||||
-141
@@ -1,141 +0,0 @@
|
||||
import 'reflect-metadata'
|
||||
|
||||
import { SubscriptionSettingName } from '@standardnotes/settings'
|
||||
|
||||
import { SubscriptionSettingProjector } from '../../../Projection/SubscriptionSettingProjector'
|
||||
import { SubscriptionSetting } from '../../Setting/SubscriptionSetting'
|
||||
import { SubscriptionSettingServiceInterface } from '../../Setting/SubscriptionSettingServiceInterface'
|
||||
import { UserSubscriptionServiceInterface } from '../../Subscription/UserSubscriptionServiceInterface'
|
||||
|
||||
import { GetSubscriptionSetting } from './GetSubscriptionSetting'
|
||||
import { UserSubscription } from '../../Subscription/UserSubscription'
|
||||
import { UserSubscriptionType } from '../../Subscription/UserSubscriptionType'
|
||||
import { User } from '../../User/User'
|
||||
|
||||
describe('GetSubscriptionSetting', () => {
|
||||
let userSubscriptionService: UserSubscriptionServiceInterface
|
||||
let subscriptionSettingService: SubscriptionSettingServiceInterface
|
||||
let subscriptionSettingProjector: SubscriptionSettingProjector
|
||||
let subscriptionSetting: SubscriptionSetting
|
||||
let regularSubscription: UserSubscription
|
||||
let user: User
|
||||
|
||||
const createUseCase = () =>
|
||||
new GetSubscriptionSetting(userSubscriptionService, subscriptionSettingService, subscriptionSettingProjector)
|
||||
|
||||
beforeEach(() => {
|
||||
subscriptionSetting = {} as jest.Mocked<SubscriptionSetting>
|
||||
|
||||
user = {
|
||||
uuid: '1-2-3',
|
||||
} as jest.Mocked<User>
|
||||
|
||||
regularSubscription = {
|
||||
uuid: '1-2-3',
|
||||
subscriptionType: UserSubscriptionType.Regular,
|
||||
user: Promise.resolve(user),
|
||||
} as jest.Mocked<UserSubscription>
|
||||
|
||||
userSubscriptionService = {} as jest.Mocked<UserSubscriptionServiceInterface>
|
||||
userSubscriptionService.findRegularSubscriptionForUserUuid = jest
|
||||
.fn()
|
||||
.mockReturnValue({ regularSubscription, sharedSubscription: null })
|
||||
|
||||
subscriptionSettingService = {} as jest.Mocked<SubscriptionSettingServiceInterface>
|
||||
subscriptionSettingService.findSubscriptionSettingWithDecryptedValue = jest
|
||||
.fn()
|
||||
.mockReturnValue(subscriptionSetting)
|
||||
|
||||
subscriptionSettingProjector = {} as jest.Mocked<SubscriptionSettingProjector>
|
||||
subscriptionSettingProjector.projectSimple = jest.fn().mockReturnValue({ foo: 'bar' })
|
||||
})
|
||||
|
||||
it('should find a setting for user', async () => {
|
||||
expect(
|
||||
await createUseCase().execute({
|
||||
userUuid: '1-2-3',
|
||||
subscriptionSettingName: SubscriptionSettingName.FileUploadBytesUsed,
|
||||
}),
|
||||
).toEqual({
|
||||
success: true,
|
||||
setting: { foo: 'bar' },
|
||||
})
|
||||
})
|
||||
|
||||
it('should not get a setting for user if user has no corresponding regular subscription', async () => {
|
||||
userSubscriptionService.findRegularSubscriptionForUserUuid = jest
|
||||
.fn()
|
||||
.mockReturnValue({ regularSubscription: null, sharedSubscription: null })
|
||||
|
||||
expect(
|
||||
await createUseCase().execute({
|
||||
userUuid: '1-2-3',
|
||||
subscriptionSettingName: SubscriptionSettingName.FileUploadBytesLimit,
|
||||
}),
|
||||
).toEqual({
|
||||
success: false,
|
||||
error: {
|
||||
message: 'No subscription found.',
|
||||
},
|
||||
})
|
||||
})
|
||||
|
||||
it('should not get a setting for user if it does not exist', async () => {
|
||||
subscriptionSettingService.findSubscriptionSettingWithDecryptedValue = jest.fn().mockReturnValue(null)
|
||||
|
||||
expect(
|
||||
await createUseCase().execute({
|
||||
userUuid: '1-2-3',
|
||||
subscriptionSettingName: SubscriptionSettingName.FileUploadBytesLimit,
|
||||
}),
|
||||
).toEqual({
|
||||
success: false,
|
||||
error: {
|
||||
message: 'Setting FILE_UPLOAD_BYTES_LIMIT for user 1-2-3 not found!',
|
||||
},
|
||||
})
|
||||
})
|
||||
|
||||
it('should not retrieve a sensitive setting for user', async () => {
|
||||
subscriptionSetting = {
|
||||
sensitive: true,
|
||||
name: SubscriptionSettingName.FileUploadBytesLimit,
|
||||
} as jest.Mocked<SubscriptionSetting>
|
||||
|
||||
subscriptionSettingService.findSubscriptionSettingWithDecryptedValue = jest
|
||||
.fn()
|
||||
.mockReturnValue(subscriptionSetting)
|
||||
|
||||
expect(
|
||||
await createUseCase().execute({
|
||||
userUuid: '1-2-3',
|
||||
subscriptionSettingName: SubscriptionSettingName.FileUploadBytesLimit,
|
||||
}),
|
||||
).toEqual({
|
||||
success: true,
|
||||
sensitive: true,
|
||||
})
|
||||
})
|
||||
|
||||
it('should retrieve a sensitive setting for user if explicitly told to', async () => {
|
||||
subscriptionSetting = {
|
||||
sensitive: true,
|
||||
name: SubscriptionSettingName.FileUploadBytesLimit,
|
||||
} as jest.Mocked<SubscriptionSetting>
|
||||
|
||||
subscriptionSettingService.findSubscriptionSettingWithDecryptedValue = jest
|
||||
.fn()
|
||||
.mockReturnValue(subscriptionSetting)
|
||||
|
||||
expect(
|
||||
await createUseCase().execute({
|
||||
userUuid: '1-2-3',
|
||||
subscriptionSettingName: SubscriptionSettingName.FileUploadBytesLimit,
|
||||
allowSensitiveRetrieval: true,
|
||||
}),
|
||||
).toEqual({
|
||||
success: true,
|
||||
setting: { foo: 'bar' },
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -1,61 +0,0 @@
|
||||
import { inject, injectable } from 'inversify'
|
||||
|
||||
import { GetSubscriptionSettingDTO } from './GetSubscriptionSettingDTO'
|
||||
import { GetSubscriptionSettingResponse } from './GetSubscriptionSettingResponse'
|
||||
import { UseCaseInterface } from '../UseCaseInterface'
|
||||
import TYPES from '../../../Bootstrap/Types'
|
||||
import { SubscriptionSettingServiceInterface } from '../../Setting/SubscriptionSettingServiceInterface'
|
||||
import { UserSubscriptionServiceInterface } from '../../Subscription/UserSubscriptionServiceInterface'
|
||||
import { SubscriptionSettingProjector } from '../../../Projection/SubscriptionSettingProjector'
|
||||
|
||||
@injectable()
|
||||
export class GetSubscriptionSetting implements UseCaseInterface {
|
||||
constructor(
|
||||
@inject(TYPES.UserSubscriptionService) private userSubscriptionService: UserSubscriptionServiceInterface,
|
||||
@inject(TYPES.SubscriptionSettingService) private subscriptionSettingService: SubscriptionSettingServiceInterface,
|
||||
@inject(TYPES.SubscriptionSettingProjector) private subscriptionSettingProjector: SubscriptionSettingProjector,
|
||||
) {}
|
||||
|
||||
async execute(dto: GetSubscriptionSettingDTO): Promise<GetSubscriptionSettingResponse> {
|
||||
const { regularSubscription } = await this.userSubscriptionService.findRegularSubscriptionForUserUuid(dto.userUuid)
|
||||
if (regularSubscription === null) {
|
||||
return {
|
||||
success: false,
|
||||
error: {
|
||||
message: 'No subscription found.',
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
const regularSubscriptionUser = await regularSubscription.user
|
||||
|
||||
const setting = await this.subscriptionSettingService.findSubscriptionSettingWithDecryptedValue({
|
||||
userUuid: regularSubscriptionUser.uuid,
|
||||
userSubscriptionUuid: regularSubscription.uuid,
|
||||
subscriptionSettingName: dto.subscriptionSettingName,
|
||||
})
|
||||
|
||||
if (setting === null) {
|
||||
return {
|
||||
success: false,
|
||||
error: {
|
||||
message: `Setting ${dto.subscriptionSettingName} for user ${dto.userUuid} not found!`,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
if (setting.sensitive && !dto.allowSensitiveRetrieval) {
|
||||
return {
|
||||
success: true,
|
||||
sensitive: true,
|
||||
}
|
||||
}
|
||||
|
||||
const simpleSetting = await this.subscriptionSettingProjector.projectSimple(setting)
|
||||
|
||||
return {
|
||||
success: true,
|
||||
setting: simpleSetting,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
import { SubscriptionSettingName } from '@standardnotes/settings'
|
||||
|
||||
export type GetSubscriptionSettingDTO = {
|
||||
userUuid: string
|
||||
subscriptionSettingName: SubscriptionSettingName
|
||||
allowSensitiveRetrieval?: boolean
|
||||
}
|
||||
-17
@@ -1,17 +0,0 @@
|
||||
import { SimpleSetting } from '../../Setting/SimpleSetting'
|
||||
|
||||
export type GetSubscriptionSettingResponse =
|
||||
| {
|
||||
success: true
|
||||
setting: SimpleSetting
|
||||
}
|
||||
| {
|
||||
success: true
|
||||
sensitive: true
|
||||
}
|
||||
| {
|
||||
success: false
|
||||
error: {
|
||||
message: string
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -40,7 +40,7 @@ export class GetUserKeyParamsRecovery implements UseCaseInterface<KeyParamsData>
|
||||
}
|
||||
|
||||
const recoveryCodesSetting = await this.settingService.findSettingWithDecryptedValue({
|
||||
settingName: SettingName.RecoveryCodes,
|
||||
settingName: SettingName.create(SettingName.NAMES.RecoveryCodes).getValue(),
|
||||
userUuid: user.uuid,
|
||||
})
|
||||
if (!recoveryCodesSetting) {
|
||||
|
||||
@@ -83,7 +83,7 @@ export class SignInWithRecoveryCodes implements UseCaseInterface<AuthResponse202
|
||||
}
|
||||
|
||||
const recoveryCodesSetting = await this.settingService.findSettingWithDecryptedValue({
|
||||
settingName: SettingName.RecoveryCodes,
|
||||
settingName: SettingName.create(SettingName.NAMES.RecoveryCodes).getValue(),
|
||||
userUuid: user.uuid,
|
||||
})
|
||||
if (!recoveryCodesSetting) {
|
||||
@@ -116,7 +116,7 @@ export class SignInWithRecoveryCodes implements UseCaseInterface<AuthResponse202
|
||||
}
|
||||
|
||||
await this.deleteSetting.execute({
|
||||
settingName: SettingName.MfaSecret,
|
||||
settingName: SettingName.NAMES.MfaSecret,
|
||||
userUuid: user.uuid,
|
||||
})
|
||||
|
||||
|
||||
@@ -14,6 +14,11 @@ import { User } from '../../User/User'
|
||||
import { UserRepositoryInterface } from '../../User/UserRepositoryInterface'
|
||||
import { UpdateSetting } from './UpdateSetting'
|
||||
import { SettingName } from '@standardnotes/settings'
|
||||
import { SubscriptionSettingServiceInterface } from '../../Setting/SubscriptionSettingServiceInterface'
|
||||
import { SubscriptionSettingProjector } from '../../../Projection/SubscriptionSettingProjector'
|
||||
import { UserSubscriptionServiceInterface } from '../../Subscription/UserSubscriptionServiceInterface'
|
||||
import { UserSubscriptionType } from '../../Subscription/UserSubscriptionType'
|
||||
import { UserSubscription } from '../../Subscription/UserSubscription'
|
||||
|
||||
describe('UpdateSetting', () => {
|
||||
let settingService: SettingServiceInterface
|
||||
@@ -25,9 +30,24 @@ describe('UpdateSetting', () => {
|
||||
let userRepository: UserRepositoryInterface
|
||||
let roleService: RoleServiceInterface
|
||||
let logger: Logger
|
||||
let userSubscriptionService: UserSubscriptionServiceInterface
|
||||
let subscriptionSettingProjector: SubscriptionSettingProjector
|
||||
let subscriptionSettingService: SubscriptionSettingServiceInterface
|
||||
let regularSubscription: UserSubscription
|
||||
let sharedSubscription: UserSubscription
|
||||
|
||||
const createUseCase = () =>
|
||||
new UpdateSetting(settingService, settingProjector, settingsAssociationService, userRepository, roleService, logger)
|
||||
new UpdateSetting(
|
||||
settingService,
|
||||
subscriptionSettingService,
|
||||
userSubscriptionService,
|
||||
settingProjector,
|
||||
subscriptionSettingProjector,
|
||||
settingsAssociationService,
|
||||
userRepository,
|
||||
roleService,
|
||||
logger,
|
||||
)
|
||||
|
||||
beforeEach(() => {
|
||||
setting = {} as jest.Mocked<Setting>
|
||||
@@ -35,9 +55,32 @@ describe('UpdateSetting', () => {
|
||||
settingService = {} as jest.Mocked<SettingServiceInterface>
|
||||
settingService.createOrReplace = jest.fn().mockReturnValue({ status: 'created', setting })
|
||||
|
||||
subscriptionSettingService = {} as jest.Mocked<SubscriptionSettingServiceInterface>
|
||||
subscriptionSettingService.createOrReplace = jest.fn().mockReturnValue({ status: 'created', setting })
|
||||
|
||||
settingProjector = {} as jest.Mocked<SettingProjector>
|
||||
settingProjector.projectSimple = jest.fn().mockReturnValue(settingProjection)
|
||||
|
||||
regularSubscription = {
|
||||
uuid: '1-2-3',
|
||||
subscriptionType: UserSubscriptionType.Regular,
|
||||
user: Promise.resolve(user),
|
||||
} as jest.Mocked<UserSubscription>
|
||||
|
||||
sharedSubscription = {
|
||||
uuid: '2-3-4',
|
||||
subscriptionType: UserSubscriptionType.Shared,
|
||||
user: Promise.resolve(user),
|
||||
} as jest.Mocked<UserSubscription>
|
||||
|
||||
userSubscriptionService = {} as jest.Mocked<UserSubscriptionServiceInterface>
|
||||
userSubscriptionService.findRegularSubscriptionForUserUuid = jest
|
||||
.fn()
|
||||
.mockReturnValue({ regularSubscription: null, sharedSubscription: null })
|
||||
|
||||
subscriptionSettingProjector = {} as jest.Mocked<SubscriptionSettingProjector>
|
||||
subscriptionSettingProjector.projectSimple = jest.fn().mockReturnValue({ foo: 'sub-bar' })
|
||||
|
||||
user = {} as jest.Mocked<User>
|
||||
|
||||
userRepository = {} as jest.Mocked<UserRepositoryInterface>
|
||||
@@ -57,124 +100,217 @@ describe('UpdateSetting', () => {
|
||||
logger.error = jest.fn()
|
||||
})
|
||||
|
||||
it('should create a setting', async () => {
|
||||
const props = {
|
||||
name: SettingName.ExtensionKey,
|
||||
unencryptedValue: 'test-setting-value',
|
||||
serverEncryptionVersion: EncryptionVersion.Default,
|
||||
sensitive: false,
|
||||
}
|
||||
|
||||
const response = await createUseCase().execute({ props, userUuid: '1-2-3' })
|
||||
|
||||
expect(settingService.createOrReplace).toHaveBeenCalledWith({
|
||||
props: {
|
||||
name: 'EXTENSION_KEY',
|
||||
describe('no subscription', () => {
|
||||
it('should create a setting', async () => {
|
||||
const props = {
|
||||
name: SettingName.NAMES.ExtensionKey,
|
||||
unencryptedValue: 'test-setting-value',
|
||||
serverEncryptionVersion: 1,
|
||||
serverEncryptionVersion: EncryptionVersion.Default,
|
||||
sensitive: false,
|
||||
},
|
||||
user,
|
||||
}
|
||||
|
||||
const response = await createUseCase().execute({ props, userUuid: '1-2-3' })
|
||||
|
||||
expect(settingService.createOrReplace).toHaveBeenCalledWith({
|
||||
props: {
|
||||
name: 'EXTENSION_KEY',
|
||||
unencryptedValue: 'test-setting-value',
|
||||
serverEncryptionVersion: 1,
|
||||
sensitive: false,
|
||||
},
|
||||
user,
|
||||
})
|
||||
|
||||
expect(response).toEqual({
|
||||
success: true,
|
||||
setting: settingProjection,
|
||||
statusCode: 201,
|
||||
})
|
||||
})
|
||||
|
||||
expect(response).toEqual({
|
||||
success: true,
|
||||
setting: settingProjection,
|
||||
statusCode: 201,
|
||||
it('should not create a setting if user does not exist', async () => {
|
||||
userRepository.findOneByUuid = jest.fn().mockReturnValue(null)
|
||||
|
||||
const props = {
|
||||
name: SettingName.NAMES.ExtensionKey,
|
||||
unencryptedValue: 'test-setting-value',
|
||||
serverEncryptionVersion: EncryptionVersion.Unencrypted,
|
||||
sensitive: false,
|
||||
}
|
||||
|
||||
const response = await createUseCase().execute({ props, userUuid: '1-2-3' })
|
||||
|
||||
expect(settingService.createOrReplace).not.toHaveBeenCalled()
|
||||
|
||||
expect(response).toEqual({
|
||||
success: false,
|
||||
error: {
|
||||
message: 'User 1-2-3 not found.',
|
||||
},
|
||||
statusCode: 404,
|
||||
})
|
||||
})
|
||||
|
||||
it('should not create a subscription setting', async () => {
|
||||
const props = {
|
||||
name: SettingName.NAMES.MuteSignInEmails,
|
||||
unencryptedValue: 'test-setting-value',
|
||||
serverEncryptionVersion: EncryptionVersion.Unencrypted,
|
||||
sensitive: false,
|
||||
}
|
||||
|
||||
const response = await createUseCase().execute({ props, userUuid: '1-2-3' })
|
||||
|
||||
expect(settingService.createOrReplace).not.toHaveBeenCalled()
|
||||
|
||||
expect(response).toEqual({
|
||||
success: false,
|
||||
error: {
|
||||
message: 'User 1-2-3 has no subscription to change a subscription setting.',
|
||||
},
|
||||
statusCode: 401,
|
||||
})
|
||||
})
|
||||
|
||||
it('should not create a setting if the setting name is invalid', async () => {
|
||||
const props = {
|
||||
name: 'random-setting',
|
||||
unencryptedValue: 'test-setting-value',
|
||||
serverEncryptionVersion: EncryptionVersion.Unencrypted,
|
||||
sensitive: false,
|
||||
}
|
||||
|
||||
const response = await createUseCase().execute({ props, userUuid: '1-2-3' })
|
||||
|
||||
expect(settingService.createOrReplace).not.toHaveBeenCalled()
|
||||
|
||||
expect(response).toEqual({
|
||||
success: false,
|
||||
error: {
|
||||
message: 'Invalid setting name: random-setting',
|
||||
},
|
||||
statusCode: 400,
|
||||
})
|
||||
})
|
||||
|
||||
it('should not create a setting if user is not permitted to', async () => {
|
||||
settingsAssociationService.getPermissionAssociatedWithSetting = jest
|
||||
.fn()
|
||||
.mockReturnValue(PermissionName.DailyEmailBackup)
|
||||
|
||||
roleService.userHasPermission = jest.fn().mockReturnValue(false)
|
||||
|
||||
const props = {
|
||||
name: SettingName.NAMES.ExtensionKey,
|
||||
unencryptedValue: 'test-setting-value',
|
||||
serverEncryptionVersion: EncryptionVersion.Unencrypted,
|
||||
sensitive: false,
|
||||
}
|
||||
|
||||
const response = await createUseCase().execute({ props, userUuid: '1-2-3' })
|
||||
|
||||
expect(settingService.createOrReplace).not.toHaveBeenCalled()
|
||||
|
||||
expect(response).toEqual({
|
||||
success: false,
|
||||
error: {
|
||||
message: 'User 1-2-3 is not permitted to change the setting.',
|
||||
},
|
||||
statusCode: 401,
|
||||
})
|
||||
})
|
||||
|
||||
it('should not create a setting if setting is not mutable by the client', async () => {
|
||||
settingsAssociationService.isSettingMutableByClient = jest.fn().mockReturnValue(false)
|
||||
|
||||
const props = {
|
||||
name: SettingName.NAMES.ExtensionKey,
|
||||
unencryptedValue: 'test-setting-value',
|
||||
serverEncryptionVersion: EncryptionVersion.Unencrypted,
|
||||
sensitive: false,
|
||||
}
|
||||
|
||||
const response = await createUseCase().execute({ props, userUuid: '1-2-3' })
|
||||
|
||||
expect(settingService.createOrReplace).not.toHaveBeenCalled()
|
||||
|
||||
expect(response).toEqual({
|
||||
success: false,
|
||||
error: {
|
||||
message: 'User 1-2-3 is not permitted to change the setting.',
|
||||
},
|
||||
statusCode: 401,
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
it('should not create a setting if user does not exist', async () => {
|
||||
userRepository.findOneByUuid = jest.fn().mockReturnValue(null)
|
||||
describe('regular subscription', () => {
|
||||
beforeEach(() => {
|
||||
userSubscriptionService.findRegularSubscriptionForUserUuid = jest
|
||||
.fn()
|
||||
.mockReturnValue({ regularSubscription, sharedSubscription: null })
|
||||
})
|
||||
|
||||
const props = {
|
||||
name: SettingName.ExtensionKey,
|
||||
unencryptedValue: 'test-setting-value',
|
||||
serverEncryptionVersion: EncryptionVersion.Unencrypted,
|
||||
sensitive: false,
|
||||
}
|
||||
it('should create a subscription setting', async () => {
|
||||
const props = {
|
||||
name: SettingName.NAMES.MuteSignInEmails,
|
||||
unencryptedValue: 'test-setting-value',
|
||||
serverEncryptionVersion: EncryptionVersion.Default,
|
||||
sensitive: false,
|
||||
}
|
||||
|
||||
const response = await createUseCase().execute({ props, userUuid: '1-2-3' })
|
||||
const response = await createUseCase().execute({ props, userUuid: '1-2-3' })
|
||||
|
||||
expect(settingService.createOrReplace).not.toHaveBeenCalled()
|
||||
expect(subscriptionSettingService.createOrReplace).toHaveBeenCalledWith({
|
||||
props: {
|
||||
name: 'MUTE_SIGN_IN_EMAILS',
|
||||
unencryptedValue: 'test-setting-value',
|
||||
serverEncryptionVersion: 1,
|
||||
sensitive: false,
|
||||
},
|
||||
userSubscription: regularSubscription,
|
||||
})
|
||||
|
||||
expect(response).toEqual({
|
||||
success: false,
|
||||
error: {
|
||||
message: 'User 1-2-3 not found.',
|
||||
},
|
||||
statusCode: 404,
|
||||
expect(response).toEqual({
|
||||
success: true,
|
||||
setting: { foo: 'sub-bar' },
|
||||
statusCode: 201,
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
it('should not create a setting if the setting name is invalid', async () => {
|
||||
const props = {
|
||||
name: 'random-setting',
|
||||
unencryptedValue: 'test-setting-value',
|
||||
serverEncryptionVersion: EncryptionVersion.Unencrypted,
|
||||
sensitive: false,
|
||||
}
|
||||
|
||||
const response = await createUseCase().execute({ props, userUuid: '1-2-3' })
|
||||
|
||||
expect(settingService.createOrReplace).not.toHaveBeenCalled()
|
||||
|
||||
expect(response).toEqual({
|
||||
success: false,
|
||||
error: {
|
||||
message: 'Setting name random-setting is invalid.',
|
||||
},
|
||||
statusCode: 400,
|
||||
describe('shared subscription', () => {
|
||||
beforeEach(() => {
|
||||
userSubscriptionService.findRegularSubscriptionForUserUuid = jest
|
||||
.fn()
|
||||
.mockReturnValue({ regularSubscription, sharedSubscription })
|
||||
})
|
||||
})
|
||||
|
||||
it('should not create a setting if user is not permitted to', async () => {
|
||||
settingsAssociationService.getPermissionAssociatedWithSetting = jest
|
||||
.fn()
|
||||
.mockReturnValue(PermissionName.DailyEmailBackup)
|
||||
it('should create a subscription setting', async () => {
|
||||
const props = {
|
||||
name: SettingName.NAMES.MuteSignInEmails,
|
||||
unencryptedValue: 'test-setting-value',
|
||||
serverEncryptionVersion: EncryptionVersion.Default,
|
||||
sensitive: false,
|
||||
}
|
||||
|
||||
roleService.userHasPermission = jest.fn().mockReturnValue(false)
|
||||
const response = await createUseCase().execute({ props, userUuid: '1-2-3' })
|
||||
|
||||
const props = {
|
||||
name: SettingName.ExtensionKey,
|
||||
unencryptedValue: 'test-setting-value',
|
||||
serverEncryptionVersion: EncryptionVersion.Unencrypted,
|
||||
sensitive: false,
|
||||
}
|
||||
expect(subscriptionSettingService.createOrReplace).toHaveBeenCalledWith({
|
||||
props: {
|
||||
name: 'MUTE_SIGN_IN_EMAILS',
|
||||
unencryptedValue: 'test-setting-value',
|
||||
serverEncryptionVersion: 1,
|
||||
sensitive: false,
|
||||
},
|
||||
userSubscription: sharedSubscription,
|
||||
})
|
||||
|
||||
const response = await createUseCase().execute({ props, userUuid: '1-2-3' })
|
||||
|
||||
expect(settingService.createOrReplace).not.toHaveBeenCalled()
|
||||
|
||||
expect(response).toEqual({
|
||||
success: false,
|
||||
error: {
|
||||
message: 'User 1-2-3 is not permitted to change the setting.',
|
||||
},
|
||||
statusCode: 401,
|
||||
})
|
||||
})
|
||||
|
||||
it('should not create a setting if setting is not mutable by the client', async () => {
|
||||
settingsAssociationService.isSettingMutableByClient = jest.fn().mockReturnValue(false)
|
||||
|
||||
const props = {
|
||||
name: SettingName.ExtensionKey,
|
||||
unencryptedValue: 'test-setting-value',
|
||||
serverEncryptionVersion: EncryptionVersion.Unencrypted,
|
||||
sensitive: false,
|
||||
}
|
||||
|
||||
const response = await createUseCase().execute({ props, userUuid: '1-2-3' })
|
||||
|
||||
expect(settingService.createOrReplace).not.toHaveBeenCalled()
|
||||
|
||||
expect(response).toEqual({
|
||||
success: false,
|
||||
error: {
|
||||
message: 'User 1-2-3 is not permitted to change the setting.',
|
||||
},
|
||||
statusCode: 401,
|
||||
expect(response).toEqual({
|
||||
success: true,
|
||||
setting: { foo: 'sub-bar' },
|
||||
statusCode: 201,
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@@ -12,12 +12,19 @@ import { User } from '../../User/User'
|
||||
import { SettingName } from '@standardnotes/settings'
|
||||
import { RoleServiceInterface } from '../../Role/RoleServiceInterface'
|
||||
import { SettingsAssociationServiceInterface } from '../../Setting/SettingsAssociationServiceInterface'
|
||||
import { SubscriptionSettingServiceInterface } from '../../Setting/SubscriptionSettingServiceInterface'
|
||||
import { UserSubscriptionServiceInterface } from '../../Subscription/UserSubscriptionServiceInterface'
|
||||
import { CreateOrReplaceSubscriptionSettingResponse } from '../../Setting/CreateOrReplaceSubscriptionSettingResponse'
|
||||
import { SubscriptionSettingProjector } from '../../../Projection/SubscriptionSettingProjector'
|
||||
|
||||
@injectable()
|
||||
export class UpdateSetting implements UseCaseInterface {
|
||||
constructor(
|
||||
@inject(TYPES.SettingService) private settingService: SettingServiceInterface,
|
||||
@inject(TYPES.SubscriptionSettingService) private subscriptionSettingService: SubscriptionSettingServiceInterface,
|
||||
@inject(TYPES.UserSubscriptionService) private userSubscriptionService: UserSubscriptionServiceInterface,
|
||||
@inject(TYPES.SettingProjector) private settingProjector: SettingProjector,
|
||||
@inject(TYPES.SubscriptionSettingProjector) private subscriptionSettingProjector: SubscriptionSettingProjector,
|
||||
@inject(TYPES.SettingsAssociationService) private settingsAssociationService: SettingsAssociationServiceInterface,
|
||||
@inject(TYPES.UserRepository) private userRepository: UserRepositoryInterface,
|
||||
@inject(TYPES.RoleService) private roleService: RoleServiceInterface,
|
||||
@@ -25,15 +32,17 @@ export class UpdateSetting implements UseCaseInterface {
|
||||
) {}
|
||||
|
||||
async execute(dto: UpdateSettingDto): Promise<UpdateSettingResponse> {
|
||||
if (!Object.values(SettingName).includes(dto.props.name as SettingName)) {
|
||||
const settingNameOrError = SettingName.create(dto.props.name)
|
||||
if (settingNameOrError.isFailed()) {
|
||||
return {
|
||||
success: false,
|
||||
error: {
|
||||
message: `Setting name ${dto.props.name} is invalid.`,
|
||||
message: settingNameOrError.getError(),
|
||||
},
|
||||
statusCode: 400,
|
||||
}
|
||||
}
|
||||
const settingName = settingNameOrError.getValue()
|
||||
|
||||
this.logger.debug('[%s] Updating setting: %O', dto.userUuid, dto)
|
||||
|
||||
@@ -51,7 +60,7 @@ export class UpdateSetting implements UseCaseInterface {
|
||||
}
|
||||
}
|
||||
|
||||
if (!(await this.userHasPermissionToUpdateSetting(user, props.name as SettingName))) {
|
||||
if (!(await this.userHasPermissionToUpdateSetting(user, settingName))) {
|
||||
return {
|
||||
success: false,
|
||||
error: {
|
||||
@@ -61,10 +70,34 @@ export class UpdateSetting implements UseCaseInterface {
|
||||
}
|
||||
}
|
||||
|
||||
props.serverEncryptionVersion = this.settingsAssociationService.getEncryptionVersionForSetting(
|
||||
props.name as SettingName,
|
||||
)
|
||||
props.sensitive = this.settingsAssociationService.getSensitivityForSetting(props.name as SettingName)
|
||||
props.serverEncryptionVersion = this.settingsAssociationService.getEncryptionVersionForSetting(settingName)
|
||||
props.sensitive = this.settingsAssociationService.getSensitivityForSetting(settingName)
|
||||
|
||||
if (settingName.isASubscriptionSetting()) {
|
||||
const { regularSubscription, sharedSubscription } =
|
||||
await this.userSubscriptionService.findRegularSubscriptionForUserUuid(user.uuid)
|
||||
const subscription = sharedSubscription ?? regularSubscription
|
||||
if (!subscription) {
|
||||
return {
|
||||
success: false,
|
||||
error: {
|
||||
message: `User ${userUuid} has no subscription to change a subscription setting.`,
|
||||
},
|
||||
statusCode: 401,
|
||||
}
|
||||
}
|
||||
|
||||
const response = await this.subscriptionSettingService.createOrReplace({
|
||||
userSubscription: subscription,
|
||||
props,
|
||||
})
|
||||
|
||||
return {
|
||||
success: true,
|
||||
setting: await this.subscriptionSettingProjector.projectSimple(response.subscriptionSetting),
|
||||
statusCode: this.statusToStatusCode(response),
|
||||
}
|
||||
}
|
||||
|
||||
const response = await this.settingService.createOrReplace({
|
||||
user,
|
||||
@@ -79,7 +112,9 @@ export class UpdateSetting implements UseCaseInterface {
|
||||
}
|
||||
|
||||
/* istanbul ignore next */
|
||||
private statusToStatusCode(response: CreateOrReplaceSettingResponse): number {
|
||||
private statusToStatusCode(
|
||||
response: CreateOrReplaceSettingResponse | CreateOrReplaceSubscriptionSettingResponse,
|
||||
): number {
|
||||
if (response.status === 'created') {
|
||||
return 201
|
||||
}
|
||||
@@ -92,7 +127,7 @@ export class UpdateSetting implements UseCaseInterface {
|
||||
}
|
||||
|
||||
private async userHasPermissionToUpdateSetting(user: User, settingName: SettingName): Promise<boolean> {
|
||||
const settingIsMutableByClient = await this.settingsAssociationService.isSettingMutableByClient(settingName)
|
||||
const settingIsMutableByClient = this.settingsAssociationService.isSettingMutableByClient(settingName)
|
||||
if (!settingIsMutableByClient) {
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -55,7 +55,7 @@ describe('VerifyMFA', () => {
|
||||
lockRepository.lockSuccessfullOTP = jest.fn()
|
||||
|
||||
setting = {
|
||||
name: SettingName.MfaSecret,
|
||||
name: SettingName.NAMES.MfaSecret,
|
||||
value: 'shhhh',
|
||||
} as jest.Mocked<Setting>
|
||||
|
||||
@@ -87,7 +87,7 @@ describe('VerifyMFA', () => {
|
||||
|
||||
it('should pass MFA verification if user has MFA deleted', async () => {
|
||||
setting = {
|
||||
name: SettingName.MfaSecret,
|
||||
name: SettingName.NAMES.MfaSecret,
|
||||
value: null,
|
||||
} as jest.Mocked<Setting>
|
||||
|
||||
@@ -177,7 +177,7 @@ describe('VerifyMFA', () => {
|
||||
|
||||
it('should not pass MFA verification if mfa is not correct', async () => {
|
||||
setting = {
|
||||
name: SettingName.MfaSecret,
|
||||
name: SettingName.NAMES.MfaSecret,
|
||||
value: 'shhhh2',
|
||||
} as jest.Mocked<Setting>
|
||||
|
||||
|
||||
@@ -90,7 +90,7 @@ export class VerifyMFA implements UseCaseInterface {
|
||||
|
||||
const mfaSecret = await this.settingService.findSettingWithDecryptedValue({
|
||||
userUuid: user.uuid,
|
||||
settingName: SettingName.MfaSecret,
|
||||
settingName: SettingName.create(SettingName.NAMES.MfaSecret).getValue(),
|
||||
})
|
||||
const twoFactorEnabled = mfaSecret !== null && mfaSecret.value !== null
|
||||
|
||||
|
||||
@@ -39,7 +39,10 @@ export class VerifyPredicate implements UseCaseInterface {
|
||||
}
|
||||
|
||||
private async hasUserEnabledEmailBackups(userUuid: string): Promise<boolean> {
|
||||
const setting = await this.settingRepository.findOneByNameAndUserUuid(SettingName.EmailBackupFrequency, userUuid)
|
||||
const setting = await this.settingRepository.findOneByNameAndUserUuid(
|
||||
SettingName.NAMES.EmailBackupFrequency,
|
||||
userUuid,
|
||||
)
|
||||
|
||||
if (setting === null || setting.value === EmailBackupFrequency.Disabled) {
|
||||
return false
|
||||
|
||||
Reference in New Issue
Block a user