mirror of
https://github.com/bitwarden/browser.git
synced 2025-02-16 01:21:48 +01:00
[PM-5735] Create kdf Service (#8715)
* key connector migration initial * migrator complete * fix dependencies * finalized tests * fix deps and sync main * clean up definition file * fixing tests * fixed tests * fixing CLI, Browser, Desktop builds * fixed factory options * reverting exports * implemented UserKeyDefinition clearOn * Initial Kdf Service Changes * rename and account setting kdfconfig * fixing tests and renaming migration * fixed DI ordering for browser * rename and fix DI * Clean up Migrations * fixing migrations * begin data structure changes for kdf config * Make KDF more type safe; co-author: jlf0dev * fixing tests * Fixed CLI login and comments * set now accepts userId and test updates --------- Co-authored-by: Jake Fink <jfink@bitwarden.com>
This commit is contained in:
parent
dba910d0b9
commit
1e4158fd87
@ -0,0 +1,28 @@
|
||||
import { KdfConfigService as AbstractKdfConfigService } from "@bitwarden/common/auth/abstractions/kdf-config.service";
|
||||
import { KdfConfigService } from "@bitwarden/common/auth/services/kdf-config.service";
|
||||
|
||||
import {
|
||||
FactoryOptions,
|
||||
CachedServices,
|
||||
factory,
|
||||
} from "../../../platform/background/service-factories/factory-options";
|
||||
import {
|
||||
StateProviderInitOptions,
|
||||
stateProviderFactory,
|
||||
} from "../../../platform/background/service-factories/state-provider.factory";
|
||||
|
||||
type KdfConfigServiceFactoryOptions = FactoryOptions;
|
||||
|
||||
export type KdfConfigServiceInitOptions = KdfConfigServiceFactoryOptions & StateProviderInitOptions;
|
||||
|
||||
export function kdfConfigServiceFactory(
|
||||
cache: { kdfConfigService?: AbstractKdfConfigService } & CachedServices,
|
||||
opts: KdfConfigServiceInitOptions,
|
||||
): Promise<AbstractKdfConfigService> {
|
||||
return factory(
|
||||
cache,
|
||||
"kdfConfigService",
|
||||
opts,
|
||||
async () => new KdfConfigService(await stateProviderFactory(cache, opts)),
|
||||
);
|
||||
}
|
@ -68,6 +68,7 @@ import {
|
||||
deviceTrustServiceFactory,
|
||||
DeviceTrustServiceInitOptions,
|
||||
} from "./device-trust-service.factory";
|
||||
import { kdfConfigServiceFactory, KdfConfigServiceInitOptions } from "./kdf-config-service.factory";
|
||||
import {
|
||||
keyConnectorServiceFactory,
|
||||
KeyConnectorServiceInitOptions,
|
||||
@ -106,7 +107,8 @@ export type LoginStrategyServiceInitOptions = LoginStrategyServiceFactoryOptions
|
||||
AuthRequestServiceInitOptions &
|
||||
UserDecryptionOptionsServiceInitOptions &
|
||||
GlobalStateProviderInitOptions &
|
||||
BillingAccountProfileStateServiceInitOptions;
|
||||
BillingAccountProfileStateServiceInitOptions &
|
||||
KdfConfigServiceInitOptions;
|
||||
|
||||
export function loginStrategyServiceFactory(
|
||||
cache: { loginStrategyService?: LoginStrategyServiceAbstraction } & CachedServices,
|
||||
@ -140,6 +142,7 @@ export function loginStrategyServiceFactory(
|
||||
await internalUserDecryptionOptionServiceFactory(cache, opts),
|
||||
await globalStateProviderFactory(cache, opts),
|
||||
await billingAccountProfileStateServiceFactory(cache, opts),
|
||||
await kdfConfigServiceFactory(cache, opts),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
@ -22,13 +22,16 @@ import {
|
||||
stateServiceFactory,
|
||||
} from "../../../platform/background/service-factories/state-service.factory";
|
||||
|
||||
import { KdfConfigServiceInitOptions, kdfConfigServiceFactory } from "./kdf-config-service.factory";
|
||||
|
||||
type PinCryptoServiceFactoryOptions = FactoryOptions;
|
||||
|
||||
export type PinCryptoServiceInitOptions = PinCryptoServiceFactoryOptions &
|
||||
StateServiceInitOptions &
|
||||
CryptoServiceInitOptions &
|
||||
VaultTimeoutSettingsServiceInitOptions &
|
||||
LogServiceInitOptions;
|
||||
LogServiceInitOptions &
|
||||
KdfConfigServiceInitOptions;
|
||||
|
||||
export function pinCryptoServiceFactory(
|
||||
cache: { pinCryptoService?: PinCryptoServiceAbstraction } & CachedServices,
|
||||
@ -44,6 +47,7 @@ export function pinCryptoServiceFactory(
|
||||
await cryptoServiceFactory(cache, opts),
|
||||
await vaultTimeoutSettingsServiceFactory(cache, opts),
|
||||
await logServiceFactory(cache, opts),
|
||||
await kdfConfigServiceFactory(cache, opts),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
@ -32,6 +32,7 @@ import {
|
||||
} from "../../../platform/background/service-factories/state-service.factory";
|
||||
|
||||
import { accountServiceFactory, AccountServiceInitOptions } from "./account-service.factory";
|
||||
import { KdfConfigServiceInitOptions, kdfConfigServiceFactory } from "./kdf-config-service.factory";
|
||||
import {
|
||||
internalMasterPasswordServiceFactory,
|
||||
MasterPasswordServiceInitOptions,
|
||||
@ -59,7 +60,8 @@ export type UserVerificationServiceInitOptions = UserVerificationServiceFactoryO
|
||||
PinCryptoServiceInitOptions &
|
||||
LogServiceInitOptions &
|
||||
VaultTimeoutSettingsServiceInitOptions &
|
||||
PlatformUtilsServiceInitOptions;
|
||||
PlatformUtilsServiceInitOptions &
|
||||
KdfConfigServiceInitOptions;
|
||||
|
||||
export function userVerificationServiceFactory(
|
||||
cache: { userVerificationService?: AbstractUserVerificationService } & CachedServices,
|
||||
@ -82,6 +84,7 @@ export function userVerificationServiceFactory(
|
||||
await logServiceFactory(cache, opts),
|
||||
await vaultTimeoutSettingsServiceFactory(cache, opts),
|
||||
await platformUtilsServiceFactory(cache, opts),
|
||||
await kdfConfigServiceFactory(cache, opts),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
@ -12,6 +12,7 @@ import { InternalPolicyService } from "@bitwarden/common/admin-console/abstracti
|
||||
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
||||
import { AuthService } from "@bitwarden/common/auth/abstractions/auth.service";
|
||||
import { DeviceTrustServiceAbstraction } from "@bitwarden/common/auth/abstractions/device-trust.service.abstraction";
|
||||
import { KdfConfigService } from "@bitwarden/common/auth/abstractions/kdf-config.service";
|
||||
import { InternalMasterPasswordServiceAbstraction } from "@bitwarden/common/auth/abstractions/master-password.service.abstraction";
|
||||
import { UserVerificationService } from "@bitwarden/common/auth/abstractions/user-verification/user-verification.service.abstraction";
|
||||
import { AuthenticationStatus } from "@bitwarden/common/auth/enums/authentication-status";
|
||||
@ -66,6 +67,7 @@ export class LockComponent extends BaseLockComponent {
|
||||
private routerService: BrowserRouterService,
|
||||
biometricStateService: BiometricStateService,
|
||||
accountService: AccountService,
|
||||
kdfConfigService: KdfConfigService,
|
||||
) {
|
||||
super(
|
||||
masterPasswordService,
|
||||
@ -90,6 +92,7 @@ export class LockComponent extends BaseLockComponent {
|
||||
pinCryptoService,
|
||||
biometricStateService,
|
||||
accountService,
|
||||
kdfConfigService,
|
||||
);
|
||||
this.successRoute = "/tabs/current";
|
||||
this.isInitialLockScreen = (window as any).previousPopupUrl == null;
|
||||
|
@ -33,6 +33,7 @@ import { AvatarService as AvatarServiceAbstraction } from "@bitwarden/common/aut
|
||||
import { DeviceTrustServiceAbstraction } from "@bitwarden/common/auth/abstractions/device-trust.service.abstraction";
|
||||
import { DevicesServiceAbstraction } from "@bitwarden/common/auth/abstractions/devices/devices.service.abstraction";
|
||||
import { DevicesApiServiceAbstraction } from "@bitwarden/common/auth/abstractions/devices-api.service.abstraction";
|
||||
import { KdfConfigService as kdfConfigServiceAbstraction } from "@bitwarden/common/auth/abstractions/kdf-config.service";
|
||||
import { KeyConnectorService as KeyConnectorServiceAbstraction } from "@bitwarden/common/auth/abstractions/key-connector.service";
|
||||
import { InternalMasterPasswordServiceAbstraction } from "@bitwarden/common/auth/abstractions/master-password.service.abstraction";
|
||||
import { SsoLoginServiceAbstraction } from "@bitwarden/common/auth/abstractions/sso-login.service.abstraction";
|
||||
@ -48,6 +49,7 @@ import { AvatarService } from "@bitwarden/common/auth/services/avatar.service";
|
||||
import { DeviceTrustService } from "@bitwarden/common/auth/services/device-trust.service.implementation";
|
||||
import { DevicesServiceImplementation } from "@bitwarden/common/auth/services/devices/devices.service.implementation";
|
||||
import { DevicesApiServiceImplementation } from "@bitwarden/common/auth/services/devices-api.service.implementation";
|
||||
import { KdfConfigService } from "@bitwarden/common/auth/services/kdf-config.service";
|
||||
import { KeyConnectorService } from "@bitwarden/common/auth/services/key-connector.service";
|
||||
import { MasterPasswordService } from "@bitwarden/common/auth/services/master-password/master-password.service";
|
||||
import { SsoLoginService } from "@bitwarden/common/auth/services/sso-login.service";
|
||||
@ -339,6 +341,7 @@ export default class MainBackground {
|
||||
intraprocessMessagingSubject: Subject<Message<object>>;
|
||||
userKeyInitService: UserKeyInitService;
|
||||
scriptInjectorService: BrowserScriptInjectorService;
|
||||
kdfConfigService: kdfConfigServiceAbstraction;
|
||||
|
||||
onUpdatedRan: boolean;
|
||||
onReplacedRan: boolean;
|
||||
@ -542,6 +545,9 @@ export default class MainBackground {
|
||||
this.masterPasswordService = new MasterPasswordService(this.stateProvider);
|
||||
|
||||
this.i18nService = new I18nService(BrowserApi.getUILanguage(), this.globalStateProvider);
|
||||
|
||||
this.kdfConfigService = new KdfConfigService(this.stateProvider);
|
||||
|
||||
this.cryptoService = new BrowserCryptoService(
|
||||
this.masterPasswordService,
|
||||
this.keyGenerationService,
|
||||
@ -553,6 +559,7 @@ export default class MainBackground {
|
||||
this.accountService,
|
||||
this.stateProvider,
|
||||
this.biometricStateService,
|
||||
this.kdfConfigService,
|
||||
);
|
||||
|
||||
this.appIdService = new AppIdService(this.globalStateProvider);
|
||||
@ -675,6 +682,7 @@ export default class MainBackground {
|
||||
this.userDecryptionOptionsService,
|
||||
this.globalStateProvider,
|
||||
this.billingAccountProfileStateService,
|
||||
this.kdfConfigService,
|
||||
);
|
||||
|
||||
this.ssoLoginService = new SsoLoginService(this.stateProvider);
|
||||
@ -725,6 +733,7 @@ export default class MainBackground {
|
||||
this.cryptoService,
|
||||
this.vaultTimeoutSettingsService,
|
||||
this.logService,
|
||||
this.kdfConfigService,
|
||||
);
|
||||
|
||||
this.userVerificationService = new UserVerificationService(
|
||||
@ -739,6 +748,7 @@ export default class MainBackground {
|
||||
this.logService,
|
||||
this.vaultTimeoutSettingsService,
|
||||
this.platformUtilsService,
|
||||
this.kdfConfigService,
|
||||
);
|
||||
|
||||
this.vaultFilterService = new VaultFilterService(
|
||||
@ -861,7 +871,7 @@ export default class MainBackground {
|
||||
this.cipherService,
|
||||
this.cryptoService,
|
||||
this.cryptoFunctionService,
|
||||
this.stateService,
|
||||
this.kdfConfigService,
|
||||
);
|
||||
|
||||
this.organizationVaultExportService = new OrganizationVaultExportService(
|
||||
@ -869,8 +879,8 @@ export default class MainBackground {
|
||||
this.apiService,
|
||||
this.cryptoService,
|
||||
this.cryptoFunctionService,
|
||||
this.stateService,
|
||||
this.collectionService,
|
||||
this.kdfConfigService,
|
||||
);
|
||||
|
||||
this.exportService = new VaultExportService(
|
||||
|
@ -4,6 +4,10 @@ import {
|
||||
AccountServiceInitOptions,
|
||||
accountServiceFactory,
|
||||
} from "../../../auth/background/service-factories/account-service.factory";
|
||||
import {
|
||||
KdfConfigServiceInitOptions,
|
||||
kdfConfigServiceFactory,
|
||||
} from "../../../auth/background/service-factories/kdf-config-service.factory";
|
||||
import {
|
||||
internalMasterPasswordServiceFactory,
|
||||
MasterPasswordServiceInitOptions,
|
||||
@ -18,7 +22,10 @@ import {
|
||||
} from "../../background/service-factories/log-service.factory";
|
||||
import { BrowserCryptoService } from "../../services/browser-crypto.service";
|
||||
|
||||
import { biometricStateServiceFactory } from "./biometric-state-service.factory";
|
||||
import {
|
||||
BiometricStateServiceInitOptions,
|
||||
biometricStateServiceFactory,
|
||||
} from "./biometric-state-service.factory";
|
||||
import {
|
||||
cryptoFunctionServiceFactory,
|
||||
CryptoFunctionServiceInitOptions,
|
||||
@ -46,7 +53,9 @@ export type CryptoServiceInitOptions = CryptoServiceFactoryOptions &
|
||||
LogServiceInitOptions &
|
||||
StateServiceInitOptions &
|
||||
AccountServiceInitOptions &
|
||||
StateProviderInitOptions;
|
||||
StateProviderInitOptions &
|
||||
BiometricStateServiceInitOptions &
|
||||
KdfConfigServiceInitOptions;
|
||||
|
||||
export function cryptoServiceFactory(
|
||||
cache: { cryptoService?: AbstractCryptoService } & CachedServices,
|
||||
@ -68,6 +77,7 @@ export function cryptoServiceFactory(
|
||||
await accountServiceFactory(cache, opts),
|
||||
await stateProviderFactory(cache, opts),
|
||||
await biometricStateServiceFactory(cache, opts),
|
||||
await kdfConfigServiceFactory(cache, opts),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
import { firstValueFrom } from "rxjs";
|
||||
|
||||
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
||||
import { KdfConfigService } from "@bitwarden/common/auth/abstractions/kdf-config.service";
|
||||
import { InternalMasterPasswordServiceAbstraction } from "@bitwarden/common/auth/abstractions/master-password.service.abstraction";
|
||||
import { CryptoFunctionService } from "@bitwarden/common/platform/abstractions/crypto-function.service";
|
||||
import { EncryptService } from "@bitwarden/common/platform/abstractions/encrypt.service";
|
||||
@ -28,6 +29,7 @@ export class BrowserCryptoService extends CryptoService {
|
||||
accountService: AccountService,
|
||||
stateProvider: StateProvider,
|
||||
private biometricStateService: BiometricStateService,
|
||||
kdfConfigService: KdfConfigService,
|
||||
) {
|
||||
super(
|
||||
masterPasswordService,
|
||||
@ -39,6 +41,7 @@ export class BrowserCryptoService extends CryptoService {
|
||||
stateService,
|
||||
accountService,
|
||||
stateProvider,
|
||||
kdfConfigService,
|
||||
);
|
||||
}
|
||||
override async hasUserKeyStored(keySuffix: KeySuffixOptions, userId?: UserId): Promise<boolean> {
|
||||
|
@ -16,6 +16,7 @@ import { OrganizationService } from "@bitwarden/common/admin-console/abstraction
|
||||
import { PolicyApiServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/policy/policy-api.service.abstraction";
|
||||
import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction";
|
||||
import { AuthService } from "@bitwarden/common/auth/abstractions/auth.service";
|
||||
import { KdfConfigService } from "@bitwarden/common/auth/abstractions/kdf-config.service";
|
||||
import { KeyConnectorService } from "@bitwarden/common/auth/abstractions/key-connector.service";
|
||||
import { TwoFactorService } from "@bitwarden/common/auth/abstractions/two-factor.service";
|
||||
import { TwoFactorProviderType } from "@bitwarden/common/auth/enums/two-factor-provider-type";
|
||||
@ -68,6 +69,7 @@ export class LoginCommand {
|
||||
protected policyApiService: PolicyApiServiceAbstraction,
|
||||
protected orgService: OrganizationService,
|
||||
protected logoutCallback: () => Promise<void>,
|
||||
protected kdfConfigService: KdfConfigService,
|
||||
) {}
|
||||
|
||||
async run(email: string, password: string, options: OptionValues) {
|
||||
@ -563,14 +565,12 @@ export class LoginCommand {
|
||||
message: "Master Password Hint (optional):",
|
||||
});
|
||||
const masterPasswordHint = hint.input;
|
||||
const kdf = await this.stateService.getKdfType();
|
||||
const kdfConfig = await this.stateService.getKdfConfig();
|
||||
const kdfConfig = await this.kdfConfigService.getKdfConfig();
|
||||
|
||||
// Create new key and hash new password
|
||||
const newMasterKey = await this.cryptoService.makeMasterKey(
|
||||
masterPassword,
|
||||
this.email.trim().toLowerCase(),
|
||||
kdf,
|
||||
kdfConfig,
|
||||
);
|
||||
const newPasswordHash = await this.cryptoService.hashMasterKey(masterPassword, newMasterKey);
|
||||
|
@ -3,6 +3,7 @@ import { firstValueFrom } from "rxjs";
|
||||
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
||||
import { OrganizationApiServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/organization/organization-api.service.abstraction";
|
||||
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
||||
import { KdfConfigService } from "@bitwarden/common/auth/abstractions/kdf-config.service";
|
||||
import { KeyConnectorService } from "@bitwarden/common/auth/abstractions/key-connector.service";
|
||||
import { InternalMasterPasswordServiceAbstraction } from "@bitwarden/common/auth/abstractions/master-password.service.abstraction";
|
||||
import { SecretVerificationRequest } from "@bitwarden/common/auth/models/request/secret-verification.request";
|
||||
@ -34,6 +35,7 @@ export class UnlockCommand {
|
||||
private syncService: SyncService,
|
||||
private organizationApiService: OrganizationApiServiceAbstraction,
|
||||
private logout: () => Promise<void>,
|
||||
private kdfConfigService: KdfConfigService,
|
||||
) {}
|
||||
|
||||
async run(password: string, cmdOptions: Record<string, any>) {
|
||||
@ -48,9 +50,8 @@ export class UnlockCommand {
|
||||
|
||||
await this.setNewSessionKey();
|
||||
const email = await this.stateService.getEmail();
|
||||
const kdf = await this.stateService.getKdfType();
|
||||
const kdfConfig = await this.stateService.getKdfConfig();
|
||||
const masterKey = await this.cryptoService.makeMasterKey(password, email, kdf, kdfConfig);
|
||||
const kdfConfig = await this.kdfConfigService.getKdfConfig();
|
||||
const masterKey = await this.cryptoService.makeMasterKey(password, email, kdfConfig);
|
||||
const userId = (await firstValueFrom(this.accountService.activeAccount$))?.id;
|
||||
const storedMasterKeyHash = await firstValueFrom(
|
||||
this.masterPasswordService.masterKeyHash$(userId),
|
||||
|
@ -30,12 +30,14 @@ import { AccountService } from "@bitwarden/common/auth/abstractions/account.serv
|
||||
import { AvatarService as AvatarServiceAbstraction } from "@bitwarden/common/auth/abstractions/avatar.service";
|
||||
import { DeviceTrustServiceAbstraction } from "@bitwarden/common/auth/abstractions/device-trust.service.abstraction";
|
||||
import { DevicesApiServiceAbstraction } from "@bitwarden/common/auth/abstractions/devices-api.service.abstraction";
|
||||
import { KdfConfigService as KdfConfigServiceAbstraction } from "@bitwarden/common/auth/abstractions/kdf-config.service";
|
||||
import { InternalMasterPasswordServiceAbstraction } from "@bitwarden/common/auth/abstractions/master-password.service.abstraction";
|
||||
import { AccountServiceImplementation } from "@bitwarden/common/auth/services/account.service";
|
||||
import { AuthService } from "@bitwarden/common/auth/services/auth.service";
|
||||
import { AvatarService } from "@bitwarden/common/auth/services/avatar.service";
|
||||
import { DeviceTrustService } from "@bitwarden/common/auth/services/device-trust.service.implementation";
|
||||
import { DevicesApiServiceImplementation } from "@bitwarden/common/auth/services/devices-api.service.implementation";
|
||||
import { KdfConfigService } from "@bitwarden/common/auth/services/kdf-config.service";
|
||||
import { KeyConnectorService } from "@bitwarden/common/auth/services/key-connector.service";
|
||||
import { MasterPasswordService } from "@bitwarden/common/auth/services/master-password/master-password.service";
|
||||
import { TokenService } from "@bitwarden/common/auth/services/token.service";
|
||||
@ -235,6 +237,7 @@ export class Main {
|
||||
billingAccountProfileStateService: BillingAccountProfileStateService;
|
||||
providerApiService: ProviderApiServiceAbstraction;
|
||||
userKeyInitService: UserKeyInitService;
|
||||
kdfConfigService: KdfConfigServiceAbstraction;
|
||||
|
||||
constructor() {
|
||||
let p = null;
|
||||
@ -357,6 +360,8 @@ export class Main {
|
||||
|
||||
this.masterPasswordService = new MasterPasswordService(this.stateProvider);
|
||||
|
||||
this.kdfConfigService = new KdfConfigService(this.stateProvider);
|
||||
|
||||
this.cryptoService = new CryptoService(
|
||||
this.masterPasswordService,
|
||||
this.keyGenerationService,
|
||||
@ -367,6 +372,7 @@ export class Main {
|
||||
this.stateService,
|
||||
this.accountService,
|
||||
this.stateProvider,
|
||||
this.kdfConfigService,
|
||||
);
|
||||
|
||||
this.appIdService = new AppIdService(this.globalStateProvider);
|
||||
@ -512,6 +518,7 @@ export class Main {
|
||||
this.userDecryptionOptionsService,
|
||||
this.globalStateProvider,
|
||||
this.billingAccountProfileStateService,
|
||||
this.kdfConfigService,
|
||||
);
|
||||
|
||||
this.authService = new AuthService(
|
||||
@ -574,6 +581,7 @@ export class Main {
|
||||
this.cryptoService,
|
||||
this.vaultTimeoutSettingsService,
|
||||
this.logService,
|
||||
this.kdfConfigService,
|
||||
);
|
||||
|
||||
this.userVerificationService = new UserVerificationService(
|
||||
@ -588,6 +596,7 @@ export class Main {
|
||||
this.logService,
|
||||
this.vaultTimeoutSettingsService,
|
||||
this.platformUtilsService,
|
||||
this.kdfConfigService,
|
||||
);
|
||||
|
||||
this.vaultTimeoutService = new VaultTimeoutService(
|
||||
@ -654,7 +663,7 @@ export class Main {
|
||||
this.cipherService,
|
||||
this.cryptoService,
|
||||
this.cryptoFunctionService,
|
||||
this.stateService,
|
||||
this.kdfConfigService,
|
||||
);
|
||||
|
||||
this.organizationExportService = new OrganizationVaultExportService(
|
||||
@ -662,8 +671,8 @@ export class Main {
|
||||
this.apiService,
|
||||
this.cryptoService,
|
||||
this.cryptoFunctionService,
|
||||
this.stateService,
|
||||
this.collectionService,
|
||||
this.kdfConfigService,
|
||||
);
|
||||
|
||||
this.exportService = new VaultExportService(
|
||||
|
@ -134,6 +134,7 @@ export class ServeCommand {
|
||||
this.main.syncService,
|
||||
this.main.organizationApiService,
|
||||
async () => await this.main.logout(),
|
||||
this.main.kdfConfigService,
|
||||
);
|
||||
|
||||
this.sendCreateCommand = new SendCreateCommand(
|
||||
|
@ -156,6 +156,7 @@ export class Program {
|
||||
this.main.policyApiService,
|
||||
this.main.organizationService,
|
||||
async () => await this.main.logout(),
|
||||
this.main.kdfConfigService,
|
||||
);
|
||||
const response = await command.run(email, password, options);
|
||||
this.processResponse(response, true);
|
||||
@ -265,6 +266,7 @@ export class Program {
|
||||
this.main.syncService,
|
||||
this.main.organizationApiService,
|
||||
async () => await this.main.logout(),
|
||||
this.main.kdfConfigService,
|
||||
);
|
||||
const response = await command.run(password, cmd);
|
||||
this.processResponse(response);
|
||||
@ -627,6 +629,7 @@ export class Program {
|
||||
this.main.syncService,
|
||||
this.main.organizationApiService,
|
||||
this.main.logout,
|
||||
this.main.kdfConfigService,
|
||||
);
|
||||
const response = await command.run(null, null);
|
||||
if (!response.success) {
|
||||
|
@ -21,6 +21,7 @@ import { VaultTimeoutSettingsService } from "@bitwarden/common/abstractions/vaul
|
||||
import { PolicyService as PolicyServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction";
|
||||
import { AccountService as AccountServiceAbstraction } from "@bitwarden/common/auth/abstractions/account.service";
|
||||
import { AuthService as AuthServiceAbstraction } from "@bitwarden/common/auth/abstractions/auth.service";
|
||||
import { KdfConfigService as KdfConfigServiceAbstraction } from "@bitwarden/common/auth/abstractions/kdf-config.service";
|
||||
import { InternalMasterPasswordServiceAbstraction } from "@bitwarden/common/auth/abstractions/master-password.service.abstraction";
|
||||
import { TokenService } from "@bitwarden/common/auth/abstractions/token.service";
|
||||
import { AutofillSettingsServiceAbstraction } from "@bitwarden/common/autofill/services/autofill-settings.service";
|
||||
@ -258,6 +259,7 @@ const safeProviders: SafeProvider[] = [
|
||||
AccountServiceAbstraction,
|
||||
StateProvider,
|
||||
BiometricStateService,
|
||||
KdfConfigServiceAbstraction,
|
||||
],
|
||||
}),
|
||||
safeProvider({
|
||||
|
@ -14,6 +14,7 @@ import { PolicyApiServiceAbstraction } from "@bitwarden/common/admin-console/abs
|
||||
import { InternalPolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction";
|
||||
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
||||
import { DeviceTrustServiceAbstraction } from "@bitwarden/common/auth/abstractions/device-trust.service.abstraction";
|
||||
import { KdfConfigService } from "@bitwarden/common/auth/abstractions/kdf-config.service";
|
||||
import { InternalMasterPasswordServiceAbstraction } from "@bitwarden/common/auth/abstractions/master-password.service.abstraction";
|
||||
import { UserVerificationService } from "@bitwarden/common/auth/abstractions/user-verification/user-verification.service.abstraction";
|
||||
import { FakeMasterPasswordService } from "@bitwarden/common/auth/services/master-password/fake-master-password.service";
|
||||
@ -164,6 +165,10 @@ describe("LockComponent", () => {
|
||||
provide: AccountService,
|
||||
useValue: accountService,
|
||||
},
|
||||
{
|
||||
provide: KdfConfigService,
|
||||
useValue: mock<KdfConfigService>(),
|
||||
},
|
||||
],
|
||||
schemas: [NO_ERRORS_SCHEMA],
|
||||
}).compileComponents();
|
||||
|
@ -11,6 +11,7 @@ import { PolicyApiServiceAbstraction } from "@bitwarden/common/admin-console/abs
|
||||
import { InternalPolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction";
|
||||
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
||||
import { DeviceTrustServiceAbstraction } from "@bitwarden/common/auth/abstractions/device-trust.service.abstraction";
|
||||
import { KdfConfigService } from "@bitwarden/common/auth/abstractions/kdf-config.service";
|
||||
import { InternalMasterPasswordServiceAbstraction } from "@bitwarden/common/auth/abstractions/master-password.service.abstraction";
|
||||
import { UserVerificationService } from "@bitwarden/common/auth/abstractions/user-verification/user-verification.service.abstraction";
|
||||
import { DeviceType } from "@bitwarden/common/enums";
|
||||
@ -63,6 +64,7 @@ export class LockComponent extends BaseLockComponent {
|
||||
pinCryptoService: PinCryptoServiceAbstraction,
|
||||
biometricStateService: BiometricStateService,
|
||||
accountService: AccountService,
|
||||
kdfConfigService: KdfConfigService,
|
||||
) {
|
||||
super(
|
||||
masterPasswordService,
|
||||
@ -87,6 +89,7 @@ export class LockComponent extends BaseLockComponent {
|
||||
pinCryptoService,
|
||||
biometricStateService,
|
||||
accountService,
|
||||
kdfConfigService,
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -9,6 +9,7 @@ import { OrganizationUserService } from "@bitwarden/common/admin-console/abstrac
|
||||
import { PolicyApiServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/policy/policy-api.service.abstraction";
|
||||
import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction";
|
||||
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
||||
import { KdfConfigService } from "@bitwarden/common/auth/abstractions/kdf-config.service";
|
||||
import { InternalMasterPasswordServiceAbstraction } from "@bitwarden/common/auth/abstractions/master-password.service.abstraction";
|
||||
import { SsoLoginServiceAbstraction } from "@bitwarden/common/auth/abstractions/sso-login.service.abstraction";
|
||||
import { BroadcasterService } from "@bitwarden/common/platform/abstractions/broadcaster.service";
|
||||
@ -52,6 +53,7 @@ export class SetPasswordComponent extends BaseSetPasswordComponent implements On
|
||||
userDecryptionOptionsService: InternalUserDecryptionOptionsServiceAbstraction,
|
||||
ssoLoginService: SsoLoginServiceAbstraction,
|
||||
dialogService: DialogService,
|
||||
kdfConfigService: KdfConfigService,
|
||||
) {
|
||||
super(
|
||||
accountService,
|
||||
@ -73,6 +75,7 @@ export class SetPasswordComponent extends BaseSetPasswordComponent implements On
|
||||
userDecryptionOptionsService,
|
||||
ssoLoginService,
|
||||
dialogService,
|
||||
kdfConfigService,
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
import { FakeStateProvider } from "@bitwarden/common/../spec/fake-state-provider";
|
||||
import { mock } from "jest-mock-extended";
|
||||
|
||||
import { KdfConfigService } from "@bitwarden/common/auth/abstractions/kdf-config.service";
|
||||
import { FakeMasterPasswordService } from "@bitwarden/common/auth/services/master-password/fake-master-password.service";
|
||||
import { CryptoFunctionService } from "@bitwarden/common/platform/abstractions/crypto-function.service";
|
||||
import { EncryptService } from "@bitwarden/common/platform/abstractions/encrypt.service";
|
||||
@ -35,6 +36,7 @@ describe("electronCryptoService", () => {
|
||||
let accountService: FakeAccountService;
|
||||
let stateProvider: FakeStateProvider;
|
||||
const biometricStateService = mock<BiometricStateService>();
|
||||
const kdfConfigService = mock<KdfConfigService>();
|
||||
|
||||
const mockUserId = "mock user id" as UserId;
|
||||
|
||||
@ -54,6 +56,7 @@ describe("electronCryptoService", () => {
|
||||
accountService,
|
||||
stateProvider,
|
||||
biometricStateService,
|
||||
kdfConfigService,
|
||||
);
|
||||
});
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
import { firstValueFrom } from "rxjs";
|
||||
|
||||
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
||||
import { KdfConfigService } from "@bitwarden/common/auth/abstractions/kdf-config.service";
|
||||
import { InternalMasterPasswordServiceAbstraction } from "@bitwarden/common/auth/abstractions/master-password.service.abstraction";
|
||||
import { CryptoFunctionService } from "@bitwarden/common/platform/abstractions/crypto-function.service";
|
||||
import { EncryptService } from "@bitwarden/common/platform/abstractions/encrypt.service";
|
||||
@ -31,6 +32,7 @@ export class ElectronCryptoService extends CryptoService {
|
||||
accountService: AccountService,
|
||||
stateProvider: StateProvider,
|
||||
private biometricStateService: BiometricStateService,
|
||||
kdfConfigService: KdfConfigService,
|
||||
) {
|
||||
super(
|
||||
masterPasswordService,
|
||||
@ -42,6 +44,7 @@ export class ElectronCryptoService extends CryptoService {
|
||||
stateService,
|
||||
accountService,
|
||||
stateProvider,
|
||||
kdfConfigService,
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -7,10 +7,15 @@ import {
|
||||
OrganizationUserResetPasswordRequest,
|
||||
OrganizationUserResetPasswordWithIdRequest,
|
||||
} from "@bitwarden/common/admin-console/abstractions/organization-user/requests";
|
||||
import { KdfConfig } from "@bitwarden/common/auth/models/domain/kdf-config";
|
||||
import {
|
||||
Argon2KdfConfig,
|
||||
KdfConfig,
|
||||
PBKDF2KdfConfig,
|
||||
} from "@bitwarden/common/auth/models/domain/kdf-config";
|
||||
import { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.service";
|
||||
import { EncryptService } from "@bitwarden/common/platform/abstractions/encrypt.service";
|
||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||
import { KdfType } from "@bitwarden/common/platform/enums";
|
||||
import { Utils } from "@bitwarden/common/platform/misc/utils";
|
||||
import { EncryptedString, EncString } from "@bitwarden/common/platform/models/domain/enc-string";
|
||||
import { SymmetricCryptoKey } from "@bitwarden/common/platform/models/domain/symmetric-crypto-key";
|
||||
@ -90,12 +95,17 @@ export class OrganizationUserResetPasswordService {
|
||||
const decValue = await this.cryptoService.rsaDecrypt(response.resetPasswordKey, decPrivateKey);
|
||||
const existingUserKey = new SymmetricCryptoKey(decValue) as UserKey;
|
||||
|
||||
// determine Kdf Algorithm
|
||||
const kdfConfig: KdfConfig =
|
||||
response.kdf === KdfType.PBKDF2_SHA256
|
||||
? new PBKDF2KdfConfig(response.kdfIterations)
|
||||
: new Argon2KdfConfig(response.kdfIterations, response.kdfMemory, response.kdfParallelism);
|
||||
|
||||
// Create new master key and hash new password
|
||||
const newMasterKey = await this.cryptoService.makeMasterKey(
|
||||
newMasterPassword,
|
||||
email.trim().toLowerCase(),
|
||||
response.kdf,
|
||||
new KdfConfig(response.kdfIterations, response.kdfMemory, response.kdfParallelism),
|
||||
kdfConfig,
|
||||
);
|
||||
const newMasterKeyHash = await this.cryptoService.hashMasterKey(
|
||||
newMasterPassword,
|
||||
|
@ -3,10 +3,15 @@ import { Injectable } from "@angular/core";
|
||||
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
||||
import { PolicyData } from "@bitwarden/common/admin-console/models/data/policy.data";
|
||||
import { Policy } from "@bitwarden/common/admin-console/models/domain/policy";
|
||||
import { KdfConfig } from "@bitwarden/common/auth/models/domain/kdf-config";
|
||||
import {
|
||||
Argon2KdfConfig,
|
||||
KdfConfig,
|
||||
PBKDF2KdfConfig,
|
||||
} from "@bitwarden/common/auth/models/domain/kdf-config";
|
||||
import { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.service";
|
||||
import { EncryptService } from "@bitwarden/common/platform/abstractions/encrypt.service";
|
||||
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
|
||||
import { KdfType } from "@bitwarden/common/platform/enums";
|
||||
import { Utils } from "@bitwarden/common/platform/misc/utils";
|
||||
import { EncryptedString } from "@bitwarden/common/platform/models/domain/enc-string";
|
||||
import { SymmetricCryptoKey } from "@bitwarden/common/platform/models/domain/symmetric-crypto-key";
|
||||
@ -231,16 +236,22 @@ export class EmergencyAccessService {
|
||||
|
||||
const grantorUserKey = new SymmetricCryptoKey(grantorKeyBuffer) as UserKey;
|
||||
|
||||
const masterKey = await this.cryptoService.makeMasterKey(
|
||||
masterPassword,
|
||||
email,
|
||||
takeoverResponse.kdf,
|
||||
new KdfConfig(
|
||||
takeoverResponse.kdfIterations,
|
||||
takeoverResponse.kdfMemory,
|
||||
takeoverResponse.kdfParallelism,
|
||||
),
|
||||
);
|
||||
let config: KdfConfig;
|
||||
|
||||
switch (takeoverResponse.kdf) {
|
||||
case KdfType.PBKDF2_SHA256:
|
||||
config = new PBKDF2KdfConfig(takeoverResponse.kdfIterations);
|
||||
break;
|
||||
case KdfType.Argon2id:
|
||||
config = new Argon2KdfConfig(
|
||||
takeoverResponse.kdfIterations,
|
||||
takeoverResponse.kdfMemory,
|
||||
takeoverResponse.kdfParallelism,
|
||||
);
|
||||
break;
|
||||
}
|
||||
|
||||
const masterKey = await this.cryptoService.makeMasterKey(masterPassword, email, config);
|
||||
const masterKeyHash = await this.cryptoService.hashMasterKey(masterPassword, masterKey);
|
||||
|
||||
const encKey = await this.cryptoService.encryptUserKeyWithMasterKey(masterKey, grantorUserKey);
|
||||
|
@ -2,6 +2,7 @@ import { mock, MockProxy } from "jest-mock-extended";
|
||||
import { BehaviorSubject } from "rxjs";
|
||||
|
||||
import { DeviceTrustServiceAbstraction } from "@bitwarden/common/auth/abstractions/device-trust.service.abstraction";
|
||||
import { KdfConfigService } from "@bitwarden/common/auth/abstractions/kdf-config.service";
|
||||
import { FakeMasterPasswordService } from "@bitwarden/common/auth/services/master-password/fake-master-password.service";
|
||||
import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service";
|
||||
import { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.service";
|
||||
@ -47,6 +48,7 @@ describe("KeyRotationService", () => {
|
||||
let mockEncryptService: MockProxy<EncryptService>;
|
||||
let mockStateService: MockProxy<StateService>;
|
||||
let mockConfigService: MockProxy<ConfigService>;
|
||||
let mockKdfConfigService: MockProxy<KdfConfigService>;
|
||||
|
||||
const mockUserId = Utils.newGuid() as UserId;
|
||||
const mockAccountService: FakeAccountService = mockAccountServiceWith(mockUserId);
|
||||
@ -65,6 +67,7 @@ describe("KeyRotationService", () => {
|
||||
mockEncryptService = mock<EncryptService>();
|
||||
mockStateService = mock<StateService>();
|
||||
mockConfigService = mock<ConfigService>();
|
||||
mockKdfConfigService = mock<KdfConfigService>();
|
||||
|
||||
keyRotationService = new UserKeyRotationService(
|
||||
mockMasterPasswordService,
|
||||
@ -80,6 +83,7 @@ describe("KeyRotationService", () => {
|
||||
mockStateService,
|
||||
mockAccountService,
|
||||
mockConfigService,
|
||||
mockKdfConfigService,
|
||||
);
|
||||
});
|
||||
|
||||
|
@ -3,6 +3,7 @@ import { firstValueFrom } from "rxjs";
|
||||
|
||||
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
||||
import { DeviceTrustServiceAbstraction } from "@bitwarden/common/auth/abstractions/device-trust.service.abstraction";
|
||||
import { KdfConfigService } from "@bitwarden/common/auth/abstractions/kdf-config.service";
|
||||
import { InternalMasterPasswordServiceAbstraction } from "@bitwarden/common/auth/abstractions/master-password.service.abstraction";
|
||||
import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum";
|
||||
import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service";
|
||||
@ -39,6 +40,7 @@ export class UserKeyRotationService {
|
||||
private stateService: StateService,
|
||||
private accountService: AccountService,
|
||||
private configService: ConfigService,
|
||||
private kdfConfigService: KdfConfigService,
|
||||
) {}
|
||||
|
||||
/**
|
||||
@ -54,8 +56,7 @@ export class UserKeyRotationService {
|
||||
const masterKey = await this.cryptoService.makeMasterKey(
|
||||
masterPassword,
|
||||
await this.stateService.getEmail(),
|
||||
await this.stateService.getKdfType(),
|
||||
await this.stateService.getKdfConfig(),
|
||||
await this.kdfConfigService.getKdfConfig(),
|
||||
);
|
||||
|
||||
if (!masterKey) {
|
||||
|
@ -2,6 +2,7 @@ import { Component, OnInit } from "@angular/core";
|
||||
import { FormBuilder, Validators } from "@angular/forms";
|
||||
|
||||
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
||||
import { KdfConfigService } from "@bitwarden/common/auth/abstractions/kdf-config.service";
|
||||
import { TwoFactorProviderType } from "@bitwarden/common/auth/enums/two-factor-provider-type";
|
||||
import { EmailTokenRequest } from "@bitwarden/common/auth/models/request/email-token.request";
|
||||
import { EmailRequest } from "@bitwarden/common/auth/models/request/email.request";
|
||||
@ -37,6 +38,7 @@ export class ChangeEmailComponent implements OnInit {
|
||||
private logService: LogService,
|
||||
private stateService: StateService,
|
||||
private formBuilder: FormBuilder,
|
||||
private kdfConfigService: KdfConfigService,
|
||||
) {}
|
||||
|
||||
async ngOnInit() {
|
||||
@ -83,12 +85,10 @@ export class ChangeEmailComponent implements OnInit {
|
||||
step1Value.masterPassword,
|
||||
await this.cryptoService.getOrDeriveMasterKey(step1Value.masterPassword),
|
||||
);
|
||||
const kdf = await this.stateService.getKdfType();
|
||||
const kdfConfig = await this.stateService.getKdfConfig();
|
||||
const kdfConfig = await this.kdfConfigService.getKdfConfig();
|
||||
const newMasterKey = await this.cryptoService.makeMasterKey(
|
||||
step1Value.masterPassword,
|
||||
newEmail,
|
||||
kdf,
|
||||
kdfConfig,
|
||||
);
|
||||
request.newMasterPasswordHash = await this.cryptoService.hashMasterKey(
|
||||
|
@ -5,6 +5,7 @@ import { ChangePasswordComponent as BaseChangePasswordComponent } from "@bitward
|
||||
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
||||
import { AuditService } from "@bitwarden/common/abstractions/audit.service";
|
||||
import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction";
|
||||
import { KdfConfigService } from "@bitwarden/common/auth/abstractions/kdf-config.service";
|
||||
import { UserVerificationService } from "@bitwarden/common/auth/abstractions/user-verification/user-verification.service.abstraction";
|
||||
import { PasswordRequest } from "@bitwarden/common/auth/models/request/password.request";
|
||||
import { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.service";
|
||||
@ -48,6 +49,7 @@ export class ChangePasswordComponent extends BaseChangePasswordComponent {
|
||||
dialogService: DialogService,
|
||||
private userVerificationService: UserVerificationService,
|
||||
private keyRotationService: UserKeyRotationService,
|
||||
kdfConfigService: KdfConfigService,
|
||||
) {
|
||||
super(
|
||||
i18nService,
|
||||
@ -58,6 +60,7 @@ export class ChangePasswordComponent extends BaseChangePasswordComponent {
|
||||
policyService,
|
||||
stateService,
|
||||
dialogService,
|
||||
kdfConfigService,
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -5,6 +5,7 @@ import { takeUntil } from "rxjs";
|
||||
|
||||
import { ChangePasswordComponent } from "@bitwarden/angular/auth/components/change-password.component";
|
||||
import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction";
|
||||
import { KdfConfigService } from "@bitwarden/common/auth/abstractions/kdf-config.service";
|
||||
import { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.service";
|
||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
|
||||
@ -58,6 +59,7 @@ export class EmergencyAccessTakeoverComponent
|
||||
private logService: LogService,
|
||||
dialogService: DialogService,
|
||||
private dialogRef: DialogRef<EmergencyAccessTakeoverResultType>,
|
||||
kdfConfigService: KdfConfigService,
|
||||
) {
|
||||
super(
|
||||
i18nService,
|
||||
@ -68,6 +70,7 @@ export class EmergencyAccessTakeoverComponent
|
||||
policyService,
|
||||
stateService,
|
||||
dialogService,
|
||||
kdfConfigService,
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -3,6 +3,7 @@ import { Component, Inject } from "@angular/core";
|
||||
import { FormGroup, FormControl, Validators } from "@angular/forms";
|
||||
|
||||
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
||||
import { KdfConfigService } from "@bitwarden/common/auth/abstractions/kdf-config.service";
|
||||
import { KdfConfig } from "@bitwarden/common/auth/models/domain/kdf-config";
|
||||
import { KdfRequest } from "@bitwarden/common/models/request/kdf.request";
|
||||
import { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.service";
|
||||
@ -18,7 +19,6 @@ import { KdfType } from "@bitwarden/common/platform/enums";
|
||||
templateUrl: "change-kdf-confirmation.component.html",
|
||||
})
|
||||
export class ChangeKdfConfirmationComponent {
|
||||
kdf: KdfType;
|
||||
kdfConfig: KdfConfig;
|
||||
|
||||
form = new FormGroup({
|
||||
@ -37,9 +37,9 @@ export class ChangeKdfConfirmationComponent {
|
||||
private messagingService: MessagingService,
|
||||
private stateService: StateService,
|
||||
private logService: LogService,
|
||||
@Inject(DIALOG_DATA) params: { kdf: KdfType; kdfConfig: KdfConfig },
|
||||
private kdfConfigService: KdfConfigService,
|
||||
@Inject(DIALOG_DATA) params: { kdfConfig: KdfConfig },
|
||||
) {
|
||||
this.kdf = params.kdf;
|
||||
this.kdfConfig = params.kdfConfig;
|
||||
this.masterPassword = null;
|
||||
}
|
||||
@ -65,22 +65,24 @@ export class ChangeKdfConfirmationComponent {
|
||||
|
||||
private async makeKeyAndSaveAsync() {
|
||||
const masterPassword = this.form.value.masterPassword;
|
||||
|
||||
// Ensure the KDF config is valid.
|
||||
this.kdfConfig.validateKdfConfig();
|
||||
|
||||
const request = new KdfRequest();
|
||||
request.kdf = this.kdf;
|
||||
request.kdf = this.kdfConfig.kdfType;
|
||||
request.kdfIterations = this.kdfConfig.iterations;
|
||||
request.kdfMemory = this.kdfConfig.memory;
|
||||
request.kdfParallelism = this.kdfConfig.parallelism;
|
||||
if (this.kdfConfig.kdfType === KdfType.Argon2id) {
|
||||
request.kdfMemory = this.kdfConfig.memory;
|
||||
request.kdfParallelism = this.kdfConfig.parallelism;
|
||||
}
|
||||
const masterKey = await this.cryptoService.getOrDeriveMasterKey(masterPassword);
|
||||
request.masterPasswordHash = await this.cryptoService.hashMasterKey(masterPassword, masterKey);
|
||||
const email = await this.stateService.getEmail();
|
||||
|
||||
// Ensure the KDF config is valid.
|
||||
this.cryptoService.validateKdfConfig(this.kdf, this.kdfConfig);
|
||||
|
||||
const newMasterKey = await this.cryptoService.makeMasterKey(
|
||||
masterPassword,
|
||||
email,
|
||||
this.kdf,
|
||||
this.kdfConfig,
|
||||
);
|
||||
request.newMasterPasswordHash = await this.cryptoService.hashMasterKey(
|
||||
|
@ -19,14 +19,14 @@
|
||||
<select
|
||||
id="kdf"
|
||||
name="Kdf"
|
||||
[(ngModel)]="kdf"
|
||||
[(ngModel)]="kdfConfig.kdfType"
|
||||
(ngModelChange)="onChangeKdf($event)"
|
||||
class="form-control mb-3"
|
||||
required
|
||||
>
|
||||
<option *ngFor="let o of kdfOptions" [ngValue]="o.value">{{ o.name }}</option>
|
||||
</select>
|
||||
<ng-container *ngIf="kdf == kdfType.Argon2id">
|
||||
<ng-container *ngIf="isArgon2(kdfConfig)">
|
||||
<label for="kdfMemory">{{ "kdfMemory" | i18n }}</label>
|
||||
<input
|
||||
id="kdfMemory"
|
||||
@ -43,7 +43,7 @@
|
||||
</div>
|
||||
<div class="col-6">
|
||||
<div class="form-group mb-0">
|
||||
<ng-container *ngIf="kdf == kdfType.PBKDF2_SHA256">
|
||||
<ng-container *ngIf="isPBKDF2(kdfConfig)">
|
||||
<label for="kdfIterations">{{ "kdfIterations" | i18n }}</label>
|
||||
<a
|
||||
class="ml-auto"
|
||||
@ -65,7 +65,7 @@
|
||||
required
|
||||
/>
|
||||
</ng-container>
|
||||
<ng-container *ngIf="kdf == kdfType.Argon2id">
|
||||
<ng-container *ngIf="isArgon2(kdfConfig)">
|
||||
<label for="kdfIterations">{{ "kdfIterations" | i18n }}</label>
|
||||
<input
|
||||
id="iterations"
|
||||
@ -92,7 +92,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12">
|
||||
<ng-container *ngIf="kdf == kdfType.PBKDF2_SHA256">
|
||||
<ng-container *ngIf="isPBKDF2(kdfConfig)">
|
||||
<p class="small form-text text-muted">
|
||||
{{ "kdfIterationsDesc" | i18n: (PBKDF2_ITERATIONS.defaultValue | number) }}
|
||||
</p>
|
||||
@ -100,7 +100,7 @@
|
||||
{{ "kdfIterationsWarning" | i18n: (100000 | number) }}
|
||||
</bit-callout>
|
||||
</ng-container>
|
||||
<ng-container *ngIf="kdf == kdfType.Argon2id">
|
||||
<ng-container *ngIf="isArgon2(kdfConfig)">
|
||||
<p class="small form-text text-muted">{{ "argon2Desc" | i18n }}</p>
|
||||
<bit-callout type="warning"> {{ "argon2Warning" | i18n }}</bit-callout>
|
||||
</ng-container>
|
||||
|
@ -1,7 +1,11 @@
|
||||
import { Component, OnInit } from "@angular/core";
|
||||
|
||||
import { KdfConfig } from "@bitwarden/common/auth/models/domain/kdf-config";
|
||||
import { StateService } from "@bitwarden/common/platform/abstractions/state.service";
|
||||
import { KdfConfigService } from "@bitwarden/common/auth/abstractions/kdf-config.service";
|
||||
import {
|
||||
Argon2KdfConfig,
|
||||
KdfConfig,
|
||||
PBKDF2KdfConfig,
|
||||
} from "@bitwarden/common/auth/models/domain/kdf-config";
|
||||
import {
|
||||
DEFAULT_KDF_CONFIG,
|
||||
PBKDF2_ITERATIONS,
|
||||
@ -19,7 +23,6 @@ import { ChangeKdfConfirmationComponent } from "./change-kdf-confirmation.compon
|
||||
templateUrl: "change-kdf.component.html",
|
||||
})
|
||||
export class ChangeKdfComponent implements OnInit {
|
||||
kdf = KdfType.PBKDF2_SHA256;
|
||||
kdfConfig: KdfConfig = DEFAULT_KDF_CONFIG;
|
||||
kdfType = KdfType;
|
||||
kdfOptions: any[] = [];
|
||||
@ -31,8 +34,8 @@ export class ChangeKdfComponent implements OnInit {
|
||||
protected ARGON2_PARALLELISM = ARGON2_PARALLELISM;
|
||||
|
||||
constructor(
|
||||
private stateService: StateService,
|
||||
private dialogService: DialogService,
|
||||
private kdfConfigService: KdfConfigService,
|
||||
) {
|
||||
this.kdfOptions = [
|
||||
{ name: "PBKDF2 SHA-256", value: KdfType.PBKDF2_SHA256 },
|
||||
@ -41,19 +44,22 @@ export class ChangeKdfComponent implements OnInit {
|
||||
}
|
||||
|
||||
async ngOnInit() {
|
||||
this.kdf = await this.stateService.getKdfType();
|
||||
this.kdfConfig = await this.stateService.getKdfConfig();
|
||||
this.kdfConfig = await this.kdfConfigService.getKdfConfig();
|
||||
}
|
||||
|
||||
isPBKDF2(t: KdfConfig): t is PBKDF2KdfConfig {
|
||||
return t instanceof PBKDF2KdfConfig;
|
||||
}
|
||||
|
||||
isArgon2(t: KdfConfig): t is Argon2KdfConfig {
|
||||
return t instanceof Argon2KdfConfig;
|
||||
}
|
||||
|
||||
async onChangeKdf(newValue: KdfType) {
|
||||
if (newValue === KdfType.PBKDF2_SHA256) {
|
||||
this.kdfConfig = new KdfConfig(PBKDF2_ITERATIONS.defaultValue);
|
||||
this.kdfConfig = new PBKDF2KdfConfig();
|
||||
} else if (newValue === KdfType.Argon2id) {
|
||||
this.kdfConfig = new KdfConfig(
|
||||
ARGON2_ITERATIONS.defaultValue,
|
||||
ARGON2_MEMORY.defaultValue,
|
||||
ARGON2_PARALLELISM.defaultValue,
|
||||
);
|
||||
this.kdfConfig = new Argon2KdfConfig();
|
||||
} else {
|
||||
throw new Error("Unknown KDF type.");
|
||||
}
|
||||
@ -62,7 +68,6 @@ export class ChangeKdfComponent implements OnInit {
|
||||
async openConfirmationModal() {
|
||||
this.dialogService.open(ChangeKdfConfirmationComponent, {
|
||||
data: {
|
||||
kdf: this.kdf,
|
||||
kdfConfig: this.kdfConfig,
|
||||
},
|
||||
});
|
||||
|
@ -4,6 +4,7 @@ import { Router } from "@angular/router";
|
||||
import { UpdatePasswordComponent as BaseUpdatePasswordComponent } from "@bitwarden/angular/auth/components/update-password.component";
|
||||
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
||||
import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction";
|
||||
import { KdfConfigService } from "@bitwarden/common/auth/abstractions/kdf-config.service";
|
||||
import { UserVerificationService } from "@bitwarden/common/auth/abstractions/user-verification/user-verification.service.abstraction";
|
||||
import { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.service";
|
||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||
@ -32,6 +33,7 @@ export class UpdatePasswordComponent extends BaseUpdatePasswordComponent {
|
||||
stateService: StateService,
|
||||
userVerificationService: UserVerificationService,
|
||||
dialogService: DialogService,
|
||||
kdfConfigService: KdfConfigService,
|
||||
) {
|
||||
super(
|
||||
router,
|
||||
@ -46,6 +48,7 @@ export class UpdatePasswordComponent extends BaseUpdatePasswordComponent {
|
||||
userVerificationService,
|
||||
logService,
|
||||
dialogService,
|
||||
kdfConfigService,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -35,6 +35,7 @@ import { EventCollectionService } from "@bitwarden/common/abstractions/event/eve
|
||||
import { SearchService } from "@bitwarden/common/abstractions/search.service";
|
||||
import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
|
||||
import { Organization } from "@bitwarden/common/admin-console/models/domain/organization";
|
||||
import { KdfConfigService } from "@bitwarden/common/auth/abstractions/kdf-config.service";
|
||||
import { TokenService } from "@bitwarden/common/auth/abstractions/token.service";
|
||||
import { UserVerificationService } from "@bitwarden/common/auth/abstractions/user-verification/user-verification.service.abstraction";
|
||||
import { BillingAccountProfileStateService } from "@bitwarden/common/billing/abstractions/account/billing-account-profile-state.service";
|
||||
@ -184,6 +185,7 @@ export class VaultComponent implements OnInit, OnDestroy {
|
||||
private apiService: ApiService,
|
||||
private userVerificationService: UserVerificationService,
|
||||
private billingAccountProfileStateService: BillingAccountProfileStateService,
|
||||
protected kdfConfigService: KdfConfigService,
|
||||
) {}
|
||||
|
||||
async ngOnInit() {
|
||||
@ -972,10 +974,10 @@ export class VaultComponent implements OnInit, OnDestroy {
|
||||
}
|
||||
|
||||
async isLowKdfIteration() {
|
||||
const kdfType = await this.stateService.getKdfType();
|
||||
const kdfOptions = await this.stateService.getKdfConfig();
|
||||
const kdfConfig = await this.kdfConfigService.getKdfConfig();
|
||||
return (
|
||||
kdfType === KdfType.PBKDF2_SHA256 && kdfOptions.iterations < PBKDF2_ITERATIONS.defaultValue
|
||||
kdfConfig.kdfType === KdfType.PBKDF2_SHA256 &&
|
||||
kdfConfig.iterations < PBKDF2_ITERATIONS.defaultValue
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -3,13 +3,13 @@ import { Subject, takeUntil } from "rxjs";
|
||||
|
||||
import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction";
|
||||
import { MasterPasswordPolicyOptions } from "@bitwarden/common/admin-console/models/domain/master-password-policy-options";
|
||||
import { KdfConfigService } from "@bitwarden/common/auth/abstractions/kdf-config.service";
|
||||
import { KdfConfig } from "@bitwarden/common/auth/models/domain/kdf-config";
|
||||
import { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.service";
|
||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||
import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service";
|
||||
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
||||
import { StateService } from "@bitwarden/common/platform/abstractions/state.service";
|
||||
import { KdfType } from "@bitwarden/common/platform/enums";
|
||||
import { Utils } from "@bitwarden/common/platform/misc/utils";
|
||||
import { EncString } from "@bitwarden/common/platform/models/domain/enc-string";
|
||||
import { PasswordGenerationServiceAbstraction } from "@bitwarden/common/tools/generator/password";
|
||||
@ -31,7 +31,6 @@ export class ChangePasswordComponent implements OnInit, OnDestroy {
|
||||
minimumLength = Utils.minimumPasswordLength;
|
||||
|
||||
protected email: string;
|
||||
protected kdf: KdfType;
|
||||
protected kdfConfig: KdfConfig;
|
||||
|
||||
protected destroy$ = new Subject<void>();
|
||||
@ -45,6 +44,7 @@ export class ChangePasswordComponent implements OnInit, OnDestroy {
|
||||
protected policyService: PolicyService,
|
||||
protected stateService: StateService,
|
||||
protected dialogService: DialogService,
|
||||
protected kdfConfigService: KdfConfigService,
|
||||
) {}
|
||||
|
||||
async ngOnInit() {
|
||||
@ -73,18 +73,14 @@ export class ChangePasswordComponent implements OnInit, OnDestroy {
|
||||
}
|
||||
|
||||
const email = await this.stateService.getEmail();
|
||||
if (this.kdf == null) {
|
||||
this.kdf = await this.stateService.getKdfType();
|
||||
}
|
||||
if (this.kdfConfig == null) {
|
||||
this.kdfConfig = await this.stateService.getKdfConfig();
|
||||
this.kdfConfig = await this.kdfConfigService.getKdfConfig();
|
||||
}
|
||||
|
||||
// Create new master key
|
||||
const newMasterKey = await this.cryptoService.makeMasterKey(
|
||||
this.masterPassword,
|
||||
email.trim().toLowerCase(),
|
||||
this.kdf,
|
||||
this.kdfConfig,
|
||||
);
|
||||
const newMasterKeyHash = await this.cryptoService.hashMasterKey(
|
||||
|
@ -12,6 +12,7 @@ import { InternalPolicyService } from "@bitwarden/common/admin-console/abstracti
|
||||
import { MasterPasswordPolicyOptions } from "@bitwarden/common/admin-console/models/domain/master-password-policy-options";
|
||||
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
||||
import { DeviceTrustServiceAbstraction } from "@bitwarden/common/auth/abstractions/device-trust.service.abstraction";
|
||||
import { KdfConfigService } from "@bitwarden/common/auth/abstractions/kdf-config.service";
|
||||
import { InternalMasterPasswordServiceAbstraction } from "@bitwarden/common/auth/abstractions/master-password.service.abstraction";
|
||||
import { UserVerificationService } from "@bitwarden/common/auth/abstractions/user-verification/user-verification.service.abstraction";
|
||||
import { ForceSetPasswordReason } from "@bitwarden/common/auth/models/domain/force-set-password-reason";
|
||||
@ -79,6 +80,7 @@ export class LockComponent implements OnInit, OnDestroy {
|
||||
protected pinCryptoService: PinCryptoServiceAbstraction,
|
||||
protected biometricStateService: BiometricStateService,
|
||||
protected accountService: AccountService,
|
||||
protected kdfConfigService: KdfConfigService,
|
||||
) {}
|
||||
|
||||
async ngOnInit() {
|
||||
@ -208,14 +210,12 @@ export class LockComponent implements OnInit, OnDestroy {
|
||||
}
|
||||
|
||||
private async doUnlockWithMasterPassword() {
|
||||
const kdfConfig = await this.kdfConfigService.getKdfConfig();
|
||||
const userId = (await firstValueFrom(this.accountService.activeAccount$))?.id;
|
||||
const kdf = await this.stateService.getKdfType();
|
||||
const kdfConfig = await this.stateService.getKdfConfig();
|
||||
|
||||
const masterKey = await this.cryptoService.makeMasterKey(
|
||||
this.masterPassword,
|
||||
this.email,
|
||||
kdf,
|
||||
kdfConfig,
|
||||
);
|
||||
const storedMasterKeyHash = await firstValueFrom(
|
||||
|
@ -15,7 +15,7 @@ import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.servic
|
||||
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
|
||||
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
||||
import { StateService } from "@bitwarden/common/platform/abstractions/state.service";
|
||||
import { DEFAULT_KDF_CONFIG, DEFAULT_KDF_TYPE } from "@bitwarden/common/platform/enums";
|
||||
import { DEFAULT_KDF_CONFIG } from "@bitwarden/common/platform/enums";
|
||||
import { Utils } from "@bitwarden/common/platform/misc/utils";
|
||||
import { PasswordGenerationServiceAbstraction } from "@bitwarden/common/tools/generator/password";
|
||||
import { DialogService } from "@bitwarden/components";
|
||||
@ -273,9 +273,8 @@ export class RegisterComponent extends CaptchaProtectedComponent implements OnIn
|
||||
name: string,
|
||||
): Promise<RegisterRequest> {
|
||||
const hint = this.formGroup.value.hint;
|
||||
const kdf = DEFAULT_KDF_TYPE;
|
||||
const kdfConfig = DEFAULT_KDF_CONFIG;
|
||||
const key = await this.cryptoService.makeMasterKey(masterPassword, email, kdf, kdfConfig);
|
||||
const key = await this.cryptoService.makeMasterKey(masterPassword, email, kdfConfig);
|
||||
const newUserKey = await this.cryptoService.makeUserKey(key);
|
||||
const masterKeyHash = await this.cryptoService.hashMasterKey(masterPassword, key);
|
||||
const keys = await this.cryptoService.makeKeyPair(newUserKey[0]);
|
||||
@ -287,10 +286,8 @@ export class RegisterComponent extends CaptchaProtectedComponent implements OnIn
|
||||
newUserKey[1].encryptedString,
|
||||
this.referenceData,
|
||||
this.captchaToken,
|
||||
kdf,
|
||||
kdfConfig.kdfType,
|
||||
kdfConfig.iterations,
|
||||
kdfConfig.memory,
|
||||
kdfConfig.parallelism,
|
||||
);
|
||||
request.keys = new KeysRequest(keys[0], keys[1].encryptedString);
|
||||
const orgInvite = await this.stateService.getOrganizationInvitation();
|
||||
|
@ -13,6 +13,7 @@ import { PolicyService } from "@bitwarden/common/admin-console/abstractions/poli
|
||||
import { MasterPasswordPolicyOptions } from "@bitwarden/common/admin-console/models/domain/master-password-policy-options";
|
||||
import { OrganizationAutoEnrollStatusResponse } from "@bitwarden/common/admin-console/models/response/organization-auto-enroll-status.response";
|
||||
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
||||
import { KdfConfigService } from "@bitwarden/common/auth/abstractions/kdf-config.service";
|
||||
import { InternalMasterPasswordServiceAbstraction } from "@bitwarden/common/auth/abstractions/master-password.service.abstraction";
|
||||
import { SsoLoginServiceAbstraction } from "@bitwarden/common/auth/abstractions/sso-login.service.abstraction";
|
||||
import { ForceSetPasswordReason } from "@bitwarden/common/auth/models/domain/force-set-password-reason";
|
||||
@ -23,11 +24,7 @@ import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.servic
|
||||
import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service";
|
||||
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
||||
import { StateService } from "@bitwarden/common/platform/abstractions/state.service";
|
||||
import {
|
||||
HashPurpose,
|
||||
DEFAULT_KDF_TYPE,
|
||||
DEFAULT_KDF_CONFIG,
|
||||
} from "@bitwarden/common/platform/enums";
|
||||
import { HashPurpose, DEFAULT_KDF_CONFIG } from "@bitwarden/common/platform/enums";
|
||||
import { Utils } from "@bitwarden/common/platform/misc/utils";
|
||||
import { EncString } from "@bitwarden/common/platform/models/domain/enc-string";
|
||||
import { PasswordGenerationServiceAbstraction } from "@bitwarden/common/tools/generator/password";
|
||||
@ -73,6 +70,7 @@ export class SetPasswordComponent extends BaseChangePasswordComponent {
|
||||
private userDecryptionOptionsService: InternalUserDecryptionOptionsServiceAbstraction,
|
||||
private ssoLoginService: SsoLoginServiceAbstraction,
|
||||
dialogService: DialogService,
|
||||
kdfConfigService: KdfConfigService,
|
||||
) {
|
||||
super(
|
||||
i18nService,
|
||||
@ -83,6 +81,7 @@ export class SetPasswordComponent extends BaseChangePasswordComponent {
|
||||
policyService,
|
||||
stateService,
|
||||
dialogService,
|
||||
kdfConfigService,
|
||||
);
|
||||
}
|
||||
|
||||
@ -139,7 +138,6 @@ export class SetPasswordComponent extends BaseChangePasswordComponent {
|
||||
}
|
||||
|
||||
async setupSubmitActions() {
|
||||
this.kdf = DEFAULT_KDF_TYPE;
|
||||
this.kdfConfig = DEFAULT_KDF_CONFIG;
|
||||
return true;
|
||||
}
|
||||
@ -169,10 +167,8 @@ export class SetPasswordComponent extends BaseChangePasswordComponent {
|
||||
this.hint,
|
||||
this.orgSsoIdentifier,
|
||||
keysRequest,
|
||||
this.kdf,
|
||||
this.kdfConfig.kdfType, //always PBKDF2 --> see this.setupSubmitActions
|
||||
this.kdfConfig.iterations,
|
||||
this.kdfConfig.memory,
|
||||
this.kdfConfig.parallelism,
|
||||
);
|
||||
try {
|
||||
if (this.resetPasswordAutoEnroll) {
|
||||
@ -246,9 +242,7 @@ export class SetPasswordComponent extends BaseChangePasswordComponent {
|
||||
);
|
||||
userDecryptionOpts.hasMasterPassword = true;
|
||||
await this.userDecryptionOptionsService.setUserDecryptionOptions(userDecryptionOpts);
|
||||
|
||||
await this.stateService.setKdfType(this.kdf);
|
||||
await this.stateService.setKdfConfig(this.kdfConfig);
|
||||
await this.kdfConfigService.setKdfConfig(this.userId, this.kdfConfig);
|
||||
await this.masterPasswordService.setMasterKey(masterKey, this.userId);
|
||||
await this.cryptoService.setUserKey(userKey[0]);
|
||||
|
||||
|
@ -2,6 +2,7 @@ import { DialogRef } from "@angular/cdk/dialog";
|
||||
import { Directive, OnInit } from "@angular/core";
|
||||
import { FormBuilder, Validators } from "@angular/forms";
|
||||
|
||||
import { KdfConfigService } from "@bitwarden/common/auth/abstractions/kdf-config.service";
|
||||
import { UserVerificationService } from "@bitwarden/common/auth/abstractions/user-verification/user-verification.service.abstraction";
|
||||
import { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.service";
|
||||
import { StateService } from "@bitwarden/common/platform/abstractions/state.service";
|
||||
@ -22,6 +23,7 @@ export class SetPinComponent implements OnInit {
|
||||
private userVerificationService: UserVerificationService,
|
||||
private stateService: StateService,
|
||||
private formBuilder: FormBuilder,
|
||||
private kdfConfigService: KdfConfigService,
|
||||
) {}
|
||||
|
||||
async ngOnInit() {
|
||||
@ -43,8 +45,7 @@ export class SetPinComponent implements OnInit {
|
||||
const pinKey = await this.cryptoService.makePinKey(
|
||||
pin,
|
||||
await this.stateService.getEmail(),
|
||||
await this.stateService.getKdfType(),
|
||||
await this.stateService.getKdfConfig(),
|
||||
await this.kdfConfigService.getKdfConfig(),
|
||||
);
|
||||
const userKey = await this.cryptoService.getUserKey();
|
||||
const pinProtectedKey = await this.cryptoService.encrypt(userKey.key, pinKey);
|
||||
|
@ -4,6 +4,7 @@ import { Router } from "@angular/router";
|
||||
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
||||
import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction";
|
||||
import { MasterPasswordPolicyOptions } from "@bitwarden/common/admin-console/models/domain/master-password-policy-options";
|
||||
import { KdfConfigService } from "@bitwarden/common/auth/abstractions/kdf-config.service";
|
||||
import { UserVerificationService } from "@bitwarden/common/auth/abstractions/user-verification/user-verification.service.abstraction";
|
||||
import { VerificationType } from "@bitwarden/common/auth/enums/verification-type";
|
||||
import { PasswordRequest } from "@bitwarden/common/auth/models/request/password.request";
|
||||
@ -44,6 +45,7 @@ export class UpdatePasswordComponent extends BaseChangePasswordComponent {
|
||||
private userVerificationService: UserVerificationService,
|
||||
private logService: LogService,
|
||||
dialogService: DialogService,
|
||||
kdfConfigService: KdfConfigService,
|
||||
) {
|
||||
super(
|
||||
i18nService,
|
||||
@ -54,6 +56,7 @@ export class UpdatePasswordComponent extends BaseChangePasswordComponent {
|
||||
policyService,
|
||||
stateService,
|
||||
dialogService,
|
||||
kdfConfigService,
|
||||
);
|
||||
}
|
||||
|
||||
@ -90,8 +93,7 @@ export class UpdatePasswordComponent extends BaseChangePasswordComponent {
|
||||
return false;
|
||||
}
|
||||
|
||||
this.kdf = await this.stateService.getKdfType();
|
||||
this.kdfConfig = await this.stateService.getKdfConfig();
|
||||
this.kdfConfig = await this.kdfConfigService.getKdfConfig();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -6,6 +6,7 @@ import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
||||
import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction";
|
||||
import { MasterPasswordPolicyOptions } from "@bitwarden/common/admin-console/models/domain/master-password-policy-options";
|
||||
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
||||
import { KdfConfigService } from "@bitwarden/common/auth/abstractions/kdf-config.service";
|
||||
import { InternalMasterPasswordServiceAbstraction } from "@bitwarden/common/auth/abstractions/master-password.service.abstraction";
|
||||
import { UserVerificationService } from "@bitwarden/common/auth/abstractions/user-verification/user-verification.service.abstraction";
|
||||
import { VerificationType } from "@bitwarden/common/auth/enums/verification-type";
|
||||
@ -59,6 +60,7 @@ export class UpdateTempPasswordComponent extends BaseChangePasswordComponent {
|
||||
private userVerificationService: UserVerificationService,
|
||||
protected router: Router,
|
||||
dialogService: DialogService,
|
||||
kdfConfigService: KdfConfigService,
|
||||
private accountService: AccountService,
|
||||
private masterPasswordService: InternalMasterPasswordServiceAbstraction,
|
||||
) {
|
||||
@ -71,6 +73,7 @@ export class UpdateTempPasswordComponent extends BaseChangePasswordComponent {
|
||||
policyService,
|
||||
stateService,
|
||||
dialogService,
|
||||
kdfConfigService,
|
||||
);
|
||||
}
|
||||
|
||||
@ -104,8 +107,7 @@ export class UpdateTempPasswordComponent extends BaseChangePasswordComponent {
|
||||
|
||||
async setupSubmitActions(): Promise<boolean> {
|
||||
this.email = await this.stateService.getEmail();
|
||||
this.kdf = await this.stateService.getKdfType();
|
||||
this.kdfConfig = await this.stateService.getKdfConfig();
|
||||
this.kdfConfig = await this.kdfConfigService.getKdfConfig();
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -124,7 +126,6 @@ export class UpdateTempPasswordComponent extends BaseChangePasswordComponent {
|
||||
const newMasterKey = await this.cryptoService.makeMasterKey(
|
||||
this.masterPassword,
|
||||
this.email.trim().toLowerCase(),
|
||||
this.kdf,
|
||||
this.kdfConfig,
|
||||
);
|
||||
const newPasswordHash = await this.cryptoService.hashMasterKey(
|
||||
|
@ -63,6 +63,7 @@ import { AvatarService as AvatarServiceAbstraction } from "@bitwarden/common/aut
|
||||
import { DeviceTrustServiceAbstraction } from "@bitwarden/common/auth/abstractions/device-trust.service.abstraction";
|
||||
import { DevicesServiceAbstraction } from "@bitwarden/common/auth/abstractions/devices/devices.service.abstraction";
|
||||
import { DevicesApiServiceAbstraction } from "@bitwarden/common/auth/abstractions/devices-api.service.abstraction";
|
||||
import { KdfConfigService as KdfConfigServiceAbstraction } from "@bitwarden/common/auth/abstractions/kdf-config.service";
|
||||
import { KeyConnectorService as KeyConnectorServiceAbstraction } from "@bitwarden/common/auth/abstractions/key-connector.service";
|
||||
import {
|
||||
InternalMasterPasswordServiceAbstraction,
|
||||
@ -85,6 +86,7 @@ import { AvatarService } from "@bitwarden/common/auth/services/avatar.service";
|
||||
import { DeviceTrustService } from "@bitwarden/common/auth/services/device-trust.service.implementation";
|
||||
import { DevicesServiceImplementation } from "@bitwarden/common/auth/services/devices/devices.service.implementation";
|
||||
import { DevicesApiServiceImplementation } from "@bitwarden/common/auth/services/devices-api.service.implementation";
|
||||
import { KdfConfigService } from "@bitwarden/common/auth/services/kdf-config.service";
|
||||
import { KeyConnectorService } from "@bitwarden/common/auth/services/key-connector.service";
|
||||
import { MasterPasswordService } from "@bitwarden/common/auth/services/master-password/master-password.service";
|
||||
import { PasswordResetEnrollmentServiceImplementation } from "@bitwarden/common/auth/services/password-reset-enrollment.service.implementation";
|
||||
@ -390,6 +392,7 @@ const safeProviders: SafeProvider[] = [
|
||||
InternalUserDecryptionOptionsServiceAbstraction,
|
||||
GlobalStateProvider,
|
||||
BillingAccountProfileStateService,
|
||||
KdfConfigServiceAbstraction,
|
||||
],
|
||||
}),
|
||||
safeProvider({
|
||||
@ -543,6 +546,7 @@ const safeProviders: SafeProvider[] = [
|
||||
StateServiceAbstraction,
|
||||
AccountServiceAbstraction,
|
||||
StateProvider,
|
||||
KdfConfigServiceAbstraction,
|
||||
],
|
||||
}),
|
||||
safeProvider({
|
||||
@ -713,7 +717,7 @@ const safeProviders: SafeProvider[] = [
|
||||
CipherServiceAbstraction,
|
||||
CryptoServiceAbstraction,
|
||||
CryptoFunctionServiceAbstraction,
|
||||
StateServiceAbstraction,
|
||||
KdfConfigServiceAbstraction,
|
||||
],
|
||||
}),
|
||||
safeProvider({
|
||||
@ -724,8 +728,8 @@ const safeProviders: SafeProvider[] = [
|
||||
ApiServiceAbstraction,
|
||||
CryptoServiceAbstraction,
|
||||
CryptoFunctionServiceAbstraction,
|
||||
StateServiceAbstraction,
|
||||
CollectionServiceAbstraction,
|
||||
KdfConfigServiceAbstraction,
|
||||
],
|
||||
}),
|
||||
safeProvider({
|
||||
@ -834,6 +838,7 @@ const safeProviders: SafeProvider[] = [
|
||||
LogService,
|
||||
VaultTimeoutSettingsServiceAbstraction,
|
||||
PlatformUtilsServiceAbstraction,
|
||||
KdfConfigServiceAbstraction,
|
||||
],
|
||||
}),
|
||||
safeProvider({
|
||||
@ -985,6 +990,7 @@ const safeProviders: SafeProvider[] = [
|
||||
CryptoServiceAbstraction,
|
||||
VaultTimeoutSettingsServiceAbstraction,
|
||||
LogService,
|
||||
KdfConfigServiceAbstraction,
|
||||
],
|
||||
}),
|
||||
safeProvider({
|
||||
@ -1150,6 +1156,11 @@ const safeProviders: SafeProvider[] = [
|
||||
useClass: ProviderApiService,
|
||||
deps: [ApiServiceAbstraction],
|
||||
}),
|
||||
safeProvider({
|
||||
provide: KdfConfigServiceAbstraction,
|
||||
useClass: KdfConfigService,
|
||||
deps: [StateProvider],
|
||||
}),
|
||||
];
|
||||
|
||||
function encryptServiceFactory(
|
||||
|
@ -2,6 +2,7 @@ import { mock, MockProxy } from "jest-mock-extended";
|
||||
|
||||
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
||||
import { DeviceTrustServiceAbstraction } from "@bitwarden/common/auth/abstractions/device-trust.service.abstraction";
|
||||
import { KdfConfigService } from "@bitwarden/common/auth/abstractions/kdf-config.service";
|
||||
import { TokenService } from "@bitwarden/common/auth/abstractions/token.service";
|
||||
import { TwoFactorService } from "@bitwarden/common/auth/abstractions/two-factor.service";
|
||||
import { IdentityTokenResponse } from "@bitwarden/common/auth/models/response/identity-token.response";
|
||||
@ -44,6 +45,7 @@ describe("AuthRequestLoginStrategy", () => {
|
||||
let userDecryptionOptions: MockProxy<InternalUserDecryptionOptionsServiceAbstraction>;
|
||||
let deviceTrustService: MockProxy<DeviceTrustServiceAbstraction>;
|
||||
let billingAccountProfileStateService: MockProxy<BillingAccountProfileStateService>;
|
||||
let kdfConfigService: MockProxy<KdfConfigService>;
|
||||
|
||||
const mockUserId = Utils.newGuid() as UserId;
|
||||
let accountService: FakeAccountService;
|
||||
@ -77,6 +79,7 @@ describe("AuthRequestLoginStrategy", () => {
|
||||
userDecryptionOptions = mock<InternalUserDecryptionOptionsServiceAbstraction>();
|
||||
deviceTrustService = mock<DeviceTrustServiceAbstraction>();
|
||||
billingAccountProfileStateService = mock<BillingAccountProfileStateService>();
|
||||
kdfConfigService = mock<KdfConfigService>();
|
||||
|
||||
accountService = mockAccountServiceWith(mockUserId);
|
||||
masterPasswordService = new FakeMasterPasswordService();
|
||||
@ -101,6 +104,7 @@ describe("AuthRequestLoginStrategy", () => {
|
||||
userDecryptionOptions,
|
||||
deviceTrustService,
|
||||
billingAccountProfileStateService,
|
||||
kdfConfigService,
|
||||
);
|
||||
|
||||
tokenResponse = identityTokenResponseFactory();
|
||||
|
@ -3,6 +3,7 @@ import { Jsonify } from "type-fest";
|
||||
|
||||
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
||||
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
||||
import { KdfConfigService } from "@bitwarden/common/auth/abstractions/kdf-config.service";
|
||||
import { InternalMasterPasswordServiceAbstraction } from "@bitwarden/common/auth/abstractions/master-password.service.abstraction";
|
||||
import { TokenService } from "@bitwarden/common/auth/abstractions/token.service";
|
||||
import { TwoFactorService } from "@bitwarden/common/auth/abstractions/two-factor.service";
|
||||
@ -63,6 +64,7 @@ export class AuthRequestLoginStrategy extends LoginStrategy {
|
||||
userDecryptionOptionsService: InternalUserDecryptionOptionsServiceAbstraction,
|
||||
private deviceTrustService: DeviceTrustServiceAbstraction,
|
||||
billingAccountProfileStateService: BillingAccountProfileStateService,
|
||||
kdfConfigService: KdfConfigService,
|
||||
) {
|
||||
super(
|
||||
accountService,
|
||||
@ -78,6 +80,7 @@ export class AuthRequestLoginStrategy extends LoginStrategy {
|
||||
twoFactorService,
|
||||
userDecryptionOptionsService,
|
||||
billingAccountProfileStateService,
|
||||
kdfConfigService,
|
||||
);
|
||||
|
||||
this.cache = new BehaviorSubject(data);
|
||||
|
@ -2,6 +2,7 @@ import { mock, MockProxy } from "jest-mock-extended";
|
||||
|
||||
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
||||
import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction";
|
||||
import { KdfConfigService } from "@bitwarden/common/auth/abstractions/kdf-config.service";
|
||||
import { TokenService } from "@bitwarden/common/auth/abstractions/token.service";
|
||||
import { TwoFactorService } from "@bitwarden/common/auth/abstractions/two-factor.service";
|
||||
import { TwoFactorProviderType } from "@bitwarden/common/auth/enums/two-factor-provider-type";
|
||||
@ -117,6 +118,7 @@ describe("LoginStrategy", () => {
|
||||
let policyService: MockProxy<PolicyService>;
|
||||
let passwordStrengthService: MockProxy<PasswordStrengthServiceAbstraction>;
|
||||
let billingAccountProfileStateService: MockProxy<BillingAccountProfileStateService>;
|
||||
let kdfConfigService: MockProxy<KdfConfigService>;
|
||||
|
||||
let passwordLoginStrategy: PasswordLoginStrategy;
|
||||
let credentials: PasswordLoginCredentials;
|
||||
@ -136,6 +138,7 @@ describe("LoginStrategy", () => {
|
||||
stateService = mock<StateService>();
|
||||
twoFactorService = mock<TwoFactorService>();
|
||||
userDecryptionOptionsService = mock<InternalUserDecryptionOptionsServiceAbstraction>();
|
||||
kdfConfigService = mock<KdfConfigService>();
|
||||
policyService = mock<PolicyService>();
|
||||
passwordStrengthService = mock<PasswordStrengthService>();
|
||||
billingAccountProfileStateService = mock<BillingAccountProfileStateService>();
|
||||
@ -162,6 +165,7 @@ describe("LoginStrategy", () => {
|
||||
policyService,
|
||||
loginStrategyService,
|
||||
billingAccountProfileStateService,
|
||||
kdfConfigService,
|
||||
);
|
||||
credentials = new PasswordLoginCredentials(email, masterPassword);
|
||||
});
|
||||
@ -208,8 +212,6 @@ describe("LoginStrategy", () => {
|
||||
userId: userId,
|
||||
name: name,
|
||||
email: email,
|
||||
kdfIterations: kdfIterations,
|
||||
kdfType: kdf,
|
||||
},
|
||||
},
|
||||
keys: new AccountKeys(),
|
||||
@ -404,6 +406,7 @@ describe("LoginStrategy", () => {
|
||||
policyService,
|
||||
loginStrategyService,
|
||||
billingAccountProfileStateService,
|
||||
kdfConfigService,
|
||||
);
|
||||
|
||||
apiService.postIdentityToken.mockResolvedValue(identityTokenResponseFactory());
|
||||
|
@ -2,12 +2,14 @@ import { BehaviorSubject } from "rxjs";
|
||||
|
||||
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
||||
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
||||
import { KdfConfigService } from "@bitwarden/common/auth/abstractions/kdf-config.service";
|
||||
import { InternalMasterPasswordServiceAbstraction } from "@bitwarden/common/auth/abstractions/master-password.service.abstraction";
|
||||
import { TokenService } from "@bitwarden/common/auth/abstractions/token.service";
|
||||
import { TwoFactorService } from "@bitwarden/common/auth/abstractions/two-factor.service";
|
||||
import { TwoFactorProviderType } from "@bitwarden/common/auth/enums/two-factor-provider-type";
|
||||
import { AuthResult } from "@bitwarden/common/auth/models/domain/auth-result";
|
||||
import { ForceSetPasswordReason } from "@bitwarden/common/auth/models/domain/force-set-password-reason";
|
||||
import { Argon2KdfConfig, PBKDF2KdfConfig } from "@bitwarden/common/auth/models/domain/kdf-config";
|
||||
import { DeviceRequest } from "@bitwarden/common/auth/models/request/identity-token/device.request";
|
||||
import { PasswordTokenRequest } from "@bitwarden/common/auth/models/request/identity-token/password-token.request";
|
||||
import { SsoTokenRequest } from "@bitwarden/common/auth/models/request/identity-token/sso-token.request";
|
||||
@ -27,6 +29,7 @@ import { LogService } from "@bitwarden/common/platform/abstractions/log.service"
|
||||
import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service";
|
||||
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
||||
import { StateService } from "@bitwarden/common/platform/abstractions/state.service";
|
||||
import { KdfType } from "@bitwarden/common/platform/enums";
|
||||
import { Account, AccountProfile } from "@bitwarden/common/platform/models/domain/account";
|
||||
import { UserId } from "@bitwarden/common/types/guid";
|
||||
|
||||
@ -72,6 +75,7 @@ export abstract class LoginStrategy {
|
||||
protected twoFactorService: TwoFactorService,
|
||||
protected userDecryptionOptionsService: InternalUserDecryptionOptionsServiceAbstraction,
|
||||
protected billingAccountProfileStateService: BillingAccountProfileStateService,
|
||||
protected KdfConfigService: KdfConfigService,
|
||||
) {}
|
||||
|
||||
abstract exportCache(): CacheData;
|
||||
@ -182,10 +186,6 @@ export abstract class LoginStrategy {
|
||||
userId,
|
||||
name: accountInformation.name,
|
||||
email: accountInformation.email,
|
||||
kdfIterations: tokenResponse.kdfIterations,
|
||||
kdfMemory: tokenResponse.kdfMemory,
|
||||
kdfParallelism: tokenResponse.kdfParallelism,
|
||||
kdfType: tokenResponse.kdf,
|
||||
},
|
||||
},
|
||||
}),
|
||||
@ -195,6 +195,17 @@ export abstract class LoginStrategy {
|
||||
UserDecryptionOptions.fromResponse(tokenResponse),
|
||||
);
|
||||
|
||||
await this.KdfConfigService.setKdfConfig(
|
||||
userId as UserId,
|
||||
tokenResponse.kdf === KdfType.PBKDF2_SHA256
|
||||
? new PBKDF2KdfConfig(tokenResponse.kdfIterations)
|
||||
: new Argon2KdfConfig(
|
||||
tokenResponse.kdfIterations,
|
||||
tokenResponse.kdfMemory,
|
||||
tokenResponse.kdfParallelism,
|
||||
),
|
||||
);
|
||||
|
||||
await this.billingAccountProfileStateService.setHasPremium(accountInformation.premium, false);
|
||||
return userId as UserId;
|
||||
}
|
||||
|
@ -2,6 +2,7 @@ import { mock, MockProxy } from "jest-mock-extended";
|
||||
|
||||
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
||||
import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction";
|
||||
import { KdfConfigService } from "@bitwarden/common/auth/abstractions/kdf-config.service";
|
||||
import { TokenService } from "@bitwarden/common/auth/abstractions/token.service";
|
||||
import { TwoFactorService } from "@bitwarden/common/auth/abstractions/two-factor.service";
|
||||
import { TwoFactorProviderType } from "@bitwarden/common/auth/enums/two-factor-provider-type";
|
||||
@ -71,6 +72,7 @@ describe("PasswordLoginStrategy", () => {
|
||||
let policyService: MockProxy<PolicyService>;
|
||||
let passwordStrengthService: MockProxy<PasswordStrengthServiceAbstraction>;
|
||||
let billingAccountProfileStateService: MockProxy<BillingAccountProfileStateService>;
|
||||
let kdfConfigService: MockProxy<KdfConfigService>;
|
||||
|
||||
let passwordLoginStrategy: PasswordLoginStrategy;
|
||||
let credentials: PasswordLoginCredentials;
|
||||
@ -94,6 +96,7 @@ describe("PasswordLoginStrategy", () => {
|
||||
policyService = mock<PolicyService>();
|
||||
passwordStrengthService = mock<PasswordStrengthService>();
|
||||
billingAccountProfileStateService = mock<BillingAccountProfileStateService>();
|
||||
kdfConfigService = mock<KdfConfigService>();
|
||||
|
||||
appIdService.getAppId.mockResolvedValue(deviceId);
|
||||
tokenService.decodeAccessToken.mockResolvedValue({});
|
||||
@ -127,6 +130,7 @@ describe("PasswordLoginStrategy", () => {
|
||||
policyService,
|
||||
loginStrategyService,
|
||||
billingAccountProfileStateService,
|
||||
kdfConfigService,
|
||||
);
|
||||
credentials = new PasswordLoginCredentials(email, masterPassword);
|
||||
tokenResponse = identityTokenResponseFactory(masterPasswordPolicy);
|
||||
|
@ -5,6 +5,7 @@ import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
||||
import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction";
|
||||
import { MasterPasswordPolicyOptions } from "@bitwarden/common/admin-console/models/domain/master-password-policy-options";
|
||||
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
||||
import { KdfConfigService } from "@bitwarden/common/auth/abstractions/kdf-config.service";
|
||||
import { InternalMasterPasswordServiceAbstraction } from "@bitwarden/common/auth/abstractions/master-password.service.abstraction";
|
||||
import { TokenService } from "@bitwarden/common/auth/abstractions/token.service";
|
||||
import { TwoFactorService } from "@bitwarden/common/auth/abstractions/two-factor.service";
|
||||
@ -89,6 +90,7 @@ export class PasswordLoginStrategy extends LoginStrategy {
|
||||
private policyService: PolicyService,
|
||||
private loginStrategyService: LoginStrategyServiceAbstraction,
|
||||
billingAccountProfileStateService: BillingAccountProfileStateService,
|
||||
kdfConfigService: KdfConfigService,
|
||||
) {
|
||||
super(
|
||||
accountService,
|
||||
@ -104,6 +106,7 @@ export class PasswordLoginStrategy extends LoginStrategy {
|
||||
twoFactorService,
|
||||
userDecryptionOptionsService,
|
||||
billingAccountProfileStateService,
|
||||
kdfConfigService,
|
||||
);
|
||||
|
||||
this.cache = new BehaviorSubject(data);
|
||||
|
@ -2,6 +2,7 @@ import { mock, MockProxy } from "jest-mock-extended";
|
||||
|
||||
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
||||
import { DeviceTrustServiceAbstraction } from "@bitwarden/common/auth/abstractions/device-trust.service.abstraction";
|
||||
import { KdfConfigService } from "@bitwarden/common/auth/abstractions/kdf-config.service";
|
||||
import { KeyConnectorService } from "@bitwarden/common/auth/abstractions/key-connector.service";
|
||||
import { TokenService } from "@bitwarden/common/auth/abstractions/token.service";
|
||||
import { TwoFactorService } from "@bitwarden/common/auth/abstractions/two-factor.service";
|
||||
@ -54,6 +55,7 @@ describe("SsoLoginStrategy", () => {
|
||||
let authRequestService: MockProxy<AuthRequestServiceAbstraction>;
|
||||
let i18nService: MockProxy<I18nService>;
|
||||
let billingAccountProfileStateService: MockProxy<BillingAccountProfileStateService>;
|
||||
let kdfConfigService: MockProxy<KdfConfigService>;
|
||||
|
||||
let ssoLoginStrategy: SsoLoginStrategy;
|
||||
let credentials: SsoLoginCredentials;
|
||||
@ -86,6 +88,7 @@ describe("SsoLoginStrategy", () => {
|
||||
authRequestService = mock<AuthRequestServiceAbstraction>();
|
||||
i18nService = mock<I18nService>();
|
||||
billingAccountProfileStateService = mock<BillingAccountProfileStateService>();
|
||||
kdfConfigService = mock<KdfConfigService>();
|
||||
|
||||
tokenService.getTwoFactorToken.mockResolvedValue(null);
|
||||
appIdService.getAppId.mockResolvedValue(deviceId);
|
||||
@ -110,6 +113,7 @@ describe("SsoLoginStrategy", () => {
|
||||
authRequestService,
|
||||
i18nService,
|
||||
billingAccountProfileStateService,
|
||||
kdfConfigService,
|
||||
);
|
||||
credentials = new SsoLoginCredentials(ssoCode, ssoCodeVerifier, ssoRedirectUrl, ssoOrgId);
|
||||
});
|
||||
|
@ -3,6 +3,7 @@ import { Jsonify } from "type-fest";
|
||||
|
||||
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
||||
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
||||
import { KdfConfigService } from "@bitwarden/common/auth/abstractions/kdf-config.service";
|
||||
import { KeyConnectorService } from "@bitwarden/common/auth/abstractions/key-connector.service";
|
||||
import { InternalMasterPasswordServiceAbstraction } from "@bitwarden/common/auth/abstractions/master-password.service.abstraction";
|
||||
import { TokenService } from "@bitwarden/common/auth/abstractions/token.service";
|
||||
@ -98,6 +99,7 @@ export class SsoLoginStrategy extends LoginStrategy {
|
||||
private authRequestService: AuthRequestServiceAbstraction,
|
||||
private i18nService: I18nService,
|
||||
billingAccountProfileStateService: BillingAccountProfileStateService,
|
||||
kdfConfigService: KdfConfigService,
|
||||
) {
|
||||
super(
|
||||
accountService,
|
||||
@ -113,6 +115,7 @@ export class SsoLoginStrategy extends LoginStrategy {
|
||||
twoFactorService,
|
||||
userDecryptionOptionsService,
|
||||
billingAccountProfileStateService,
|
||||
kdfConfigService,
|
||||
);
|
||||
|
||||
this.cache = new BehaviorSubject(data);
|
||||
|
@ -2,6 +2,7 @@ import { mock, MockProxy } from "jest-mock-extended";
|
||||
import { BehaviorSubject } from "rxjs";
|
||||
|
||||
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
||||
import { KdfConfigService } from "@bitwarden/common/auth/abstractions/kdf-config.service";
|
||||
import { KeyConnectorService } from "@bitwarden/common/auth/abstractions/key-connector.service";
|
||||
import { TokenService } from "@bitwarden/common/auth/abstractions/token.service";
|
||||
import { TwoFactorService } from "@bitwarden/common/auth/abstractions/two-factor.service";
|
||||
@ -49,6 +50,7 @@ describe("UserApiLoginStrategy", () => {
|
||||
let keyConnectorService: MockProxy<KeyConnectorService>;
|
||||
let environmentService: MockProxy<EnvironmentService>;
|
||||
let billingAccountProfileStateService: MockProxy<BillingAccountProfileStateService>;
|
||||
let kdfConfigService: MockProxy<KdfConfigService>;
|
||||
|
||||
let apiLogInStrategy: UserApiLoginStrategy;
|
||||
let credentials: UserApiLoginCredentials;
|
||||
@ -76,6 +78,7 @@ describe("UserApiLoginStrategy", () => {
|
||||
keyConnectorService = mock<KeyConnectorService>();
|
||||
environmentService = mock<EnvironmentService>();
|
||||
billingAccountProfileStateService = mock<BillingAccountProfileStateService>();
|
||||
kdfConfigService = mock<KdfConfigService>();
|
||||
|
||||
appIdService.getAppId.mockResolvedValue(deviceId);
|
||||
tokenService.getTwoFactorToken.mockResolvedValue(null);
|
||||
@ -98,6 +101,7 @@ describe("UserApiLoginStrategy", () => {
|
||||
environmentService,
|
||||
keyConnectorService,
|
||||
billingAccountProfileStateService,
|
||||
kdfConfigService,
|
||||
);
|
||||
|
||||
credentials = new UserApiLoginCredentials(apiClientId, apiClientSecret);
|
||||
|
@ -3,6 +3,7 @@ import { Jsonify } from "type-fest";
|
||||
|
||||
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
||||
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
||||
import { KdfConfigService } from "@bitwarden/common/auth/abstractions/kdf-config.service";
|
||||
import { KeyConnectorService } from "@bitwarden/common/auth/abstractions/key-connector.service";
|
||||
import { InternalMasterPasswordServiceAbstraction } from "@bitwarden/common/auth/abstractions/master-password.service.abstraction";
|
||||
import { TokenService } from "@bitwarden/common/auth/abstractions/token.service";
|
||||
@ -57,6 +58,7 @@ export class UserApiLoginStrategy extends LoginStrategy {
|
||||
private environmentService: EnvironmentService,
|
||||
private keyConnectorService: KeyConnectorService,
|
||||
billingAccountProfileStateService: BillingAccountProfileStateService,
|
||||
protected kdfConfigService: KdfConfigService,
|
||||
) {
|
||||
super(
|
||||
accountService,
|
||||
@ -72,6 +74,7 @@ export class UserApiLoginStrategy extends LoginStrategy {
|
||||
twoFactorService,
|
||||
userDecryptionOptionsService,
|
||||
billingAccountProfileStateService,
|
||||
kdfConfigService,
|
||||
);
|
||||
this.cache = new BehaviorSubject(data);
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
import { mock, MockProxy } from "jest-mock-extended";
|
||||
|
||||
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
||||
import { KdfConfigService } from "@bitwarden/common/auth/abstractions/kdf-config.service";
|
||||
import { TokenService } from "@bitwarden/common/auth/abstractions/token.service";
|
||||
import { TwoFactorService } from "@bitwarden/common/auth/abstractions/two-factor.service";
|
||||
import { AuthResult } from "@bitwarden/common/auth/models/domain/auth-result";
|
||||
@ -42,6 +43,7 @@ describe("WebAuthnLoginStrategy", () => {
|
||||
let twoFactorService!: MockProxy<TwoFactorService>;
|
||||
let userDecryptionOptionsService: MockProxy<InternalUserDecryptionOptionsServiceAbstraction>;
|
||||
let billingAccountProfileStateService: MockProxy<BillingAccountProfileStateService>;
|
||||
let kdfConfigService: MockProxy<KdfConfigService>;
|
||||
|
||||
let webAuthnLoginStrategy!: WebAuthnLoginStrategy;
|
||||
|
||||
@ -81,6 +83,7 @@ describe("WebAuthnLoginStrategy", () => {
|
||||
twoFactorService = mock<TwoFactorService>();
|
||||
userDecryptionOptionsService = mock<InternalUserDecryptionOptionsServiceAbstraction>();
|
||||
billingAccountProfileStateService = mock<BillingAccountProfileStateService>();
|
||||
kdfConfigService = mock<KdfConfigService>();
|
||||
|
||||
tokenService.getTwoFactorToken.mockResolvedValue(null);
|
||||
appIdService.getAppId.mockResolvedValue(deviceId);
|
||||
@ -101,6 +104,7 @@ describe("WebAuthnLoginStrategy", () => {
|
||||
twoFactorService,
|
||||
userDecryptionOptionsService,
|
||||
billingAccountProfileStateService,
|
||||
kdfConfigService,
|
||||
);
|
||||
|
||||
// Create credentials
|
||||
|
@ -3,6 +3,7 @@ import { Jsonify } from "type-fest";
|
||||
|
||||
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
||||
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
||||
import { KdfConfigService } from "@bitwarden/common/auth/abstractions/kdf-config.service";
|
||||
import { InternalMasterPasswordServiceAbstraction } from "@bitwarden/common/auth/abstractions/master-password.service.abstraction";
|
||||
import { TokenService } from "@bitwarden/common/auth/abstractions/token.service";
|
||||
import { TwoFactorService } from "@bitwarden/common/auth/abstractions/two-factor.service";
|
||||
@ -57,6 +58,7 @@ export class WebAuthnLoginStrategy extends LoginStrategy {
|
||||
twoFactorService: TwoFactorService,
|
||||
userDecryptionOptionsService: InternalUserDecryptionOptionsServiceAbstraction,
|
||||
billingAccountProfileStateService: BillingAccountProfileStateService,
|
||||
kdfConfigService: KdfConfigService,
|
||||
) {
|
||||
super(
|
||||
accountService,
|
||||
@ -72,6 +74,7 @@ export class WebAuthnLoginStrategy extends LoginStrategy {
|
||||
twoFactorService,
|
||||
userDecryptionOptionsService,
|
||||
billingAccountProfileStateService,
|
||||
kdfConfigService,
|
||||
);
|
||||
|
||||
this.cache = new BehaviorSubject(data);
|
||||
|
@ -3,6 +3,7 @@ import { MockProxy, mock } from "jest-mock-extended";
|
||||
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
||||
import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction";
|
||||
import { DeviceTrustServiceAbstraction } from "@bitwarden/common/auth/abstractions/device-trust.service.abstraction";
|
||||
import { KdfConfigService } from "@bitwarden/common/auth/abstractions/kdf-config.service";
|
||||
import { KeyConnectorService } from "@bitwarden/common/auth/abstractions/key-connector.service";
|
||||
import { TokenService } from "@bitwarden/common/auth/abstractions/token.service";
|
||||
import { TwoFactorService } from "@bitwarden/common/auth/abstractions/two-factor.service";
|
||||
@ -66,6 +67,7 @@ describe("LoginStrategyService", () => {
|
||||
let authRequestService: MockProxy<AuthRequestServiceAbstraction>;
|
||||
let userDecryptionOptionsService: MockProxy<InternalUserDecryptionOptionsServiceAbstraction>;
|
||||
let billingAccountProfileStateService: MockProxy<BillingAccountProfileStateService>;
|
||||
let kdfConfigService: MockProxy<KdfConfigService>;
|
||||
|
||||
let stateProvider: FakeGlobalStateProvider;
|
||||
let loginStrategyCacheExpirationState: FakeGlobalState<Date | null>;
|
||||
@ -95,6 +97,7 @@ describe("LoginStrategyService", () => {
|
||||
userDecryptionOptionsService = mock<UserDecryptionOptionsService>();
|
||||
billingAccountProfileStateService = mock<BillingAccountProfileStateService>();
|
||||
stateProvider = new FakeGlobalStateProvider();
|
||||
kdfConfigService = mock<KdfConfigService>();
|
||||
|
||||
sut = new LoginStrategyService(
|
||||
accountService,
|
||||
@ -119,6 +122,7 @@ describe("LoginStrategyService", () => {
|
||||
userDecryptionOptionsService,
|
||||
stateProvider,
|
||||
billingAccountProfileStateService,
|
||||
kdfConfigService,
|
||||
);
|
||||
|
||||
loginStrategyCacheExpirationState = stateProvider.getFake(CACHE_EXPIRATION_KEY);
|
||||
|
@ -10,13 +10,18 @@ import {
|
||||
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
||||
import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction";
|
||||
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
||||
import { KdfConfigService } from "@bitwarden/common/auth/abstractions/kdf-config.service";
|
||||
import { KeyConnectorService } from "@bitwarden/common/auth/abstractions/key-connector.service";
|
||||
import { InternalMasterPasswordServiceAbstraction } from "@bitwarden/common/auth/abstractions/master-password.service.abstraction";
|
||||
import { TokenService } from "@bitwarden/common/auth/abstractions/token.service";
|
||||
import { TwoFactorService } from "@bitwarden/common/auth/abstractions/two-factor.service";
|
||||
import { AuthenticationType } from "@bitwarden/common/auth/enums/authentication-type";
|
||||
import { AuthResult } from "@bitwarden/common/auth/models/domain/auth-result";
|
||||
import { KdfConfig } from "@bitwarden/common/auth/models/domain/kdf-config";
|
||||
import {
|
||||
Argon2KdfConfig,
|
||||
KdfConfig,
|
||||
PBKDF2KdfConfig,
|
||||
} from "@bitwarden/common/auth/models/domain/kdf-config";
|
||||
import { TokenTwoFactorRequest } from "@bitwarden/common/auth/models/request/identity-token/token-two-factor.request";
|
||||
import { PasswordlessAuthRequest } from "@bitwarden/common/auth/models/request/passwordless-auth.request";
|
||||
import { AuthRequestResponse } from "@bitwarden/common/auth/models/response/auth-request.response";
|
||||
@ -32,7 +37,7 @@ import { LogService } from "@bitwarden/common/platform/abstractions/log.service"
|
||||
import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service";
|
||||
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
||||
import { StateService } from "@bitwarden/common/platform/abstractions/state.service";
|
||||
import { KdfType } from "@bitwarden/common/platform/enums";
|
||||
import { KdfType } from "@bitwarden/common/platform/enums/kdf-type.enum";
|
||||
import { Utils } from "@bitwarden/common/platform/misc/utils";
|
||||
import { GlobalState, GlobalStateProvider } from "@bitwarden/common/platform/state";
|
||||
import { DeviceTrustServiceAbstraction } from "@bitwarden/common/src/auth/abstractions/device-trust.service.abstraction";
|
||||
@ -105,6 +110,7 @@ export class LoginStrategyService implements LoginStrategyServiceAbstraction {
|
||||
protected userDecryptionOptionsService: InternalUserDecryptionOptionsServiceAbstraction,
|
||||
protected stateProvider: GlobalStateProvider,
|
||||
protected billingAccountProfileStateService: BillingAccountProfileStateService,
|
||||
protected kdfConfigService: KdfConfigService,
|
||||
) {
|
||||
this.currentAuthnTypeState = this.stateProvider.get(CURRENT_LOGIN_STRATEGY_KEY);
|
||||
this.loginStrategyCacheState = this.stateProvider.get(CACHE_KEY);
|
||||
@ -233,24 +239,25 @@ export class LoginStrategyService implements LoginStrategyServiceAbstraction {
|
||||
|
||||
async makePreloginKey(masterPassword: string, email: string): Promise<MasterKey> {
|
||||
email = email.trim().toLowerCase();
|
||||
let kdf: KdfType = null;
|
||||
let kdfConfig: KdfConfig = null;
|
||||
try {
|
||||
const preloginResponse = await this.apiService.postPrelogin(new PreloginRequest(email));
|
||||
if (preloginResponse != null) {
|
||||
kdf = preloginResponse.kdf;
|
||||
kdfConfig = new KdfConfig(
|
||||
preloginResponse.kdfIterations,
|
||||
preloginResponse.kdfMemory,
|
||||
preloginResponse.kdfParallelism,
|
||||
);
|
||||
kdfConfig =
|
||||
preloginResponse.kdf === KdfType.PBKDF2_SHA256
|
||||
? new PBKDF2KdfConfig(preloginResponse.kdfIterations)
|
||||
: new Argon2KdfConfig(
|
||||
preloginResponse.kdfIterations,
|
||||
preloginResponse.kdfMemory,
|
||||
preloginResponse.kdfParallelism,
|
||||
);
|
||||
}
|
||||
} catch (e) {
|
||||
if (e == null || e.statusCode !== 404) {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
return await this.cryptoService.makeMasterKey(masterPassword, email, kdf, kdfConfig);
|
||||
return await this.cryptoService.makeMasterKey(masterPassword, email, kdfConfig);
|
||||
}
|
||||
|
||||
// TODO: move to auth request service
|
||||
@ -354,6 +361,7 @@ export class LoginStrategyService implements LoginStrategyServiceAbstraction {
|
||||
this.policyService,
|
||||
this,
|
||||
this.billingAccountProfileStateService,
|
||||
this.kdfConfigService,
|
||||
);
|
||||
case AuthenticationType.Sso:
|
||||
return new SsoLoginStrategy(
|
||||
@ -375,6 +383,7 @@ export class LoginStrategyService implements LoginStrategyServiceAbstraction {
|
||||
this.authRequestService,
|
||||
this.i18nService,
|
||||
this.billingAccountProfileStateService,
|
||||
this.kdfConfigService,
|
||||
);
|
||||
case AuthenticationType.UserApiKey:
|
||||
return new UserApiLoginStrategy(
|
||||
@ -394,6 +403,7 @@ export class LoginStrategyService implements LoginStrategyServiceAbstraction {
|
||||
this.environmentService,
|
||||
this.keyConnectorService,
|
||||
this.billingAccountProfileStateService,
|
||||
this.kdfConfigService,
|
||||
);
|
||||
case AuthenticationType.AuthRequest:
|
||||
return new AuthRequestLoginStrategy(
|
||||
@ -412,6 +422,7 @@ export class LoginStrategyService implements LoginStrategyServiceAbstraction {
|
||||
this.userDecryptionOptionsService,
|
||||
this.deviceTrustService,
|
||||
this.billingAccountProfileStateService,
|
||||
this.kdfConfigService,
|
||||
);
|
||||
case AuthenticationType.WebAuthn:
|
||||
return new WebAuthnLoginStrategy(
|
||||
@ -429,6 +440,7 @@ export class LoginStrategyService implements LoginStrategyServiceAbstraction {
|
||||
this.twoFactorService,
|
||||
this.userDecryptionOptionsService,
|
||||
this.billingAccountProfileStateService,
|
||||
this.kdfConfigService,
|
||||
);
|
||||
}
|
||||
}),
|
||||
|
@ -1,9 +1,9 @@
|
||||
import { VaultTimeoutSettingsService } from "@bitwarden/common/abstractions/vault-timeout/vault-timeout-settings.service";
|
||||
import { KdfConfigService } from "@bitwarden/common/auth/abstractions/kdf-config.service";
|
||||
import { KdfConfig } from "@bitwarden/common/auth/models/domain/kdf-config";
|
||||
import { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.service";
|
||||
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
|
||||
import { StateService } from "@bitwarden/common/platform/abstractions/state.service";
|
||||
import { KdfType } from "@bitwarden/common/platform/enums";
|
||||
import { EncString } from "@bitwarden/common/platform/models/domain/enc-string";
|
||||
import { PinLockType } from "@bitwarden/common/services/vault-timeout/vault-timeout-settings.service";
|
||||
import { UserKey } from "@bitwarden/common/types/key";
|
||||
@ -16,6 +16,7 @@ export class PinCryptoService implements PinCryptoServiceAbstraction {
|
||||
private cryptoService: CryptoService,
|
||||
private vaultTimeoutSettingsService: VaultTimeoutSettingsService,
|
||||
private logService: LogService,
|
||||
private kdfConfigService: KdfConfigService,
|
||||
) {}
|
||||
async decryptUserKeyWithPin(pin: string): Promise<UserKey | null> {
|
||||
try {
|
||||
@ -24,8 +25,7 @@ export class PinCryptoService implements PinCryptoServiceAbstraction {
|
||||
const { pinKeyEncryptedUserKey, oldPinKeyEncryptedMasterKey } =
|
||||
await this.getPinKeyEncryptedKeys(pinLockType);
|
||||
|
||||
const kdf: KdfType = await this.stateService.getKdfType();
|
||||
const kdfConfig: KdfConfig = await this.stateService.getKdfConfig();
|
||||
const kdfConfig: KdfConfig = await this.kdfConfigService.getKdfConfig();
|
||||
let userKey: UserKey;
|
||||
const email = await this.stateService.getEmail();
|
||||
if (oldPinKeyEncryptedMasterKey) {
|
||||
@ -33,7 +33,6 @@ export class PinCryptoService implements PinCryptoServiceAbstraction {
|
||||
pinLockType === "TRANSIENT",
|
||||
pin,
|
||||
email,
|
||||
kdf,
|
||||
kdfConfig,
|
||||
oldPinKeyEncryptedMasterKey,
|
||||
);
|
||||
@ -41,7 +40,6 @@ export class PinCryptoService implements PinCryptoServiceAbstraction {
|
||||
userKey = await this.cryptoService.decryptUserKeyWithPin(
|
||||
pin,
|
||||
email,
|
||||
kdf,
|
||||
kdfConfig,
|
||||
pinKeyEncryptedUserKey,
|
||||
);
|
||||
|
@ -1,9 +1,10 @@
|
||||
import { mock } from "jest-mock-extended";
|
||||
|
||||
import { KdfConfig } from "@bitwarden/common/auth/models/domain/kdf-config";
|
||||
import { KdfConfigService } from "@bitwarden/common/auth/abstractions/kdf-config.service";
|
||||
import { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.service";
|
||||
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
|
||||
import { StateService } from "@bitwarden/common/platform/abstractions/state.service";
|
||||
import { DEFAULT_KDF_CONFIG } from "@bitwarden/common/platform/enums";
|
||||
import { EncString } from "@bitwarden/common/platform/models/domain/enc-string";
|
||||
import { SymmetricCryptoKey } from "@bitwarden/common/platform/models/domain/symmetric-crypto-key";
|
||||
import {
|
||||
@ -13,6 +14,7 @@ import {
|
||||
import { UserKey } from "@bitwarden/common/types/key";
|
||||
|
||||
import { PinCryptoService } from "./pin-crypto.service.implementation";
|
||||
|
||||
describe("PinCryptoService", () => {
|
||||
let pinCryptoService: PinCryptoService;
|
||||
|
||||
@ -20,6 +22,7 @@ describe("PinCryptoService", () => {
|
||||
const cryptoService = mock<CryptoService>();
|
||||
const vaultTimeoutSettingsService = mock<VaultTimeoutSettingsService>();
|
||||
const logService = mock<LogService>();
|
||||
const kdfConfigService = mock<KdfConfigService>();
|
||||
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
@ -29,6 +32,7 @@ describe("PinCryptoService", () => {
|
||||
cryptoService,
|
||||
vaultTimeoutSettingsService,
|
||||
logService,
|
||||
kdfConfigService,
|
||||
);
|
||||
});
|
||||
|
||||
@ -39,7 +43,6 @@ describe("PinCryptoService", () => {
|
||||
describe("decryptUserKeyWithPin(...)", () => {
|
||||
const mockPin = "1234";
|
||||
const mockProtectedPin = "protectedPin";
|
||||
const DEFAULT_PBKDF2_ITERATIONS = 600000;
|
||||
const mockUserEmail = "user@example.com";
|
||||
const mockUserKey = new SymmetricCryptoKey(randomBytes(32)) as UserKey;
|
||||
|
||||
@ -49,7 +52,7 @@ describe("PinCryptoService", () => {
|
||||
) {
|
||||
vaultTimeoutSettingsService.isPinLockSet.mockResolvedValue(pinLockType);
|
||||
|
||||
stateService.getKdfConfig.mockResolvedValue(new KdfConfig(DEFAULT_PBKDF2_ITERATIONS));
|
||||
kdfConfigService.getKdfConfig.mockResolvedValue(DEFAULT_KDF_CONFIG);
|
||||
stateService.getEmail.mockResolvedValue(mockUserEmail);
|
||||
|
||||
if (migrationStatus === "PRE") {
|
||||
|
7
libs/common/src/auth/abstractions/kdf-config.service.ts
Normal file
7
libs/common/src/auth/abstractions/kdf-config.service.ts
Normal file
@ -0,0 +1,7 @@
|
||||
import { UserId } from "../../types/guid";
|
||||
import { KdfConfig } from "../models/domain/kdf-config";
|
||||
|
||||
export abstract class KdfConfigService {
|
||||
setKdfConfig: (userId: UserId, KdfConfig: KdfConfig) => Promise<void>;
|
||||
getKdfConfig: () => Promise<KdfConfig>;
|
||||
}
|
@ -1,11 +1,86 @@
|
||||
export class KdfConfig {
|
||||
iterations: number;
|
||||
memory?: number;
|
||||
parallelism?: number;
|
||||
import { Jsonify } from "type-fest";
|
||||
|
||||
constructor(iterations: number, memory?: number, parallelism?: number) {
|
||||
this.iterations = iterations;
|
||||
this.memory = memory;
|
||||
this.parallelism = parallelism;
|
||||
import {
|
||||
ARGON2_ITERATIONS,
|
||||
ARGON2_MEMORY,
|
||||
ARGON2_PARALLELISM,
|
||||
KdfType,
|
||||
PBKDF2_ITERATIONS,
|
||||
} from "../../../platform/enums/kdf-type.enum";
|
||||
|
||||
/**
|
||||
* Represents a type safe KDF configuration.
|
||||
*/
|
||||
export type KdfConfig = PBKDF2KdfConfig | Argon2KdfConfig;
|
||||
|
||||
/**
|
||||
* Password-Based Key Derivation Function 2 (PBKDF2) KDF configuration.
|
||||
*/
|
||||
export class PBKDF2KdfConfig {
|
||||
kdfType: KdfType.PBKDF2_SHA256 = KdfType.PBKDF2_SHA256;
|
||||
iterations: number;
|
||||
|
||||
constructor(iterations?: number) {
|
||||
this.iterations = iterations ?? PBKDF2_ITERATIONS.defaultValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates the PBKDF2 KDF configuration.
|
||||
* A Valid PBKDF2 KDF configuration has KDF iterations between the 600_000 and 2_000_000.
|
||||
*/
|
||||
validateKdfConfig(): void {
|
||||
if (!PBKDF2_ITERATIONS.inRange(this.iterations)) {
|
||||
throw new Error(
|
||||
`PBKDF2 iterations must be between ${PBKDF2_ITERATIONS.min} and ${PBKDF2_ITERATIONS.max}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
static fromJSON(json: Jsonify<PBKDF2KdfConfig>): PBKDF2KdfConfig {
|
||||
return new PBKDF2KdfConfig(json.iterations);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Argon2 KDF configuration.
|
||||
*/
|
||||
export class Argon2KdfConfig {
|
||||
kdfType: KdfType.Argon2id = KdfType.Argon2id;
|
||||
iterations: number;
|
||||
memory: number;
|
||||
parallelism: number;
|
||||
|
||||
constructor(iterations?: number, memory?: number, parallelism?: number) {
|
||||
this.iterations = iterations ?? ARGON2_ITERATIONS.defaultValue;
|
||||
this.memory = memory ?? ARGON2_MEMORY.defaultValue;
|
||||
this.parallelism = parallelism ?? ARGON2_PARALLELISM.defaultValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates the Argon2 KDF configuration.
|
||||
* A Valid Argon2 KDF configuration has iterations between 2 and 10, memory between 16mb and 1024mb, and parallelism between 1 and 16.
|
||||
*/
|
||||
validateKdfConfig(): void {
|
||||
if (!ARGON2_ITERATIONS.inRange(this.iterations)) {
|
||||
throw new Error(
|
||||
`Argon2 iterations must be between ${ARGON2_ITERATIONS.min} and ${ARGON2_ITERATIONS.max}`,
|
||||
);
|
||||
}
|
||||
|
||||
if (!ARGON2_MEMORY.inRange(this.memory)) {
|
||||
throw new Error(
|
||||
`Argon2 memory must be between ${ARGON2_MEMORY.min}mb and ${ARGON2_MEMORY.max}mb`,
|
||||
);
|
||||
}
|
||||
|
||||
if (!ARGON2_PARALLELISM.inRange(this.parallelism)) {
|
||||
throw new Error(
|
||||
`Argon2 parallelism must be between ${ARGON2_PARALLELISM.min} and ${ARGON2_PARALLELISM.max}.`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
static fromJSON(json: Jsonify<Argon2KdfConfig>): Argon2KdfConfig {
|
||||
return new Argon2KdfConfig(json.iterations, json.memory, json.parallelism);
|
||||
}
|
||||
}
|
||||
|
@ -11,18 +11,14 @@ export class SetKeyConnectorKeyRequest {
|
||||
kdfParallelism?: number;
|
||||
orgIdentifier: string;
|
||||
|
||||
constructor(
|
||||
key: string,
|
||||
kdf: KdfType,
|
||||
kdfConfig: KdfConfig,
|
||||
orgIdentifier: string,
|
||||
keys: KeysRequest,
|
||||
) {
|
||||
constructor(key: string, kdfConfig: KdfConfig, orgIdentifier: string, keys: KeysRequest) {
|
||||
this.key = key;
|
||||
this.kdf = kdf;
|
||||
this.kdf = kdfConfig.kdfType;
|
||||
this.kdfIterations = kdfConfig.iterations;
|
||||
this.kdfMemory = kdfConfig.memory;
|
||||
this.kdfParallelism = kdfConfig.parallelism;
|
||||
if (kdfConfig.kdfType === KdfType.Argon2id) {
|
||||
this.kdfMemory = kdfConfig.memory;
|
||||
this.kdfParallelism = kdfConfig.parallelism;
|
||||
}
|
||||
this.orgIdentifier = orgIdentifier;
|
||||
this.keys = keys;
|
||||
}
|
||||
|
104
libs/common/src/auth/services/kdf-config.service.spec.ts
Normal file
104
libs/common/src/auth/services/kdf-config.service.spec.ts
Normal file
@ -0,0 +1,104 @@
|
||||
import { FakeAccountService, FakeStateProvider, mockAccountServiceWith } from "../../../spec";
|
||||
import {
|
||||
ARGON2_ITERATIONS,
|
||||
ARGON2_MEMORY,
|
||||
ARGON2_PARALLELISM,
|
||||
PBKDF2_ITERATIONS,
|
||||
} from "../../platform/enums/kdf-type.enum";
|
||||
import { Utils } from "../../platform/misc/utils";
|
||||
import { UserId } from "../../types/guid";
|
||||
import { Argon2KdfConfig, PBKDF2KdfConfig } from "../models/domain/kdf-config";
|
||||
|
||||
import { KdfConfigService } from "./kdf-config.service";
|
||||
|
||||
describe("KdfConfigService", () => {
|
||||
let sutKdfConfigService: KdfConfigService;
|
||||
|
||||
let fakeStateProvider: FakeStateProvider;
|
||||
let fakeAccountService: FakeAccountService;
|
||||
const mockUserId = Utils.newGuid() as UserId;
|
||||
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
|
||||
fakeAccountService = mockAccountServiceWith(mockUserId);
|
||||
fakeStateProvider = new FakeStateProvider(fakeAccountService);
|
||||
sutKdfConfigService = new KdfConfigService(fakeStateProvider);
|
||||
});
|
||||
|
||||
it("setKdfConfig(): should set the KDF config", async () => {
|
||||
const kdfConfig: PBKDF2KdfConfig = new PBKDF2KdfConfig(600_000);
|
||||
await sutKdfConfigService.setKdfConfig(mockUserId, kdfConfig);
|
||||
await expect(sutKdfConfigService.getKdfConfig()).resolves.toEqual(kdfConfig);
|
||||
});
|
||||
|
||||
it("setKdfConfig(): should get the KDF config", async () => {
|
||||
const kdfConfig: Argon2KdfConfig = new Argon2KdfConfig(3, 64, 4);
|
||||
await sutKdfConfigService.setKdfConfig(mockUserId, kdfConfig);
|
||||
await expect(sutKdfConfigService.getKdfConfig()).resolves.toEqual(kdfConfig);
|
||||
});
|
||||
|
||||
it("setKdfConfig(): should throw error KDF cannot be null", async () => {
|
||||
const kdfConfig: Argon2KdfConfig = null;
|
||||
try {
|
||||
await sutKdfConfigService.setKdfConfig(mockUserId, kdfConfig);
|
||||
} catch (e) {
|
||||
expect(e).toEqual(new Error("kdfConfig cannot be null"));
|
||||
}
|
||||
});
|
||||
|
||||
it("setKdfConfig(): should throw error userId cannot be null", async () => {
|
||||
const kdfConfig: Argon2KdfConfig = new Argon2KdfConfig(3, 64, 4);
|
||||
try {
|
||||
await sutKdfConfigService.setKdfConfig(null, kdfConfig);
|
||||
} catch (e) {
|
||||
expect(e).toEqual(new Error("userId cannot be null"));
|
||||
}
|
||||
});
|
||||
|
||||
it("getKdfConfig(): should throw error KdfConfig for active user account state is null", async () => {
|
||||
try {
|
||||
await sutKdfConfigService.getKdfConfig();
|
||||
} catch (e) {
|
||||
expect(e).toEqual(new Error("KdfConfig for active user account state is null"));
|
||||
}
|
||||
});
|
||||
|
||||
it("validateKdfConfig(): should validate the PBKDF2 KDF config", () => {
|
||||
const kdfConfig: PBKDF2KdfConfig = new PBKDF2KdfConfig(600_000);
|
||||
expect(() => kdfConfig.validateKdfConfig()).not.toThrow();
|
||||
});
|
||||
|
||||
it("validateKdfConfig(): should validate the Argon2id KDF config", () => {
|
||||
const kdfConfig: Argon2KdfConfig = new Argon2KdfConfig(3, 64, 4);
|
||||
expect(() => kdfConfig.validateKdfConfig()).not.toThrow();
|
||||
});
|
||||
|
||||
it("validateKdfConfig(): should throw an error for invalid PBKDF2 iterations", () => {
|
||||
const kdfConfig: PBKDF2KdfConfig = new PBKDF2KdfConfig(100);
|
||||
expect(() => kdfConfig.validateKdfConfig()).toThrow(
|
||||
`PBKDF2 iterations must be between ${PBKDF2_ITERATIONS.min} and ${PBKDF2_ITERATIONS.max}`,
|
||||
);
|
||||
});
|
||||
|
||||
it("validateKdfConfig(): should throw an error for invalid Argon2 iterations", () => {
|
||||
const kdfConfig: Argon2KdfConfig = new Argon2KdfConfig(11, 64, 4);
|
||||
expect(() => kdfConfig.validateKdfConfig()).toThrow(
|
||||
`Argon2 iterations must be between ${ARGON2_ITERATIONS.min} and ${ARGON2_ITERATIONS.max}`,
|
||||
);
|
||||
});
|
||||
|
||||
it("validateKdfConfig(): should throw an error for invalid Argon2 memory", () => {
|
||||
const kdfConfig: Argon2KdfConfig = new Argon2KdfConfig(3, 1025, 4);
|
||||
expect(() => kdfConfig.validateKdfConfig()).toThrow(
|
||||
`Argon2 memory must be between ${ARGON2_MEMORY.min}mb and ${ARGON2_MEMORY.max}mb`,
|
||||
);
|
||||
});
|
||||
|
||||
it("validateKdfConfig(): should throw an error for invalid Argon2 parallelism", () => {
|
||||
const kdfConfig: Argon2KdfConfig = new Argon2KdfConfig(3, 64, 17);
|
||||
expect(() => kdfConfig.validateKdfConfig()).toThrow(
|
||||
`Argon2 parallelism must be between ${ARGON2_PARALLELISM.min} and ${ARGON2_PARALLELISM.max}`,
|
||||
);
|
||||
});
|
||||
});
|
41
libs/common/src/auth/services/kdf-config.service.ts
Normal file
41
libs/common/src/auth/services/kdf-config.service.ts
Normal file
@ -0,0 +1,41 @@
|
||||
import { firstValueFrom } from "rxjs";
|
||||
|
||||
import { KdfType } from "../../platform/enums/kdf-type.enum";
|
||||
import { KDF_CONFIG_DISK, StateProvider, UserKeyDefinition } from "../../platform/state";
|
||||
import { UserId } from "../../types/guid";
|
||||
import { KdfConfigService as KdfConfigServiceAbstraction } from "../abstractions/kdf-config.service";
|
||||
import { Argon2KdfConfig, KdfConfig, PBKDF2KdfConfig } from "../models/domain/kdf-config";
|
||||
|
||||
export const KDF_CONFIG = new UserKeyDefinition<KdfConfig>(KDF_CONFIG_DISK, "kdfConfig", {
|
||||
deserializer: (kdfConfig: KdfConfig) => {
|
||||
if (kdfConfig == null) {
|
||||
return null;
|
||||
}
|
||||
return kdfConfig.kdfType === KdfType.PBKDF2_SHA256
|
||||
? PBKDF2KdfConfig.fromJSON(kdfConfig)
|
||||
: Argon2KdfConfig.fromJSON(kdfConfig);
|
||||
},
|
||||
clearOn: ["logout"],
|
||||
});
|
||||
|
||||
export class KdfConfigService implements KdfConfigServiceAbstraction {
|
||||
constructor(private stateProvider: StateProvider) {}
|
||||
async setKdfConfig(userId: UserId, kdfConfig: KdfConfig) {
|
||||
if (!userId) {
|
||||
throw new Error("userId cannot be null");
|
||||
}
|
||||
if (kdfConfig === null) {
|
||||
throw new Error("kdfConfig cannot be null");
|
||||
}
|
||||
await this.stateProvider.setUserState(KDF_CONFIG, kdfConfig, userId);
|
||||
}
|
||||
|
||||
async getKdfConfig(): Promise<KdfConfig> {
|
||||
const userId = await firstValueFrom(this.stateProvider.activeUserId$);
|
||||
const state = await firstValueFrom(this.stateProvider.getUser(userId, KDF_CONFIG).state$);
|
||||
if (state === null) {
|
||||
throw new Error("KdfConfig for active user account state is null");
|
||||
}
|
||||
return state;
|
||||
}
|
||||
}
|
@ -7,6 +7,7 @@ import { KeysRequest } from "../../models/request/keys.request";
|
||||
import { CryptoService } from "../../platform/abstractions/crypto.service";
|
||||
import { KeyGenerationService } from "../../platform/abstractions/key-generation.service";
|
||||
import { LogService } from "../../platform/abstractions/log.service";
|
||||
import { KdfType } from "../../platform/enums/kdf-type.enum";
|
||||
import { Utils } from "../../platform/misc/utils";
|
||||
import { SymmetricCryptoKey } from "../../platform/models/domain/symmetric-crypto-key";
|
||||
import {
|
||||
@ -20,7 +21,7 @@ import { AccountService } from "../abstractions/account.service";
|
||||
import { KeyConnectorService as KeyConnectorServiceAbstraction } from "../abstractions/key-connector.service";
|
||||
import { InternalMasterPasswordServiceAbstraction } from "../abstractions/master-password.service.abstraction";
|
||||
import { TokenService } from "../abstractions/token.service";
|
||||
import { KdfConfig } from "../models/domain/kdf-config";
|
||||
import { Argon2KdfConfig, KdfConfig, PBKDF2KdfConfig } from "../models/domain/kdf-config";
|
||||
import { KeyConnectorUserKeyRequest } from "../models/request/key-connector-user-key.request";
|
||||
import { SetKeyConnectorKeyRequest } from "../models/request/set-key-connector-key.request";
|
||||
import { IdentityTokenResponse } from "../models/response/identity-token.response";
|
||||
@ -133,12 +134,14 @@ export class KeyConnectorService implements KeyConnectorServiceAbstraction {
|
||||
userDecryptionOptions,
|
||||
} = tokenResponse;
|
||||
const password = await this.keyGenerationService.createKey(512);
|
||||
const kdfConfig = new KdfConfig(kdfIterations, kdfMemory, kdfParallelism);
|
||||
const kdfConfig: KdfConfig =
|
||||
kdf === KdfType.PBKDF2_SHA256
|
||||
? new PBKDF2KdfConfig(kdfIterations)
|
||||
: new Argon2KdfConfig(kdfIterations, kdfMemory, kdfParallelism);
|
||||
|
||||
const masterKey = await this.cryptoService.makeMasterKey(
|
||||
password.keyB64,
|
||||
await this.tokenService.getEmail(),
|
||||
kdf,
|
||||
kdfConfig,
|
||||
);
|
||||
const keyConnectorRequest = new KeyConnectorUserKeyRequest(masterKey.encKeyB64);
|
||||
@ -162,7 +165,6 @@ export class KeyConnectorService implements KeyConnectorServiceAbstraction {
|
||||
const keys = new KeysRequest(pubKey, privKey.encryptedString);
|
||||
const setPasswordRequest = new SetKeyConnectorKeyRequest(
|
||||
userKey[1].encryptedString,
|
||||
kdf,
|
||||
kdfConfig,
|
||||
orgId,
|
||||
keys,
|
||||
|
@ -13,6 +13,7 @@ import { KeySuffixOptions } from "../../../platform/enums/key-suffix-options.enu
|
||||
import { UserId } from "../../../types/guid";
|
||||
import { UserKey } from "../../../types/key";
|
||||
import { AccountService } from "../../abstractions/account.service";
|
||||
import { KdfConfigService } from "../../abstractions/kdf-config.service";
|
||||
import { InternalMasterPasswordServiceAbstraction } from "../../abstractions/master-password.service.abstraction";
|
||||
import { UserVerificationApiServiceAbstraction } from "../../abstractions/user-verification/user-verification-api.service.abstraction";
|
||||
import { UserVerificationService as UserVerificationServiceAbstraction } from "../../abstractions/user-verification/user-verification.service.abstraction";
|
||||
@ -47,6 +48,7 @@ export class UserVerificationService implements UserVerificationServiceAbstracti
|
||||
private logService: LogService,
|
||||
private vaultTimeoutSettingsService: VaultTimeoutSettingsServiceAbstraction,
|
||||
private platformUtilsService: PlatformUtilsService,
|
||||
private kdfConfigService: KdfConfigService,
|
||||
) {}
|
||||
|
||||
async getAvailableVerificationOptions(
|
||||
@ -118,8 +120,7 @@ export class UserVerificationService implements UserVerificationServiceAbstracti
|
||||
masterKey = await this.cryptoService.makeMasterKey(
|
||||
verification.secret,
|
||||
await this.stateService.getEmail(),
|
||||
await this.stateService.getKdfType(),
|
||||
await this.stateService.getKdfConfig(),
|
||||
await this.kdfConfigService.getKdfConfig(),
|
||||
);
|
||||
}
|
||||
request.masterPasswordHash = alreadyHashed
|
||||
@ -176,8 +177,7 @@ export class UserVerificationService implements UserVerificationServiceAbstracti
|
||||
masterKey = await this.cryptoService.makeMasterKey(
|
||||
verification.secret,
|
||||
await this.stateService.getEmail(),
|
||||
await this.stateService.getKdfType(),
|
||||
await this.stateService.getKdfConfig(),
|
||||
await this.kdfConfigService.getKdfConfig(),
|
||||
);
|
||||
}
|
||||
const passwordValid = await this.cryptoService.compareAndUpdateKeyHash(
|
||||
|
@ -6,7 +6,7 @@ import { ProfileProviderResponse } from "../../admin-console/models/response/pro
|
||||
import { KdfConfig } from "../../auth/models/domain/kdf-config";
|
||||
import { OrganizationId, ProviderId, UserId } from "../../types/guid";
|
||||
import { UserKey, MasterKey, OrgKey, ProviderKey, PinKey, CipherKey } from "../../types/key";
|
||||
import { KeySuffixOptions, KdfType, HashPurpose } from "../enums";
|
||||
import { KeySuffixOptions, HashPurpose } from "../enums";
|
||||
import { EncArrayBuffer } from "../models/domain/enc-array-buffer";
|
||||
import { EncString } from "../models/domain/enc-string";
|
||||
import { SymmetricCryptoKey } from "../models/domain/symmetric-crypto-key";
|
||||
@ -114,16 +114,10 @@ export abstract class CryptoService {
|
||||
* Generates a master key from the provided password
|
||||
* @param password The user's master password
|
||||
* @param email The user's email
|
||||
* @param kdf The user's selected key derivation function to use
|
||||
* @param KdfConfig The user's key derivation function configuration
|
||||
* @returns A master key derived from the provided password
|
||||
*/
|
||||
abstract makeMasterKey(
|
||||
password: string,
|
||||
email: string,
|
||||
kdf: KdfType,
|
||||
KdfConfig: KdfConfig,
|
||||
): Promise<MasterKey>;
|
||||
abstract makeMasterKey(password: string, email: string, KdfConfig: KdfConfig): Promise<MasterKey>;
|
||||
/**
|
||||
* Encrypts the existing (or provided) user key with the
|
||||
* provided master key
|
||||
@ -258,16 +252,10 @@ export abstract class CryptoService {
|
||||
/**
|
||||
* @param pin The user's pin
|
||||
* @param salt The user's salt
|
||||
* @param kdf The user's kdf
|
||||
* @param kdfConfig The user's kdf config
|
||||
* @returns A key derived from the user's pin
|
||||
*/
|
||||
abstract makePinKey(
|
||||
pin: string,
|
||||
salt: string,
|
||||
kdf: KdfType,
|
||||
kdfConfig: KdfConfig,
|
||||
): Promise<PinKey>;
|
||||
abstract makePinKey(pin: string, salt: string, kdfConfig: KdfConfig): Promise<PinKey>;
|
||||
/**
|
||||
* Clears the user's pin keys from storage
|
||||
* Note: This will remove the stored pin and as a result,
|
||||
@ -279,7 +267,6 @@ export abstract class CryptoService {
|
||||
* Decrypts the user key with their pin
|
||||
* @param pin The user's PIN
|
||||
* @param salt The user's salt
|
||||
* @param kdf The user's KDF
|
||||
* @param kdfConfig The user's KDF config
|
||||
* @param pinProtectedUserKey The user's PIN protected symmetric key, if not provided
|
||||
* it will be retrieved from storage
|
||||
@ -288,7 +275,6 @@ export abstract class CryptoService {
|
||||
abstract decryptUserKeyWithPin(
|
||||
pin: string,
|
||||
salt: string,
|
||||
kdf: KdfType,
|
||||
kdfConfig: KdfConfig,
|
||||
protectedKeyCs?: EncString,
|
||||
): Promise<UserKey>;
|
||||
@ -298,7 +284,6 @@ export abstract class CryptoService {
|
||||
* @param masterPasswordOnRestart True if Master Password on Restart is enabled
|
||||
* @param pin User's PIN
|
||||
* @param email User's email
|
||||
* @param kdf User's KdfType
|
||||
* @param kdfConfig User's KdfConfig
|
||||
* @param oldPinKey The old Pin key from state (retrieved from different
|
||||
* places depending on if Master Password on Restart was enabled)
|
||||
@ -308,7 +293,6 @@ export abstract class CryptoService {
|
||||
masterPasswordOnRestart: boolean,
|
||||
pin: string,
|
||||
email: string,
|
||||
kdf: KdfType,
|
||||
kdfConfig: KdfConfig,
|
||||
oldPinKey: EncString,
|
||||
): Promise<UserKey>;
|
||||
@ -358,21 +342,12 @@ export abstract class CryptoService {
|
||||
privateKey: EncString;
|
||||
}>;
|
||||
|
||||
/**
|
||||
* Validate that the KDF config follows the requirements for the given KDF type.
|
||||
*
|
||||
* @remarks
|
||||
* Should always be called before updating a users KDF config.
|
||||
*/
|
||||
abstract validateKdfConfig(kdf: KdfType, kdfConfig: KdfConfig): void;
|
||||
|
||||
/**
|
||||
* @deprecated Left for migration purposes. Use decryptUserKeyWithPin instead.
|
||||
*/
|
||||
abstract decryptMasterKeyWithPin(
|
||||
pin: string,
|
||||
salt: string,
|
||||
kdf: KdfType,
|
||||
kdfConfig: KdfConfig,
|
||||
protectedKeyCs?: EncString,
|
||||
): Promise<MasterKey>;
|
||||
|
@ -1,6 +1,5 @@
|
||||
import { KdfConfig } from "../../auth/models/domain/kdf-config";
|
||||
import { CsprngArray } from "../../types/csprng";
|
||||
import { KdfType } from "../enums";
|
||||
import { SymmetricCryptoKey } from "../models/domain/symmetric-crypto-key";
|
||||
|
||||
export abstract class KeyGenerationService {
|
||||
@ -46,14 +45,12 @@ export abstract class KeyGenerationService {
|
||||
* Derives a 32 byte key from a password using a key derivation function.
|
||||
* @param password Password to derive the key from.
|
||||
* @param salt Salt for the key derivation function.
|
||||
* @param kdf Key derivation function to use.
|
||||
* @param kdfConfig Configuration for the key derivation function.
|
||||
* @returns 32 byte derived key.
|
||||
*/
|
||||
abstract deriveKeyFromPassword(
|
||||
password: string | Uint8Array,
|
||||
salt: string | Uint8Array,
|
||||
kdf: KdfType,
|
||||
kdfConfig: KdfConfig,
|
||||
): Promise<SymmetricCryptoKey>;
|
||||
}
|
||||
|
@ -1,12 +1,10 @@
|
||||
import { Observable } from "rxjs";
|
||||
|
||||
import { KdfConfig } from "../../auth/models/domain/kdf-config";
|
||||
import { BiometricKey } from "../../auth/types/biometric-key";
|
||||
import { GeneratorOptions } from "../../tools/generator/generator-options";
|
||||
import { GeneratedPasswordHistory, PasswordGeneratorOptions } from "../../tools/generator/password";
|
||||
import { UsernameGeneratorOptions } from "../../tools/generator/username";
|
||||
import { UserId } from "../../types/guid";
|
||||
import { KdfType } from "../enums";
|
||||
import { Account } from "../models/domain/account";
|
||||
import { EncString } from "../models/domain/enc-string";
|
||||
import { StorageOptions } from "../models/domain/storage-options";
|
||||
@ -149,10 +147,6 @@ export abstract class StateService<T extends Account = Account> {
|
||||
*/
|
||||
setEncryptedPinProtected: (value: string, options?: StorageOptions) => Promise<void>;
|
||||
getIsAuthenticated: (options?: StorageOptions) => Promise<boolean>;
|
||||
getKdfConfig: (options?: StorageOptions) => Promise<KdfConfig>;
|
||||
setKdfConfig: (kdfConfig: KdfConfig, options?: StorageOptions) => Promise<void>;
|
||||
getKdfType: (options?: StorageOptions) => Promise<KdfType>;
|
||||
setKdfType: (value: KdfType, options?: StorageOptions) => Promise<void>;
|
||||
getLastActive: (options?: StorageOptions) => Promise<number>;
|
||||
setLastActive: (value: number, options?: StorageOptions) => Promise<void>;
|
||||
getLastSync: (options?: StorageOptions) => Promise<string>;
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { KdfConfig } from "../../auth/models/domain/kdf-config";
|
||||
import { PBKDF2KdfConfig } from "../../auth/models/domain/kdf-config";
|
||||
import { RangeWithDefault } from "../misc/range-with-default";
|
||||
|
||||
export enum KdfType {
|
||||
@ -12,4 +12,4 @@ export const ARGON2_ITERATIONS = new RangeWithDefault(2, 10, 3);
|
||||
|
||||
export const DEFAULT_KDF_TYPE = KdfType.PBKDF2_SHA256;
|
||||
export const PBKDF2_ITERATIONS = new RangeWithDefault(600_000, 2_000_000, 600_000);
|
||||
export const DEFAULT_KDF_CONFIG = new KdfConfig(PBKDF2_ITERATIONS.defaultValue);
|
||||
export const DEFAULT_KDF_CONFIG = new PBKDF2KdfConfig(PBKDF2_ITERATIONS.defaultValue);
|
||||
|
@ -4,6 +4,7 @@ import { firstValueFrom, of, tap } from "rxjs";
|
||||
import { FakeAccountService, mockAccountServiceWith } from "../../../spec/fake-account-service";
|
||||
import { FakeActiveUserState, FakeSingleUserState } from "../../../spec/fake-state";
|
||||
import { FakeStateProvider } from "../../../spec/fake-state-provider";
|
||||
import { KdfConfigService } from "../../auth/abstractions/kdf-config.service";
|
||||
import { FakeMasterPasswordService } from "../../auth/services/master-password/fake-master-password.service";
|
||||
import { CsprngArray } from "../../types/csprng";
|
||||
import { UserId } from "../../types/guid";
|
||||
@ -37,6 +38,7 @@ describe("cryptoService", () => {
|
||||
const platformUtilService = mock<PlatformUtilsService>();
|
||||
const logService = mock<LogService>();
|
||||
const stateService = mock<StateService>();
|
||||
const kdfConfigService = mock<KdfConfigService>();
|
||||
let stateProvider: FakeStateProvider;
|
||||
|
||||
const mockUserId = Utils.newGuid() as UserId;
|
||||
@ -58,6 +60,7 @@ describe("cryptoService", () => {
|
||||
stateService,
|
||||
accountService,
|
||||
stateProvider,
|
||||
kdfConfigService,
|
||||
);
|
||||
});
|
||||
|
||||
|
@ -6,6 +6,7 @@ import { ProfileOrganizationResponse } from "../../admin-console/models/response
|
||||
import { ProfileProviderOrganizationResponse } from "../../admin-console/models/response/profile-provider-organization.response";
|
||||
import { ProfileProviderResponse } from "../../admin-console/models/response/profile-provider.response";
|
||||
import { AccountService } from "../../auth/abstractions/account.service";
|
||||
import { KdfConfigService } from "../../auth/abstractions/kdf-config.service";
|
||||
import { InternalMasterPasswordServiceAbstraction } from "../../auth/abstractions/master-password.service.abstraction";
|
||||
import { KdfConfig } from "../../auth/models/domain/kdf-config";
|
||||
import { Utils } from "../../platform/misc/utils";
|
||||
@ -28,16 +29,7 @@ import { KeyGenerationService } from "../abstractions/key-generation.service";
|
||||
import { LogService } from "../abstractions/log.service";
|
||||
import { PlatformUtilsService } from "../abstractions/platform-utils.service";
|
||||
import { StateService } from "../abstractions/state.service";
|
||||
import {
|
||||
KeySuffixOptions,
|
||||
HashPurpose,
|
||||
KdfType,
|
||||
ARGON2_ITERATIONS,
|
||||
ARGON2_MEMORY,
|
||||
ARGON2_PARALLELISM,
|
||||
EncryptionType,
|
||||
PBKDF2_ITERATIONS,
|
||||
} from "../enums";
|
||||
import { KeySuffixOptions, HashPurpose, EncryptionType } from "../enums";
|
||||
import { sequentialize } from "../misc/sequentialize";
|
||||
import { EFFLongWordList } from "../misc/wordlist";
|
||||
import { EncArrayBuffer } from "../models/domain/enc-array-buffer";
|
||||
@ -91,6 +83,7 @@ export class CryptoService implements CryptoServiceAbstraction {
|
||||
protected stateService: StateService,
|
||||
protected accountService: AccountService,
|
||||
protected stateProvider: StateProvider,
|
||||
protected kdfConfigService: KdfConfigService,
|
||||
) {
|
||||
// User Key
|
||||
this.activeUserKeyState = stateProvider.getActive(USER_KEY);
|
||||
@ -283,8 +276,7 @@ export class CryptoService implements CryptoServiceAbstraction {
|
||||
return (masterKey ||= await this.makeMasterKey(
|
||||
password,
|
||||
await this.stateService.getEmail({ userId: userId }),
|
||||
await this.stateService.getKdfType({ userId: userId }),
|
||||
await this.stateService.getKdfConfig({ userId: userId }),
|
||||
await this.kdfConfigService.getKdfConfig(),
|
||||
));
|
||||
}
|
||||
|
||||
@ -295,16 +287,10 @@ export class CryptoService implements CryptoServiceAbstraction {
|
||||
* Does not validate the kdf config to ensure it satisfies the minimum requirements for the given kdf type.
|
||||
* TODO: Move to MasterPasswordService
|
||||
*/
|
||||
async makeMasterKey(
|
||||
password: string,
|
||||
email: string,
|
||||
kdf: KdfType,
|
||||
KdfConfig: KdfConfig,
|
||||
): Promise<MasterKey> {
|
||||
async makeMasterKey(password: string, email: string, KdfConfig: KdfConfig): Promise<MasterKey> {
|
||||
return (await this.keyGenerationService.deriveKeyFromPassword(
|
||||
password,
|
||||
email,
|
||||
kdf,
|
||||
KdfConfig,
|
||||
)) as MasterKey;
|
||||
}
|
||||
@ -560,8 +546,8 @@ export class CryptoService implements CryptoServiceAbstraction {
|
||||
await this.stateProvider.setUserState(USER_ENCRYPTED_PRIVATE_KEY, null, userId);
|
||||
}
|
||||
|
||||
async makePinKey(pin: string, salt: string, kdf: KdfType, kdfConfig: KdfConfig): Promise<PinKey> {
|
||||
const pinKey = await this.keyGenerationService.deriveKeyFromPassword(pin, salt, kdf, kdfConfig);
|
||||
async makePinKey(pin: string, salt: string, kdfConfig: KdfConfig): Promise<PinKey> {
|
||||
const pinKey = await this.keyGenerationService.deriveKeyFromPassword(pin, salt, kdfConfig);
|
||||
return (await this.stretchKey(pinKey)) as PinKey;
|
||||
}
|
||||
|
||||
@ -575,7 +561,6 @@ export class CryptoService implements CryptoServiceAbstraction {
|
||||
async decryptUserKeyWithPin(
|
||||
pin: string,
|
||||
salt: string,
|
||||
kdf: KdfType,
|
||||
kdfConfig: KdfConfig,
|
||||
pinProtectedUserKey?: EncString,
|
||||
): Promise<UserKey> {
|
||||
@ -584,7 +569,7 @@ export class CryptoService implements CryptoServiceAbstraction {
|
||||
if (!pinProtectedUserKey) {
|
||||
throw new Error("No PIN protected key found.");
|
||||
}
|
||||
const pinKey = await this.makePinKey(pin, salt, kdf, kdfConfig);
|
||||
const pinKey = await this.makePinKey(pin, salt, kdfConfig);
|
||||
const userKey = await this.encryptService.decryptToBytes(pinProtectedUserKey, pinKey);
|
||||
return new SymmetricCryptoKey(userKey) as UserKey;
|
||||
}
|
||||
@ -593,7 +578,6 @@ export class CryptoService implements CryptoServiceAbstraction {
|
||||
async decryptMasterKeyWithPin(
|
||||
pin: string,
|
||||
salt: string,
|
||||
kdf: KdfType,
|
||||
kdfConfig: KdfConfig,
|
||||
pinProtectedMasterKey?: EncString,
|
||||
): Promise<MasterKey> {
|
||||
@ -604,7 +588,7 @@ export class CryptoService implements CryptoServiceAbstraction {
|
||||
}
|
||||
pinProtectedMasterKey = new EncString(pinProtectedMasterKeyString);
|
||||
}
|
||||
const pinKey = await this.makePinKey(pin, salt, kdf, kdfConfig);
|
||||
const pinKey = await this.makePinKey(pin, salt, kdfConfig);
|
||||
const masterKey = await this.encryptService.decryptToBytes(pinProtectedMasterKey, pinKey);
|
||||
return new SymmetricCryptoKey(masterKey) as MasterKey;
|
||||
}
|
||||
@ -831,8 +815,7 @@ export class CryptoService implements CryptoServiceAbstraction {
|
||||
const pinKey = await this.makePinKey(
|
||||
pin,
|
||||
await this.stateService.getEmail({ userId: userId }),
|
||||
await this.stateService.getKdfType({ userId: userId }),
|
||||
await this.stateService.getKdfConfig({ userId: userId }),
|
||||
await this.kdfConfigService.getKdfConfig(),
|
||||
);
|
||||
const encPin = await this.encryptService.encrypt(key.key, pinKey);
|
||||
|
||||
@ -873,43 +856,6 @@ export class CryptoService implements CryptoServiceAbstraction {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate that the KDF config follows the requirements for the given KDF type.
|
||||
*
|
||||
* @remarks
|
||||
* Should always be called before updating a users KDF config.
|
||||
*/
|
||||
validateKdfConfig(kdf: KdfType, kdfConfig: KdfConfig): void {
|
||||
switch (kdf) {
|
||||
case KdfType.PBKDF2_SHA256:
|
||||
if (!PBKDF2_ITERATIONS.inRange(kdfConfig.iterations)) {
|
||||
throw new Error(
|
||||
`PBKDF2 iterations must be between ${PBKDF2_ITERATIONS.min} and ${PBKDF2_ITERATIONS.max}`,
|
||||
);
|
||||
}
|
||||
break;
|
||||
case KdfType.Argon2id:
|
||||
if (!ARGON2_ITERATIONS.inRange(kdfConfig.iterations)) {
|
||||
throw new Error(
|
||||
`Argon2 iterations must be between ${ARGON2_ITERATIONS.min} and ${ARGON2_ITERATIONS.max}`,
|
||||
);
|
||||
}
|
||||
|
||||
if (!ARGON2_MEMORY.inRange(kdfConfig.memory)) {
|
||||
throw new Error(
|
||||
`Argon2 memory must be between ${ARGON2_MEMORY.min}mb and ${ARGON2_MEMORY.max}mb`,
|
||||
);
|
||||
}
|
||||
|
||||
if (!ARGON2_PARALLELISM.inRange(kdfConfig.parallelism)) {
|
||||
throw new Error(
|
||||
`Argon2 parallelism must be between ${ARGON2_PARALLELISM.min} and ${ARGON2_PARALLELISM.max}.`,
|
||||
);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
protected async clearAllStoredUserKeys(userId?: UserId): Promise<void> {
|
||||
await this.stateService.setUserKeyAutoUnlock(null, { userId: userId });
|
||||
await this.stateService.setPinKeyEncryptedUserKeyEphemeral(null, { userId: userId });
|
||||
@ -1007,16 +953,15 @@ export class CryptoService implements CryptoServiceAbstraction {
|
||||
masterPasswordOnRestart: boolean,
|
||||
pin: string,
|
||||
email: string,
|
||||
kdf: KdfType,
|
||||
kdfConfig: KdfConfig,
|
||||
oldPinKey: EncString,
|
||||
): Promise<UserKey> {
|
||||
// Decrypt
|
||||
const masterKey = await this.decryptMasterKeyWithPin(pin, email, kdf, kdfConfig, oldPinKey);
|
||||
const masterKey = await this.decryptMasterKeyWithPin(pin, email, kdfConfig, oldPinKey);
|
||||
const encUserKey = await this.stateService.getEncryptedCryptoSymmetricKey();
|
||||
const userKey = await this.decryptUserKeyWithMasterKey(masterKey, new EncString(encUserKey));
|
||||
// Migrate
|
||||
const pinKey = await this.makePinKey(pin, email, kdf, kdfConfig);
|
||||
const pinKey = await this.makePinKey(pin, email, kdfConfig);
|
||||
const pinProtectedKey = await this.encryptService.encrypt(userKey.key, pinKey);
|
||||
if (masterPasswordOnRestart) {
|
||||
await this.stateService.setDecryptedPinProtected(null);
|
||||
|
@ -1,9 +1,8 @@
|
||||
import { mock } from "jest-mock-extended";
|
||||
|
||||
import { KdfConfig } from "../../auth/models/domain/kdf-config";
|
||||
import { Argon2KdfConfig, PBKDF2KdfConfig } from "../../auth/models/domain/kdf-config";
|
||||
import { CsprngArray } from "../../types/csprng";
|
||||
import { CryptoFunctionService } from "../abstractions/crypto-function.service";
|
||||
import { KdfType } from "../enums";
|
||||
|
||||
import { KeyGenerationService } from "./key-generation.service";
|
||||
|
||||
@ -75,12 +74,11 @@ describe("KeyGenerationService", () => {
|
||||
it("should derive a 32 byte key from a password using pbkdf2", async () => {
|
||||
const password = "password";
|
||||
const salt = "salt";
|
||||
const kdf = KdfType.PBKDF2_SHA256;
|
||||
const kdfConfig = new KdfConfig(600_000);
|
||||
const kdfConfig = new PBKDF2KdfConfig(600_000);
|
||||
|
||||
cryptoFunctionService.pbkdf2.mockResolvedValue(new Uint8Array(32));
|
||||
|
||||
const key = await sut.deriveKeyFromPassword(password, salt, kdf, kdfConfig);
|
||||
const key = await sut.deriveKeyFromPassword(password, salt, kdfConfig);
|
||||
|
||||
expect(key.key.length).toEqual(32);
|
||||
});
|
||||
@ -88,13 +86,12 @@ describe("KeyGenerationService", () => {
|
||||
it("should derive a 32 byte key from a password using argon2id", async () => {
|
||||
const password = "password";
|
||||
const salt = "salt";
|
||||
const kdf = KdfType.Argon2id;
|
||||
const kdfConfig = new KdfConfig(600_000, 15);
|
||||
const kdfConfig = new Argon2KdfConfig(3, 16, 4);
|
||||
|
||||
cryptoFunctionService.hash.mockResolvedValue(new Uint8Array(32));
|
||||
cryptoFunctionService.argon2.mockResolvedValue(new Uint8Array(32));
|
||||
|
||||
const key = await sut.deriveKeyFromPassword(password, salt, kdf, kdfConfig);
|
||||
const key = await sut.deriveKeyFromPassword(password, salt, kdfConfig);
|
||||
|
||||
expect(key.key.length).toEqual(32);
|
||||
});
|
||||
|
@ -46,17 +46,16 @@ export class KeyGenerationService implements KeyGenerationServiceAbstraction {
|
||||
async deriveKeyFromPassword(
|
||||
password: string | Uint8Array,
|
||||
salt: string | Uint8Array,
|
||||
kdf: KdfType,
|
||||
kdfConfig: KdfConfig,
|
||||
): Promise<SymmetricCryptoKey> {
|
||||
let key: Uint8Array = null;
|
||||
if (kdf == null || kdf === KdfType.PBKDF2_SHA256) {
|
||||
if (kdfConfig.kdfType == null || kdfConfig.kdfType === KdfType.PBKDF2_SHA256) {
|
||||
if (kdfConfig.iterations == null) {
|
||||
kdfConfig.iterations = PBKDF2_ITERATIONS.defaultValue;
|
||||
}
|
||||
|
||||
key = await this.cryptoFunctionService.pbkdf2(password, salt, "sha256", kdfConfig.iterations);
|
||||
} else if (kdf == KdfType.Argon2id) {
|
||||
} else if (kdfConfig.kdfType == KdfType.Argon2id) {
|
||||
if (kdfConfig.iterations == null) {
|
||||
kdfConfig.iterations = ARGON2_ITERATIONS.defaultValue;
|
||||
}
|
||||
|
@ -3,7 +3,6 @@ import { Jsonify, JsonValue } from "type-fest";
|
||||
|
||||
import { AccountService } from "../../auth/abstractions/account.service";
|
||||
import { TokenService } from "../../auth/abstractions/token.service";
|
||||
import { KdfConfig } from "../../auth/models/domain/kdf-config";
|
||||
import { BiometricKey } from "../../auth/types/biometric-key";
|
||||
import { GeneratorOptions } from "../../tools/generator/generator-options";
|
||||
import { GeneratedPasswordHistory, PasswordGeneratorOptions } from "../../tools/generator/password";
|
||||
@ -19,7 +18,7 @@ import {
|
||||
AbstractMemoryStorageService,
|
||||
AbstractStorageService,
|
||||
} from "../abstractions/storage.service";
|
||||
import { HtmlStorageLocation, KdfType, StorageLocation } from "../enums";
|
||||
import { HtmlStorageLocation, StorageLocation } from "../enums";
|
||||
import { StateFactory } from "../factories/state-factory";
|
||||
import { Utils } from "../misc/utils";
|
||||
import { Account, AccountData, AccountSettings } from "../models/domain/account";
|
||||
@ -643,49 +642,6 @@ export class StateService<
|
||||
);
|
||||
}
|
||||
|
||||
async getKdfConfig(options?: StorageOptions): Promise<KdfConfig> {
|
||||
const iterations = (
|
||||
await this.getAccount(this.reconcileOptions(options, await this.defaultOnDiskOptions()))
|
||||
)?.profile?.kdfIterations;
|
||||
const memory = (
|
||||
await this.getAccount(this.reconcileOptions(options, await this.defaultOnDiskOptions()))
|
||||
)?.profile?.kdfMemory;
|
||||
const parallelism = (
|
||||
await this.getAccount(this.reconcileOptions(options, await this.defaultOnDiskOptions()))
|
||||
)?.profile?.kdfParallelism;
|
||||
return new KdfConfig(iterations, memory, parallelism);
|
||||
}
|
||||
|
||||
async setKdfConfig(config: KdfConfig, options?: StorageOptions): Promise<void> {
|
||||
const account = await this.getAccount(
|
||||
this.reconcileOptions(options, await this.defaultOnDiskOptions()),
|
||||
);
|
||||
account.profile.kdfIterations = config.iterations;
|
||||
account.profile.kdfMemory = config.memory;
|
||||
account.profile.kdfParallelism = config.parallelism;
|
||||
await this.saveAccount(
|
||||
account,
|
||||
this.reconcileOptions(options, await this.defaultOnDiskOptions()),
|
||||
);
|
||||
}
|
||||
|
||||
async getKdfType(options?: StorageOptions): Promise<KdfType> {
|
||||
return (
|
||||
await this.getAccount(this.reconcileOptions(options, await this.defaultOnDiskOptions()))
|
||||
)?.profile?.kdfType;
|
||||
}
|
||||
|
||||
async setKdfType(value: KdfType, options?: StorageOptions): Promise<void> {
|
||||
const account = await this.getAccount(
|
||||
this.reconcileOptions(options, await this.defaultOnDiskOptions()),
|
||||
);
|
||||
account.profile.kdfType = value;
|
||||
await this.saveAccount(
|
||||
account,
|
||||
this.reconcileOptions(options, await this.defaultOnDiskOptions()),
|
||||
);
|
||||
}
|
||||
|
||||
async getLastActive(options?: StorageOptions): Promise<number> {
|
||||
options = this.reconcileOptions(options, await this.defaultOnDiskOptions());
|
||||
|
||||
|
@ -35,6 +35,7 @@ export const BILLING_DISK = new StateDefinition("billing", "disk");
|
||||
|
||||
// Auth
|
||||
|
||||
export const KDF_CONFIG_DISK = new StateDefinition("kdfConfig", "disk");
|
||||
export const KEY_CONNECTOR_DISK = new StateDefinition("keyConnector", "disk");
|
||||
export const ACCOUNT_MEMORY = new StateDefinition("account", "memory");
|
||||
export const MASTER_PASSWORD_MEMORY = new StateDefinition("masterPassword", "memory");
|
||||
|
@ -55,6 +55,7 @@ import { MoveMasterKeyStateToProviderMigrator } from "./migrations/55-move-maste
|
||||
import { AuthRequestMigrator } from "./migrations/56-move-auth-requests";
|
||||
import { CipherServiceMigrator } from "./migrations/57-move-cipher-service-to-state-provider";
|
||||
import { RemoveRefreshTokenMigratedFlagMigrator } from "./migrations/58-remove-refresh-token-migrated-state-provider-flag";
|
||||
import { KdfConfigMigrator } from "./migrations/59-move-kdf-config-to-state-provider";
|
||||
import { RemoveLegacyEtmKeyMigrator } from "./migrations/6-remove-legacy-etm-key";
|
||||
import { MoveBiometricAutoPromptToAccount } from "./migrations/7-move-biometric-auto-prompt-to-account";
|
||||
import { MoveStateVersionMigrator } from "./migrations/8-move-state-version";
|
||||
@ -62,7 +63,7 @@ import { MoveBrowserSettingsToGlobal } from "./migrations/9-move-browser-setting
|
||||
import { MinVersionMigrator } from "./migrations/min-version";
|
||||
|
||||
export const MIN_VERSION = 3;
|
||||
export const CURRENT_VERSION = 58;
|
||||
export const CURRENT_VERSION = 59;
|
||||
export type MinVersion = typeof MIN_VERSION;
|
||||
|
||||
export function createMigrationBuilder() {
|
||||
@ -122,7 +123,8 @@ export function createMigrationBuilder() {
|
||||
.with(MoveMasterKeyStateToProviderMigrator, 54, 55)
|
||||
.with(AuthRequestMigrator, 55, 56)
|
||||
.with(CipherServiceMigrator, 56, 57)
|
||||
.with(RemoveRefreshTokenMigratedFlagMigrator, 57, CURRENT_VERSION);
|
||||
.with(RemoveRefreshTokenMigratedFlagMigrator, 57, 58)
|
||||
.with(KdfConfigMigrator, 58, CURRENT_VERSION);
|
||||
}
|
||||
|
||||
export async function currentVersion(
|
||||
|
@ -0,0 +1,153 @@
|
||||
import { MockProxy } from "jest-mock-extended";
|
||||
|
||||
import { KeyDefinitionLike, MigrationHelper } from "../migration-helper";
|
||||
import { mockMigrationHelper } from "../migration-helper.spec";
|
||||
|
||||
import { KdfConfigMigrator } from "./59-move-kdf-config-to-state-provider";
|
||||
|
||||
function exampleJSON() {
|
||||
return {
|
||||
global: {
|
||||
otherStuff: "otherStuff1",
|
||||
},
|
||||
authenticatedAccounts: ["FirstAccount", "SecondAccount"],
|
||||
FirstAccount: {
|
||||
profile: {
|
||||
kdfIterations: 3,
|
||||
kdfMemory: 64,
|
||||
kdfParallelism: 5,
|
||||
kdfType: 1,
|
||||
otherStuff: "otherStuff1",
|
||||
},
|
||||
otherStuff: "otherStuff2",
|
||||
},
|
||||
SecondAccount: {
|
||||
profile: {
|
||||
kdfIterations: 600_001,
|
||||
kdfMemory: null as number,
|
||||
kdfParallelism: null as number,
|
||||
kdfType: 0,
|
||||
otherStuff: "otherStuff3",
|
||||
},
|
||||
otherStuff: "otherStuff4",
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
function rollbackJSON() {
|
||||
return {
|
||||
user_FirstAccount_kdfConfig_kdfConfig: {
|
||||
iterations: 3,
|
||||
memory: 64,
|
||||
parallelism: 5,
|
||||
kdfType: 1,
|
||||
},
|
||||
user_SecondAccount_kdfConfig_kdfConfig: {
|
||||
iterations: 600_001,
|
||||
memory: null as number,
|
||||
parallelism: null as number,
|
||||
kdfType: 0,
|
||||
},
|
||||
global: {
|
||||
otherStuff: "otherStuff1",
|
||||
},
|
||||
authenticatedAccounts: ["FirstAccount", "SecondAccount"],
|
||||
FirstAccount: {
|
||||
profile: {
|
||||
otherStuff: "otherStuff2",
|
||||
},
|
||||
otherStuff: "otherStuff3",
|
||||
},
|
||||
SecondAccount: {
|
||||
profile: {
|
||||
otherStuff: "otherStuff4",
|
||||
},
|
||||
otherStuff: "otherStuff5",
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
const kdfConfigKeyDefinition: KeyDefinitionLike = {
|
||||
key: "kdfConfig",
|
||||
stateDefinition: {
|
||||
name: "kdfConfig",
|
||||
},
|
||||
};
|
||||
|
||||
describe("KdfConfigMigrator", () => {
|
||||
let helper: MockProxy<MigrationHelper>;
|
||||
let sut: KdfConfigMigrator;
|
||||
|
||||
describe("migrate", () => {
|
||||
beforeEach(() => {
|
||||
helper = mockMigrationHelper(exampleJSON(), 59);
|
||||
sut = new KdfConfigMigrator(58, 59);
|
||||
});
|
||||
|
||||
it("should remove kdfType and kdfConfig from Account.Profile", async () => {
|
||||
await sut.migrate(helper);
|
||||
|
||||
expect(helper.set).toHaveBeenCalledTimes(2);
|
||||
expect(helper.set).toHaveBeenCalledWith("FirstAccount", {
|
||||
profile: {
|
||||
otherStuff: "otherStuff1",
|
||||
},
|
||||
otherStuff: "otherStuff2",
|
||||
});
|
||||
expect(helper.set).toHaveBeenCalledWith("SecondAccount", {
|
||||
profile: {
|
||||
otherStuff: "otherStuff3",
|
||||
},
|
||||
otherStuff: "otherStuff4",
|
||||
});
|
||||
expect(helper.setToUser).toHaveBeenCalledWith("FirstAccount", kdfConfigKeyDefinition, {
|
||||
iterations: 3,
|
||||
memory: 64,
|
||||
parallelism: 5,
|
||||
kdfType: 1,
|
||||
});
|
||||
expect(helper.setToUser).toHaveBeenCalledWith("SecondAccount", kdfConfigKeyDefinition, {
|
||||
iterations: 600_001,
|
||||
memory: null as number,
|
||||
parallelism: null as number,
|
||||
kdfType: 0,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("rollback", () => {
|
||||
beforeEach(() => {
|
||||
helper = mockMigrationHelper(rollbackJSON(), 59);
|
||||
sut = new KdfConfigMigrator(58, 59);
|
||||
});
|
||||
|
||||
it("should null out new KdfConfig account value and set account.profile", async () => {
|
||||
await sut.rollback(helper);
|
||||
|
||||
expect(helper.setToUser).toHaveBeenCalledTimes(2);
|
||||
expect(helper.setToUser).toHaveBeenCalledWith("FirstAccount", kdfConfigKeyDefinition, null);
|
||||
expect(helper.setToUser).toHaveBeenCalledWith("SecondAccount", kdfConfigKeyDefinition, null);
|
||||
expect(helper.set).toHaveBeenCalledTimes(2);
|
||||
expect(helper.set).toHaveBeenCalledWith("FirstAccount", {
|
||||
profile: {
|
||||
kdfIterations: 3,
|
||||
kdfMemory: 64,
|
||||
kdfParallelism: 5,
|
||||
kdfType: 1,
|
||||
otherStuff: "otherStuff2",
|
||||
},
|
||||
otherStuff: "otherStuff3",
|
||||
});
|
||||
expect(helper.set).toHaveBeenCalledWith("SecondAccount", {
|
||||
profile: {
|
||||
kdfIterations: 600_001,
|
||||
kdfMemory: null as number,
|
||||
kdfParallelism: null as number,
|
||||
kdfType: 0,
|
||||
otherStuff: "otherStuff4",
|
||||
},
|
||||
otherStuff: "otherStuff5",
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
@ -0,0 +1,78 @@
|
||||
import { KeyDefinitionLike, MigrationHelper } from "../migration-helper";
|
||||
import { Migrator } from "../migrator";
|
||||
|
||||
enum KdfType {
|
||||
PBKDF2_SHA256 = 0,
|
||||
Argon2id = 1,
|
||||
}
|
||||
|
||||
class KdfConfig {
|
||||
iterations: number;
|
||||
kdfType: KdfType;
|
||||
memory?: number;
|
||||
parallelism?: number;
|
||||
}
|
||||
|
||||
type ExpectedAccountType = {
|
||||
profile?: {
|
||||
kdfIterations: number;
|
||||
kdfType: KdfType;
|
||||
kdfMemory?: number;
|
||||
kdfParallelism?: number;
|
||||
};
|
||||
};
|
||||
|
||||
const kdfConfigKeyDefinition: KeyDefinitionLike = {
|
||||
key: "kdfConfig",
|
||||
stateDefinition: {
|
||||
name: "kdfConfig",
|
||||
},
|
||||
};
|
||||
|
||||
export class KdfConfigMigrator extends Migrator<58, 59> {
|
||||
async migrate(helper: MigrationHelper): Promise<void> {
|
||||
const accounts = await helper.getAccounts<ExpectedAccountType>();
|
||||
async function migrateAccount(userId: string, account: ExpectedAccountType): Promise<void> {
|
||||
const iterations = account?.profile?.kdfIterations;
|
||||
const kdfType = account?.profile?.kdfType;
|
||||
const memory = account?.profile?.kdfMemory;
|
||||
const parallelism = account?.profile?.kdfParallelism;
|
||||
|
||||
const kdfConfig: KdfConfig = {
|
||||
iterations: iterations,
|
||||
kdfType: kdfType,
|
||||
memory: memory,
|
||||
parallelism: parallelism,
|
||||
};
|
||||
|
||||
if (kdfConfig != null) {
|
||||
await helper.setToUser(userId, kdfConfigKeyDefinition, kdfConfig);
|
||||
delete account?.profile?.kdfIterations;
|
||||
delete account?.profile?.kdfType;
|
||||
delete account?.profile?.kdfMemory;
|
||||
delete account?.profile?.kdfParallelism;
|
||||
}
|
||||
|
||||
await helper.set(userId, account);
|
||||
}
|
||||
await Promise.all([...accounts.map(({ userId, account }) => migrateAccount(userId, account))]);
|
||||
}
|
||||
|
||||
async rollback(helper: MigrationHelper): Promise<void> {
|
||||
const accounts = await helper.getAccounts<ExpectedAccountType>();
|
||||
async function rollbackAccount(userId: string, account: ExpectedAccountType): Promise<void> {
|
||||
const kdfConfig: KdfConfig = await helper.getFromUser(userId, kdfConfigKeyDefinition);
|
||||
|
||||
if (kdfConfig != null) {
|
||||
account.profile.kdfIterations = kdfConfig.iterations;
|
||||
account.profile.kdfType = kdfConfig.kdfType;
|
||||
account.profile.kdfMemory = kdfConfig.memory;
|
||||
account.profile.kdfParallelism = kdfConfig.parallelism;
|
||||
await helper.setToUser(userId, kdfConfigKeyDefinition, null);
|
||||
}
|
||||
await helper.set(userId, account);
|
||||
}
|
||||
|
||||
await Promise.all([...accounts.map(({ userId, account }) => rollbackAccount(userId, account))]);
|
||||
}
|
||||
}
|
@ -1,10 +1,10 @@
|
||||
import { Observable, concatMap, distinctUntilChanged, firstValueFrom, map } from "rxjs";
|
||||
|
||||
import { PBKDF2KdfConfig } from "../../../auth/models/domain/kdf-config";
|
||||
import { CryptoService } from "../../../platform/abstractions/crypto.service";
|
||||
import { EncryptService } from "../../../platform/abstractions/encrypt.service";
|
||||
import { I18nService } from "../../../platform/abstractions/i18n.service";
|
||||
import { KeyGenerationService } from "../../../platform/abstractions/key-generation.service";
|
||||
import { KdfType } from "../../../platform/enums";
|
||||
import { Utils } from "../../../platform/misc/utils";
|
||||
import { EncArrayBuffer } from "../../../platform/models/domain/enc-array-buffer";
|
||||
import { EncString } from "../../../platform/models/domain/enc-string";
|
||||
@ -69,8 +69,7 @@ export class SendService implements InternalSendServiceAbstraction {
|
||||
const passwordKey = await this.keyGenerationService.deriveKeyFromPassword(
|
||||
password,
|
||||
model.key,
|
||||
KdfType.PBKDF2_SHA256,
|
||||
{ iterations: SEND_KDF_ITERATIONS },
|
||||
new PBKDF2KdfConfig(SEND_KDF_ITERATIONS),
|
||||
);
|
||||
send.password = passwordKey.keyB64;
|
||||
}
|
||||
|
@ -1,4 +1,8 @@
|
||||
import { KdfConfig } from "@bitwarden/common/auth/models/domain/kdf-config";
|
||||
import {
|
||||
Argon2KdfConfig,
|
||||
KdfConfig,
|
||||
PBKDF2KdfConfig,
|
||||
} from "@bitwarden/common/auth/models/domain/kdf-config";
|
||||
import { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.service";
|
||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||
import { KdfType } from "@bitwarden/common/platform/enums";
|
||||
@ -69,12 +73,12 @@ export class BitwardenPasswordProtectedImporter extends BitwardenJsonImporter im
|
||||
return false;
|
||||
}
|
||||
|
||||
this.key = await this.cryptoService.makePinKey(
|
||||
password,
|
||||
jdoc.salt,
|
||||
jdoc.kdfType,
|
||||
new KdfConfig(jdoc.kdfIterations, jdoc.kdfMemory, jdoc.kdfParallelism),
|
||||
);
|
||||
const kdfConfig: KdfConfig =
|
||||
jdoc.kdfType === KdfType.PBKDF2_SHA256
|
||||
? new PBKDF2KdfConfig(jdoc.kdfIterations)
|
||||
: new Argon2KdfConfig(jdoc.kdfIterations, jdoc.kdfMemory, jdoc.kdfParallelism);
|
||||
|
||||
this.key = await this.cryptoService.makePinKey(password, jdoc.salt, kdfConfig);
|
||||
|
||||
const encKeyValidation = new EncString(jdoc.encKeyValidation_DO_NOT_EDIT);
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { KdfConfigService } from "@bitwarden/common/auth/abstractions/kdf-config.service";
|
||||
import { KdfConfig } from "@bitwarden/common/auth/models/domain/kdf-config";
|
||||
import { CryptoFunctionService } from "@bitwarden/common/platform/abstractions/crypto-function.service";
|
||||
import { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.service";
|
||||
import { StateService } from "@bitwarden/common/platform/abstractions/state.service";
|
||||
import { KdfType } from "@bitwarden/common/platform/enums";
|
||||
import { Utils } from "@bitwarden/common/platform/misc/utils";
|
||||
import { CipherType } from "@bitwarden/common/vault/enums";
|
||||
@ -12,15 +12,14 @@ export class BaseVaultExportService {
|
||||
constructor(
|
||||
protected cryptoService: CryptoService,
|
||||
private cryptoFunctionService: CryptoFunctionService,
|
||||
private stateService: StateService,
|
||||
private kdfConfigService: KdfConfigService,
|
||||
) {}
|
||||
|
||||
protected async buildPasswordExport(clearText: string, password: string): Promise<string> {
|
||||
const kdfType: KdfType = await this.stateService.getKdfType();
|
||||
const kdfConfig: KdfConfig = await this.stateService.getKdfConfig();
|
||||
const kdfConfig: KdfConfig = await this.kdfConfigService.getKdfConfig();
|
||||
|
||||
const salt = Utils.fromBufferToB64(await this.cryptoFunctionService.randomBytes(16));
|
||||
const key = await this.cryptoService.makePinKey(password, salt, kdfType, kdfConfig);
|
||||
const key = await this.cryptoService.makePinKey(password, salt, kdfConfig);
|
||||
|
||||
const encKeyValidation = await this.cryptoService.encrypt(Utils.newGuid(), key);
|
||||
const encText = await this.cryptoService.encrypt(clearText, key);
|
||||
@ -29,14 +28,17 @@ export class BaseVaultExportService {
|
||||
encrypted: true,
|
||||
passwordProtected: true,
|
||||
salt: salt,
|
||||
kdfType: kdfType,
|
||||
kdfType: kdfConfig.kdfType,
|
||||
kdfIterations: kdfConfig.iterations,
|
||||
kdfMemory: kdfConfig.memory,
|
||||
kdfParallelism: kdfConfig.parallelism,
|
||||
encKeyValidation_DO_NOT_EDIT: encKeyValidation.encryptedString,
|
||||
data: encText.encryptedString,
|
||||
};
|
||||
|
||||
if (kdfConfig.kdfType === KdfType.Argon2id) {
|
||||
jsonDoc.kdfMemory = kdfConfig.memory;
|
||||
jsonDoc.kdfParallelism = kdfConfig.parallelism;
|
||||
}
|
||||
|
||||
return JSON.stringify(jsonDoc, null, " ");
|
||||
}
|
||||
|
||||
|
@ -1,13 +1,12 @@
|
||||
import { mock, MockProxy } from "jest-mock-extended";
|
||||
|
||||
import { KdfConfig } from "@bitwarden/common/auth/models/domain/kdf-config";
|
||||
import { KdfConfigService } from "@bitwarden/common/auth/abstractions/kdf-config.service";
|
||||
import { CipherWithIdExport } from "@bitwarden/common/models/export/cipher-with-ids.export";
|
||||
import { CryptoFunctionService } from "@bitwarden/common/platform/abstractions/crypto-function.service";
|
||||
import { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.service";
|
||||
import { KdfType, PBKDF2_ITERATIONS } from "@bitwarden/common/platform/enums";
|
||||
import { DEFAULT_KDF_CONFIG, KdfType, PBKDF2_ITERATIONS } from "@bitwarden/common/platform/enums";
|
||||
import { Utils } from "@bitwarden/common/platform/misc/utils";
|
||||
import { EncryptedString, EncString } from "@bitwarden/common/platform/models/domain/enc-string";
|
||||
import { StateService } from "@bitwarden/common/platform/services/state.service";
|
||||
import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service";
|
||||
import { FolderService } from "@bitwarden/common/vault/abstractions/folder/folder.service.abstraction";
|
||||
import { CipherType } from "@bitwarden/common/vault/enums";
|
||||
@ -110,10 +109,10 @@ function expectEqualCiphers(ciphers: CipherView[] | Cipher[], jsonResult: string
|
||||
expect(actual).toEqual(JSON.stringify(items));
|
||||
}
|
||||
|
||||
function expectEqualFolderViews(folderviews: FolderView[] | Folder[], jsonResult: string) {
|
||||
function expectEqualFolderViews(folderViews: FolderView[] | Folder[], jsonResult: string) {
|
||||
const actual = JSON.stringify(JSON.parse(jsonResult).folders);
|
||||
const folders: FolderResponse[] = [];
|
||||
folderviews.forEach((c) => {
|
||||
folderViews.forEach((c) => {
|
||||
const folder = new FolderResponse();
|
||||
folder.id = c.id;
|
||||
folder.name = c.name.toString();
|
||||
@ -144,19 +143,18 @@ describe("VaultExportService", () => {
|
||||
let cipherService: MockProxy<CipherService>;
|
||||
let folderService: MockProxy<FolderService>;
|
||||
let cryptoService: MockProxy<CryptoService>;
|
||||
let stateService: MockProxy<StateService>;
|
||||
let kdfConfigService: MockProxy<KdfConfigService>;
|
||||
|
||||
beforeEach(() => {
|
||||
cryptoFunctionService = mock<CryptoFunctionService>();
|
||||
cipherService = mock<CipherService>();
|
||||
folderService = mock<FolderService>();
|
||||
cryptoService = mock<CryptoService>();
|
||||
stateService = mock<StateService>();
|
||||
kdfConfigService = mock<KdfConfigService>();
|
||||
|
||||
folderService.getAllDecryptedFromState.mockResolvedValue(UserFolderViews);
|
||||
folderService.getAllFromState.mockResolvedValue(UserFolders);
|
||||
stateService.getKdfType.mockResolvedValue(KdfType.PBKDF2_SHA256);
|
||||
stateService.getKdfConfig.mockResolvedValue(new KdfConfig(PBKDF2_ITERATIONS.defaultValue));
|
||||
kdfConfigService.getKdfConfig.mockResolvedValue(DEFAULT_KDF_CONFIG);
|
||||
cryptoService.encrypt.mockResolvedValue(new EncString("encrypted"));
|
||||
|
||||
exportService = new IndividualVaultExportService(
|
||||
@ -164,7 +162,7 @@ describe("VaultExportService", () => {
|
||||
cipherService,
|
||||
cryptoService,
|
||||
cryptoFunctionService,
|
||||
stateService,
|
||||
kdfConfigService,
|
||||
);
|
||||
});
|
||||
|
||||
|
@ -1,9 +1,9 @@
|
||||
import * as papa from "papaparse";
|
||||
|
||||
import { KdfConfigService } from "@bitwarden/common/auth/abstractions/kdf-config.service";
|
||||
import { CipherWithIdExport, FolderWithIdExport } from "@bitwarden/common/models/export";
|
||||
import { CryptoFunctionService } from "@bitwarden/common/platform/abstractions/crypto-function.service";
|
||||
import { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.service";
|
||||
import { StateService } from "@bitwarden/common/platform/abstractions/state.service";
|
||||
import { Utils } from "@bitwarden/common/platform/misc/utils";
|
||||
import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service";
|
||||
import { FolderService } from "@bitwarden/common/vault/abstractions/folder/folder.service.abstraction";
|
||||
@ -32,9 +32,9 @@ export class IndividualVaultExportService
|
||||
private cipherService: CipherService,
|
||||
cryptoService: CryptoService,
|
||||
cryptoFunctionService: CryptoFunctionService,
|
||||
stateService: StateService,
|
||||
kdfConfigService: KdfConfigService,
|
||||
) {
|
||||
super(cryptoService, cryptoFunctionService, stateService);
|
||||
super(cryptoService, cryptoFunctionService, kdfConfigService);
|
||||
}
|
||||
|
||||
async getExport(format: ExportFormat = "csv"): Promise<string> {
|
||||
|
@ -1,10 +1,10 @@
|
||||
import * as papa from "papaparse";
|
||||
|
||||
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
||||
import { KdfConfigService } from "@bitwarden/common/auth/abstractions/kdf-config.service";
|
||||
import { CipherWithIdExport, CollectionWithIdExport } from "@bitwarden/common/models/export";
|
||||
import { CryptoFunctionService } from "@bitwarden/common/platform/abstractions/crypto-function.service";
|
||||
import { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.service";
|
||||
import { StateService } from "@bitwarden/common/platform/abstractions/state.service";
|
||||
import { Utils } from "@bitwarden/common/platform/misc/utils";
|
||||
import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service";
|
||||
import { CollectionService } from "@bitwarden/common/vault/abstractions/collection.service";
|
||||
@ -36,10 +36,10 @@ export class OrganizationVaultExportService
|
||||
private apiService: ApiService,
|
||||
cryptoService: CryptoService,
|
||||
cryptoFunctionService: CryptoFunctionService,
|
||||
stateService: StateService,
|
||||
private collectionService: CollectionService,
|
||||
kdfConfigService: KdfConfigService,
|
||||
) {
|
||||
super(cryptoService, cryptoFunctionService, stateService);
|
||||
super(cryptoService, cryptoFunctionService, kdfConfigService);
|
||||
}
|
||||
|
||||
async getPasswordProtectedExport(
|
||||
|
@ -1,13 +1,12 @@
|
||||
import { mock, MockProxy } from "jest-mock-extended";
|
||||
|
||||
import { KdfConfig } from "@bitwarden/common/auth/models/domain/kdf-config";
|
||||
import { KdfConfigService } from "@bitwarden/common/auth/abstractions/kdf-config.service";
|
||||
import { CipherWithIdExport } from "@bitwarden/common/models/export/cipher-with-ids.export";
|
||||
import { CryptoFunctionService } from "@bitwarden/common/platform/abstractions/crypto-function.service";
|
||||
import { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.service";
|
||||
import { KdfType, PBKDF2_ITERATIONS } from "@bitwarden/common/platform/enums";
|
||||
import { DEFAULT_KDF_CONFIG, KdfType, PBKDF2_ITERATIONS } from "@bitwarden/common/platform/enums";
|
||||
import { Utils } from "@bitwarden/common/platform/misc/utils";
|
||||
import { EncryptedString, EncString } from "@bitwarden/common/platform/models/domain/enc-string";
|
||||
import { StateService } from "@bitwarden/common/platform/services/state.service";
|
||||
import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service";
|
||||
import { FolderService } from "@bitwarden/common/vault/abstractions/folder/folder.service.abstraction";
|
||||
import { CipherType } from "@bitwarden/common/vault/enums";
|
||||
@ -110,10 +109,10 @@ function expectEqualCiphers(ciphers: CipherView[] | Cipher[], jsonResult: string
|
||||
expect(actual).toEqual(JSON.stringify(items));
|
||||
}
|
||||
|
||||
function expectEqualFolderViews(folderviews: FolderView[] | Folder[], jsonResult: string) {
|
||||
function expectEqualFolderViews(folderViews: FolderView[] | Folder[], jsonResult: string) {
|
||||
const actual = JSON.stringify(JSON.parse(jsonResult).folders);
|
||||
const folders: FolderResponse[] = [];
|
||||
folderviews.forEach((c) => {
|
||||
folderViews.forEach((c) => {
|
||||
const folder = new FolderResponse();
|
||||
folder.id = c.id;
|
||||
folder.name = c.name.toString();
|
||||
@ -144,19 +143,18 @@ describe("VaultExportService", () => {
|
||||
let cipherService: MockProxy<CipherService>;
|
||||
let folderService: MockProxy<FolderService>;
|
||||
let cryptoService: MockProxy<CryptoService>;
|
||||
let stateService: MockProxy<StateService>;
|
||||
let kdfConfigService: MockProxy<KdfConfigService>;
|
||||
|
||||
beforeEach(() => {
|
||||
cryptoFunctionService = mock<CryptoFunctionService>();
|
||||
cipherService = mock<CipherService>();
|
||||
folderService = mock<FolderService>();
|
||||
cryptoService = mock<CryptoService>();
|
||||
stateService = mock<StateService>();
|
||||
kdfConfigService = mock<KdfConfigService>();
|
||||
|
||||
folderService.getAllDecryptedFromState.mockResolvedValue(UserFolderViews);
|
||||
folderService.getAllFromState.mockResolvedValue(UserFolders);
|
||||
stateService.getKdfType.mockResolvedValue(KdfType.PBKDF2_SHA256);
|
||||
stateService.getKdfConfig.mockResolvedValue(new KdfConfig(PBKDF2_ITERATIONS.defaultValue));
|
||||
kdfConfigService.getKdfConfig.mockResolvedValue(DEFAULT_KDF_CONFIG);
|
||||
cryptoService.encrypt.mockResolvedValue(new EncString("encrypted"));
|
||||
|
||||
exportService = new IndividualVaultExportService(
|
||||
@ -164,7 +162,7 @@ describe("VaultExportService", () => {
|
||||
cipherService,
|
||||
cryptoService,
|
||||
cryptoFunctionService,
|
||||
stateService,
|
||||
kdfConfigService,
|
||||
);
|
||||
});
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user