import 'reflect-metadata' import { LogSessionUserAgentOption, MuteSignInEmailsOption, SettingName } from '@standardnotes/settings' import { Logger } from 'winston' import { EncryptionVersion } from '../Encryption/EncryptionVersion' import { User } from '../User/User' import { Setting } from './Setting' import { SettingRepositoryInterface } from './SettingRepositoryInterface' import { SettingService } from './SettingService' import { SettingsAssociationServiceInterface } from './SettingsAssociationServiceInterface' import { SettingInterpreterInterface } from './SettingInterpreterInterface' import { SettingDecrypterInterface } from './SettingDecrypterInterface' import { SettingFactoryInterface } from './SettingFactoryInterface' describe('SettingService', () => { let setting: Setting let user: User let factory: SettingFactoryInterface let settingRepository: SettingRepositoryInterface let settingsAssociationService: SettingsAssociationServiceInterface let settingInterpreter: SettingInterpreterInterface let settingDecrypter: SettingDecrypterInterface let logger: Logger const createService = () => new SettingService( factory, settingRepository, settingsAssociationService, settingInterpreter, settingDecrypter, logger, ) beforeEach(() => { user = { uuid: '4-5-6', } as jest.Mocked user.isPotentiallyAPrivateUsernameAccount = jest.fn().mockReturnValue(false) setting = { name: SettingName.NAMES.DropboxBackupToken, } as jest.Mocked factory = {} as jest.Mocked factory.create = jest.fn().mockReturnValue(setting) factory.createReplacement = jest.fn().mockReturnValue(setting) settingRepository = {} as jest.Mocked settingRepository.findLastByNameAndUserUuid = jest.fn().mockReturnValue(null) settingRepository.findOneByNameAndUserUuid = jest.fn().mockReturnValue(null) settingRepository.save = jest.fn().mockImplementation((setting) => setting) settingsAssociationService = {} as jest.Mocked settingsAssociationService.getDefaultSettingsAndValuesForNewUser = jest.fn().mockReturnValue( new Map([ [ SettingName.NAMES.MuteSignInEmails, { value: MuteSignInEmailsOption.NotMuted, sensitive: 0, serverEncryptionVersion: EncryptionVersion.Unencrypted, }, ], ]), ) settingsAssociationService.getDefaultSettingsAndValuesForNewPrivateUsernameAccount = jest.fn().mockReturnValue( new Map([ [ SettingName.NAMES.LogSessionUserAgent, { sensitive: false, serverEncryptionVersion: EncryptionVersion.Unencrypted, value: LogSessionUserAgentOption.Disabled, }, ], ]), ) settingInterpreter = {} as jest.Mocked settingInterpreter.interpretSettingUpdated = jest.fn() settingDecrypter = {} as jest.Mocked settingDecrypter.decryptSettingValue = jest.fn().mockReturnValue('decrypted') logger = {} as jest.Mocked logger.debug = jest.fn() logger.warn = jest.fn() logger.error = jest.fn() }) it('should create default settings for a newly registered user', async () => { await createService().applyDefaultSettingsUponRegistration(user) expect(settingRepository.save).toHaveBeenCalledWith(setting) }) it('should create default settings for a newly registered vault account', async () => { user.isPotentiallyAPrivateUsernameAccount = jest.fn().mockReturnValue(true) await createService().applyDefaultSettingsUponRegistration(user) expect(settingRepository.save).toHaveBeenCalledWith(setting) }) it("should create setting if it doesn't exist", async () => { const result = await createService().createOrReplace({ user, props: { name: SettingName.NAMES.MuteFailedBackupsEmails, unencryptedValue: 'value', serverEncryptionVersion: 1, sensitive: false, }, }) expect(result.status).toEqual('created') }) it('should throw error if setting name is not valid', async () => { await expect( createService().createOrReplace({ user, props: { name: 'invalid', unencryptedValue: 'value', serverEncryptionVersion: 1, sensitive: false, }, }), ).rejects.toThrowError('Invalid setting name: invalid') }) it('should create setting with a given uuid if it does not exist', async () => { settingRepository.findOneByUuid = jest.fn().mockReturnValue(null) const result = await createService().createOrReplace({ user, props: { uuid: '1-2-3', name: SettingName.NAMES.MuteFailedBackupsEmails, unencryptedValue: 'value', serverEncryptionVersion: 1, sensitive: false, }, }) expect(result.status).toEqual('created') }) it('should replace setting if it does exist', async () => { settingRepository.findLastByNameAndUserUuid = jest.fn().mockReturnValue(setting) const result = await createService().createOrReplace({ user: user, props: { ...setting, unencryptedValue: 'value', serverEncryptionVersion: 1, }, }) expect(result.status).toEqual('replaced') }) it('should replace setting with a given uuid if it does exist', async () => { settingRepository.findOneByUuid = jest.fn().mockReturnValue(setting) const result = await createService().createOrReplace({ user: user, props: { ...setting, uuid: '1-2-3', unencryptedValue: 'value', serverEncryptionVersion: 1, }, }) expect(result.status).toEqual('replaced') }) it('should find and decrypt the value of a setting for user', async () => { setting = { value: 'encrypted', serverEncryptionVersion: EncryptionVersion.Default, } as jest.Mocked settingRepository.findLastByNameAndUserUuid = jest.fn().mockReturnValue(setting) expect( await createService().findSettingWithDecryptedValue({ userUuid: '1-2-3', settingName: SettingName.create(SettingName.NAMES.LogSessionUserAgent).getValue(), }), ).toEqual({ serverEncryptionVersion: 1, value: 'decrypted', }) }) })