1
0
mirror of https://github.com/bitwarden/browser synced 2025-12-17 16:53:34 +00: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:
Ike
2024-04-25 11:26:01 -07:00
committed by GitHub
parent dba910d0b9
commit 1e4158fd87
82 changed files with 896 additions and 361 deletions

View File

@@ -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();

View File

@@ -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);

View File

@@ -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());

View File

@@ -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;
}

View File

@@ -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);

View File

@@ -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);

View File

@@ -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);
});

View File

@@ -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);

View File

@@ -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);

View File

@@ -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);
}

View File

@@ -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

View File

@@ -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);

View File

@@ -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);

View File

@@ -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,
);
}
}),

View File

@@ -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,
);

View File

@@ -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") {