mirror of
https://github.com/bitwarden/browser
synced 2025-12-06 00:13:28 +00:00
This reverts commit b1abfb0a5c.
This commit is contained in:
@@ -17,21 +17,18 @@ import {
|
|||||||
FactoryOptions,
|
FactoryOptions,
|
||||||
factory,
|
factory,
|
||||||
} from "../../../platform/background/service-factories/factory-options";
|
} from "../../../platform/background/service-factories/factory-options";
|
||||||
|
|
||||||
import { accountServiceFactory, AccountServiceInitOptions } from "./account-service.factory";
|
|
||||||
import {
|
import {
|
||||||
internalMasterPasswordServiceFactory,
|
stateServiceFactory,
|
||||||
MasterPasswordServiceInitOptions,
|
StateServiceInitOptions,
|
||||||
} from "./master-password-service.factory";
|
} from "../../../platform/background/service-factories/state-service.factory";
|
||||||
|
|
||||||
type AuthRequestServiceFactoryOptions = FactoryOptions;
|
type AuthRequestServiceFactoryOptions = FactoryOptions;
|
||||||
|
|
||||||
export type AuthRequestServiceInitOptions = AuthRequestServiceFactoryOptions &
|
export type AuthRequestServiceInitOptions = AuthRequestServiceFactoryOptions &
|
||||||
AppIdServiceInitOptions &
|
AppIdServiceInitOptions &
|
||||||
AccountServiceInitOptions &
|
|
||||||
MasterPasswordServiceInitOptions &
|
|
||||||
CryptoServiceInitOptions &
|
CryptoServiceInitOptions &
|
||||||
ApiServiceInitOptions;
|
ApiServiceInitOptions &
|
||||||
|
StateServiceInitOptions;
|
||||||
|
|
||||||
export function authRequestServiceFactory(
|
export function authRequestServiceFactory(
|
||||||
cache: { authRequestService?: AuthRequestServiceAbstraction } & CachedServices,
|
cache: { authRequestService?: AuthRequestServiceAbstraction } & CachedServices,
|
||||||
@@ -44,10 +41,9 @@ export function authRequestServiceFactory(
|
|||||||
async () =>
|
async () =>
|
||||||
new AuthRequestService(
|
new AuthRequestService(
|
||||||
await appIdServiceFactory(cache, opts),
|
await appIdServiceFactory(cache, opts),
|
||||||
await accountServiceFactory(cache, opts),
|
|
||||||
await internalMasterPasswordServiceFactory(cache, opts),
|
|
||||||
await cryptoServiceFactory(cache, opts),
|
await cryptoServiceFactory(cache, opts),
|
||||||
await apiServiceFactory(cache, opts),
|
await apiServiceFactory(cache, opts),
|
||||||
|
await stateServiceFactory(cache, opts),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,11 +31,6 @@ import {
|
|||||||
StateProviderInitOptions,
|
StateProviderInitOptions,
|
||||||
} from "../../../platform/background/service-factories/state-provider.factory";
|
} from "../../../platform/background/service-factories/state-provider.factory";
|
||||||
|
|
||||||
import { accountServiceFactory, AccountServiceInitOptions } from "./account-service.factory";
|
|
||||||
import {
|
|
||||||
internalMasterPasswordServiceFactory,
|
|
||||||
MasterPasswordServiceInitOptions,
|
|
||||||
} from "./master-password-service.factory";
|
|
||||||
import { TokenServiceInitOptions, tokenServiceFactory } from "./token-service.factory";
|
import { TokenServiceInitOptions, tokenServiceFactory } from "./token-service.factory";
|
||||||
|
|
||||||
type KeyConnectorServiceFactoryOptions = FactoryOptions & {
|
type KeyConnectorServiceFactoryOptions = FactoryOptions & {
|
||||||
@@ -45,8 +40,6 @@ type KeyConnectorServiceFactoryOptions = FactoryOptions & {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export type KeyConnectorServiceInitOptions = KeyConnectorServiceFactoryOptions &
|
export type KeyConnectorServiceInitOptions = KeyConnectorServiceFactoryOptions &
|
||||||
AccountServiceInitOptions &
|
|
||||||
MasterPasswordServiceInitOptions &
|
|
||||||
CryptoServiceInitOptions &
|
CryptoServiceInitOptions &
|
||||||
ApiServiceInitOptions &
|
ApiServiceInitOptions &
|
||||||
TokenServiceInitOptions &
|
TokenServiceInitOptions &
|
||||||
@@ -65,8 +58,6 @@ export function keyConnectorServiceFactory(
|
|||||||
opts,
|
opts,
|
||||||
async () =>
|
async () =>
|
||||||
new KeyConnectorService(
|
new KeyConnectorService(
|
||||||
await accountServiceFactory(cache, opts),
|
|
||||||
await internalMasterPasswordServiceFactory(cache, opts),
|
|
||||||
await cryptoServiceFactory(cache, opts),
|
await cryptoServiceFactory(cache, opts),
|
||||||
await apiServiceFactory(cache, opts),
|
await apiServiceFactory(cache, opts),
|
||||||
await tokenServiceFactory(cache, opts),
|
await tokenServiceFactory(cache, opts),
|
||||||
|
|||||||
@@ -59,7 +59,6 @@ import {
|
|||||||
PasswordStrengthServiceInitOptions,
|
PasswordStrengthServiceInitOptions,
|
||||||
} from "../../../tools/background/service_factories/password-strength-service.factory";
|
} from "../../../tools/background/service_factories/password-strength-service.factory";
|
||||||
|
|
||||||
import { accountServiceFactory, AccountServiceInitOptions } from "./account-service.factory";
|
|
||||||
import {
|
import {
|
||||||
authRequestServiceFactory,
|
authRequestServiceFactory,
|
||||||
AuthRequestServiceInitOptions,
|
AuthRequestServiceInitOptions,
|
||||||
@@ -72,10 +71,6 @@ import {
|
|||||||
keyConnectorServiceFactory,
|
keyConnectorServiceFactory,
|
||||||
KeyConnectorServiceInitOptions,
|
KeyConnectorServiceInitOptions,
|
||||||
} from "./key-connector-service.factory";
|
} from "./key-connector-service.factory";
|
||||||
import {
|
|
||||||
internalMasterPasswordServiceFactory,
|
|
||||||
MasterPasswordServiceInitOptions,
|
|
||||||
} from "./master-password-service.factory";
|
|
||||||
import { tokenServiceFactory, TokenServiceInitOptions } from "./token-service.factory";
|
import { tokenServiceFactory, TokenServiceInitOptions } from "./token-service.factory";
|
||||||
import { twoFactorServiceFactory, TwoFactorServiceInitOptions } from "./two-factor-service.factory";
|
import { twoFactorServiceFactory, TwoFactorServiceInitOptions } from "./two-factor-service.factory";
|
||||||
import {
|
import {
|
||||||
@@ -86,8 +81,6 @@ import {
|
|||||||
type LoginStrategyServiceFactoryOptions = FactoryOptions;
|
type LoginStrategyServiceFactoryOptions = FactoryOptions;
|
||||||
|
|
||||||
export type LoginStrategyServiceInitOptions = LoginStrategyServiceFactoryOptions &
|
export type LoginStrategyServiceInitOptions = LoginStrategyServiceFactoryOptions &
|
||||||
AccountServiceInitOptions &
|
|
||||||
MasterPasswordServiceInitOptions &
|
|
||||||
CryptoServiceInitOptions &
|
CryptoServiceInitOptions &
|
||||||
ApiServiceInitOptions &
|
ApiServiceInitOptions &
|
||||||
TokenServiceInitOptions &
|
TokenServiceInitOptions &
|
||||||
@@ -118,8 +111,6 @@ export function loginStrategyServiceFactory(
|
|||||||
opts,
|
opts,
|
||||||
async () =>
|
async () =>
|
||||||
new LoginStrategyService(
|
new LoginStrategyService(
|
||||||
await accountServiceFactory(cache, opts),
|
|
||||||
await internalMasterPasswordServiceFactory(cache, opts),
|
|
||||||
await cryptoServiceFactory(cache, opts),
|
await cryptoServiceFactory(cache, opts),
|
||||||
await apiServiceFactory(cache, opts),
|
await apiServiceFactory(cache, opts),
|
||||||
await tokenServiceFactory(cache, opts),
|
await tokenServiceFactory(cache, opts),
|
||||||
|
|||||||
@@ -1,42 +0,0 @@
|
|||||||
import {
|
|
||||||
InternalMasterPasswordServiceAbstraction,
|
|
||||||
MasterPasswordServiceAbstraction,
|
|
||||||
} from "@bitwarden/common/auth/abstractions/master-password.service.abstraction";
|
|
||||||
import { MasterPasswordService } from "@bitwarden/common/auth/services/master-password/master-password.service";
|
|
||||||
|
|
||||||
import {
|
|
||||||
CachedServices,
|
|
||||||
factory,
|
|
||||||
FactoryOptions,
|
|
||||||
} from "../../../platform/background/service-factories/factory-options";
|
|
||||||
import {
|
|
||||||
stateProviderFactory,
|
|
||||||
StateProviderInitOptions,
|
|
||||||
} from "../../../platform/background/service-factories/state-provider.factory";
|
|
||||||
|
|
||||||
type MasterPasswordServiceFactoryOptions = FactoryOptions;
|
|
||||||
|
|
||||||
export type MasterPasswordServiceInitOptions = MasterPasswordServiceFactoryOptions &
|
|
||||||
StateProviderInitOptions;
|
|
||||||
|
|
||||||
export function internalMasterPasswordServiceFactory(
|
|
||||||
cache: { masterPasswordService?: InternalMasterPasswordServiceAbstraction } & CachedServices,
|
|
||||||
opts: MasterPasswordServiceInitOptions,
|
|
||||||
): Promise<InternalMasterPasswordServiceAbstraction> {
|
|
||||||
return factory(
|
|
||||||
cache,
|
|
||||||
"masterPasswordService",
|
|
||||||
opts,
|
|
||||||
async () => new MasterPasswordService(await stateProviderFactory(cache, opts)),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function masterPasswordServiceFactory(
|
|
||||||
cache: { masterPasswordService?: InternalMasterPasswordServiceAbstraction } & CachedServices,
|
|
||||||
opts: MasterPasswordServiceInitOptions,
|
|
||||||
): Promise<MasterPasswordServiceAbstraction> {
|
|
||||||
return (await internalMasterPasswordServiceFactory(
|
|
||||||
cache,
|
|
||||||
opts,
|
|
||||||
)) as MasterPasswordServiceAbstraction;
|
|
||||||
}
|
|
||||||
@@ -31,11 +31,6 @@ import {
|
|||||||
stateServiceFactory,
|
stateServiceFactory,
|
||||||
} from "../../../platform/background/service-factories/state-service.factory";
|
} from "../../../platform/background/service-factories/state-service.factory";
|
||||||
|
|
||||||
import { accountServiceFactory, AccountServiceInitOptions } from "./account-service.factory";
|
|
||||||
import {
|
|
||||||
internalMasterPasswordServiceFactory,
|
|
||||||
MasterPasswordServiceInitOptions,
|
|
||||||
} from "./master-password-service.factory";
|
|
||||||
import { PinCryptoServiceInitOptions, pinCryptoServiceFactory } from "./pin-crypto-service.factory";
|
import { PinCryptoServiceInitOptions, pinCryptoServiceFactory } from "./pin-crypto-service.factory";
|
||||||
import {
|
import {
|
||||||
userDecryptionOptionsServiceFactory,
|
userDecryptionOptionsServiceFactory,
|
||||||
@@ -51,8 +46,6 @@ type UserVerificationServiceFactoryOptions = FactoryOptions;
|
|||||||
export type UserVerificationServiceInitOptions = UserVerificationServiceFactoryOptions &
|
export type UserVerificationServiceInitOptions = UserVerificationServiceFactoryOptions &
|
||||||
StateServiceInitOptions &
|
StateServiceInitOptions &
|
||||||
CryptoServiceInitOptions &
|
CryptoServiceInitOptions &
|
||||||
AccountServiceInitOptions &
|
|
||||||
MasterPasswordServiceInitOptions &
|
|
||||||
I18nServiceInitOptions &
|
I18nServiceInitOptions &
|
||||||
UserVerificationApiServiceInitOptions &
|
UserVerificationApiServiceInitOptions &
|
||||||
UserDecryptionOptionsServiceInitOptions &
|
UserDecryptionOptionsServiceInitOptions &
|
||||||
@@ -73,8 +66,6 @@ export function userVerificationServiceFactory(
|
|||||||
new UserVerificationService(
|
new UserVerificationService(
|
||||||
await stateServiceFactory(cache, opts),
|
await stateServiceFactory(cache, opts),
|
||||||
await cryptoServiceFactory(cache, opts),
|
await cryptoServiceFactory(cache, opts),
|
||||||
await accountServiceFactory(cache, opts),
|
|
||||||
await internalMasterPasswordServiceFactory(cache, opts),
|
|
||||||
await i18nServiceFactory(cache, opts),
|
await i18nServiceFactory(cache, opts),
|
||||||
await userVerificationApiServiceFactory(cache, opts),
|
await userVerificationApiServiceFactory(cache, opts),
|
||||||
await userDecryptionOptionsServiceFactory(cache, opts),
|
await userDecryptionOptionsServiceFactory(cache, opts),
|
||||||
|
|||||||
@@ -12,7 +12,6 @@ import { InternalPolicyService } from "@bitwarden/common/admin-console/abstracti
|
|||||||
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
||||||
import { AuthService } from "@bitwarden/common/auth/abstractions/auth.service";
|
import { AuthService } from "@bitwarden/common/auth/abstractions/auth.service";
|
||||||
import { DeviceTrustCryptoServiceAbstraction } from "@bitwarden/common/auth/abstractions/device-trust-crypto.service.abstraction";
|
import { DeviceTrustCryptoServiceAbstraction } from "@bitwarden/common/auth/abstractions/device-trust-crypto.service.abstraction";
|
||||||
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 { UserVerificationService } from "@bitwarden/common/auth/abstractions/user-verification/user-verification.service.abstraction";
|
||||||
import { AuthenticationStatus } from "@bitwarden/common/auth/enums/authentication-status";
|
import { AuthenticationStatus } from "@bitwarden/common/auth/enums/authentication-status";
|
||||||
import { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.service";
|
import { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.service";
|
||||||
@@ -42,7 +41,6 @@ export class LockComponent extends BaseLockComponent {
|
|||||||
fido2PopoutSessionData$ = fido2PopoutSessionData$();
|
fido2PopoutSessionData$ = fido2PopoutSessionData$();
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
masterPasswordService: InternalMasterPasswordServiceAbstraction,
|
|
||||||
router: Router,
|
router: Router,
|
||||||
i18nService: I18nService,
|
i18nService: I18nService,
|
||||||
platformUtilsService: PlatformUtilsService,
|
platformUtilsService: PlatformUtilsService,
|
||||||
@@ -68,7 +66,6 @@ export class LockComponent extends BaseLockComponent {
|
|||||||
accountService: AccountService,
|
accountService: AccountService,
|
||||||
) {
|
) {
|
||||||
super(
|
super(
|
||||||
masterPasswordService,
|
|
||||||
router,
|
router,
|
||||||
i18nService,
|
i18nService,
|
||||||
platformUtilsService,
|
platformUtilsService,
|
||||||
|
|||||||
@@ -1,9 +1,65 @@
|
|||||||
import { Component } from "@angular/core";
|
import { Component } from "@angular/core";
|
||||||
|
import { ActivatedRoute, Router } from "@angular/router";
|
||||||
|
|
||||||
import { SetPasswordComponent as BaseSetPasswordComponent } from "@bitwarden/angular/auth/components/set-password.component";
|
import { SetPasswordComponent as BaseSetPasswordComponent } from "@bitwarden/angular/auth/components/set-password.component";
|
||||||
|
import { InternalUserDecryptionOptionsServiceAbstraction } from "@bitwarden/auth/common";
|
||||||
|
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
||||||
|
import { OrganizationApiServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/organization/organization-api.service.abstraction";
|
||||||
|
import { OrganizationUserService } from "@bitwarden/common/admin-console/abstractions/organization-user/organization-user.service";
|
||||||
|
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 { SsoLoginServiceAbstraction } from "@bitwarden/common/auth/abstractions/sso-login.service.abstraction";
|
||||||
|
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 { PasswordGenerationServiceAbstraction } from "@bitwarden/common/tools/generator/password";
|
||||||
|
import { SyncService } from "@bitwarden/common/vault/abstractions/sync/sync.service.abstraction";
|
||||||
|
import { DialogService } from "@bitwarden/components";
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: "app-set-password",
|
selector: "app-set-password",
|
||||||
templateUrl: "set-password.component.html",
|
templateUrl: "set-password.component.html",
|
||||||
})
|
})
|
||||||
export class SetPasswordComponent extends BaseSetPasswordComponent {}
|
export class SetPasswordComponent extends BaseSetPasswordComponent {
|
||||||
|
constructor(
|
||||||
|
apiService: ApiService,
|
||||||
|
i18nService: I18nService,
|
||||||
|
cryptoService: CryptoService,
|
||||||
|
messagingService: MessagingService,
|
||||||
|
stateService: StateService,
|
||||||
|
passwordGenerationService: PasswordGenerationServiceAbstraction,
|
||||||
|
platformUtilsService: PlatformUtilsService,
|
||||||
|
policyApiService: PolicyApiServiceAbstraction,
|
||||||
|
policyService: PolicyService,
|
||||||
|
router: Router,
|
||||||
|
syncService: SyncService,
|
||||||
|
route: ActivatedRoute,
|
||||||
|
organizationApiService: OrganizationApiServiceAbstraction,
|
||||||
|
organizationUserService: OrganizationUserService,
|
||||||
|
userDecryptionOptionsService: InternalUserDecryptionOptionsServiceAbstraction,
|
||||||
|
ssoLoginService: SsoLoginServiceAbstraction,
|
||||||
|
dialogService: DialogService,
|
||||||
|
) {
|
||||||
|
super(
|
||||||
|
i18nService,
|
||||||
|
cryptoService,
|
||||||
|
messagingService,
|
||||||
|
passwordGenerationService,
|
||||||
|
platformUtilsService,
|
||||||
|
policyApiService,
|
||||||
|
policyService,
|
||||||
|
router,
|
||||||
|
apiService,
|
||||||
|
syncService,
|
||||||
|
route,
|
||||||
|
stateService,
|
||||||
|
organizationApiService,
|
||||||
|
organizationUserService,
|
||||||
|
userDecryptionOptionsService,
|
||||||
|
ssoLoginService,
|
||||||
|
dialogService,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -9,9 +9,7 @@ import {
|
|||||||
UserDecryptionOptionsServiceAbstraction,
|
UserDecryptionOptionsServiceAbstraction,
|
||||||
} from "@bitwarden/auth/common";
|
} from "@bitwarden/auth/common";
|
||||||
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
||||||
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
|
||||||
import { AuthService } from "@bitwarden/common/auth/abstractions/auth.service";
|
import { AuthService } from "@bitwarden/common/auth/abstractions/auth.service";
|
||||||
import { InternalMasterPasswordServiceAbstraction } from "@bitwarden/common/auth/abstractions/master-password.service.abstraction";
|
|
||||||
import { SsoLoginServiceAbstraction } from "@bitwarden/common/auth/abstractions/sso-login.service.abstraction";
|
import { SsoLoginServiceAbstraction } from "@bitwarden/common/auth/abstractions/sso-login.service.abstraction";
|
||||||
import { AuthenticationStatus } from "@bitwarden/common/auth/enums/authentication-status";
|
import { AuthenticationStatus } from "@bitwarden/common/auth/enums/authentication-status";
|
||||||
import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service";
|
import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service";
|
||||||
@@ -47,9 +45,7 @@ export class SsoComponent extends BaseSsoComponent {
|
|||||||
logService: LogService,
|
logService: LogService,
|
||||||
userDecryptionOptionsService: UserDecryptionOptionsServiceAbstraction,
|
userDecryptionOptionsService: UserDecryptionOptionsServiceAbstraction,
|
||||||
configService: ConfigService,
|
configService: ConfigService,
|
||||||
masterPasswordService: InternalMasterPasswordServiceAbstraction,
|
protected authService: AuthService,
|
||||||
accountService: AccountService,
|
|
||||||
private authService: AuthService,
|
|
||||||
@Inject(WINDOW) private win: Window,
|
@Inject(WINDOW) private win: Window,
|
||||||
) {
|
) {
|
||||||
super(
|
super(
|
||||||
@@ -67,8 +63,6 @@ export class SsoComponent extends BaseSsoComponent {
|
|||||||
logService,
|
logService,
|
||||||
userDecryptionOptionsService,
|
userDecryptionOptionsService,
|
||||||
configService,
|
configService,
|
||||||
masterPasswordService,
|
|
||||||
accountService,
|
|
||||||
);
|
);
|
||||||
|
|
||||||
environmentService.environment$.pipe(takeUntilDestroyed()).subscribe((env) => {
|
environmentService.environment$.pipe(takeUntilDestroyed()).subscribe((env) => {
|
||||||
|
|||||||
@@ -11,8 +11,6 @@ import {
|
|||||||
UserDecryptionOptionsServiceAbstraction,
|
UserDecryptionOptionsServiceAbstraction,
|
||||||
} from "@bitwarden/auth/common";
|
} from "@bitwarden/auth/common";
|
||||||
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
||||||
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
|
||||||
import { InternalMasterPasswordServiceAbstraction } from "@bitwarden/common/auth/abstractions/master-password.service.abstraction";
|
|
||||||
import { SsoLoginServiceAbstraction } from "@bitwarden/common/auth/abstractions/sso-login.service.abstraction";
|
import { SsoLoginServiceAbstraction } from "@bitwarden/common/auth/abstractions/sso-login.service.abstraction";
|
||||||
import { TwoFactorService } from "@bitwarden/common/auth/abstractions/two-factor.service";
|
import { TwoFactorService } from "@bitwarden/common/auth/abstractions/two-factor.service";
|
||||||
import { TwoFactorProviderType } from "@bitwarden/common/auth/enums/two-factor-provider-type";
|
import { TwoFactorProviderType } from "@bitwarden/common/auth/enums/two-factor-provider-type";
|
||||||
@@ -64,8 +62,6 @@ export class TwoFactorComponent extends BaseTwoFactorComponent {
|
|||||||
configService: ConfigService,
|
configService: ConfigService,
|
||||||
ssoLoginService: SsoLoginServiceAbstraction,
|
ssoLoginService: SsoLoginServiceAbstraction,
|
||||||
private dialogService: DialogService,
|
private dialogService: DialogService,
|
||||||
masterPasswordService: InternalMasterPasswordServiceAbstraction,
|
|
||||||
accountService: AccountService,
|
|
||||||
@Inject(WINDOW) protected win: Window,
|
@Inject(WINDOW) protected win: Window,
|
||||||
private browserMessagingApi: ZonedMessageListenerService,
|
private browserMessagingApi: ZonedMessageListenerService,
|
||||||
) {
|
) {
|
||||||
@@ -86,8 +82,6 @@ export class TwoFactorComponent extends BaseTwoFactorComponent {
|
|||||||
userDecryptionOptionsService,
|
userDecryptionOptionsService,
|
||||||
ssoLoginService,
|
ssoLoginService,
|
||||||
configService,
|
configService,
|
||||||
masterPasswordService,
|
|
||||||
accountService,
|
|
||||||
);
|
);
|
||||||
super.onSuccessfulLogin = async () => {
|
super.onSuccessfulLogin = async () => {
|
||||||
// FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling.
|
// FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling.
|
||||||
|
|||||||
@@ -32,7 +32,6 @@ import { DeviceTrustCryptoServiceAbstraction } from "@bitwarden/common/auth/abst
|
|||||||
import { DevicesServiceAbstraction } from "@bitwarden/common/auth/abstractions/devices/devices.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 { DevicesApiServiceAbstraction } from "@bitwarden/common/auth/abstractions/devices-api.service.abstraction";
|
||||||
import { KeyConnectorService as KeyConnectorServiceAbstraction } from "@bitwarden/common/auth/abstractions/key-connector.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";
|
import { SsoLoginServiceAbstraction } from "@bitwarden/common/auth/abstractions/sso-login.service.abstraction";
|
||||||
import { TokenService as TokenServiceAbstraction } from "@bitwarden/common/auth/abstractions/token.service";
|
import { TokenService as TokenServiceAbstraction } from "@bitwarden/common/auth/abstractions/token.service";
|
||||||
import { TwoFactorService as TwoFactorServiceAbstraction } from "@bitwarden/common/auth/abstractions/two-factor.service";
|
import { TwoFactorService as TwoFactorServiceAbstraction } from "@bitwarden/common/auth/abstractions/two-factor.service";
|
||||||
@@ -47,7 +46,6 @@ import { DeviceTrustCryptoService } from "@bitwarden/common/auth/services/device
|
|||||||
import { DevicesServiceImplementation } from "@bitwarden/common/auth/services/devices/devices.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 { DevicesApiServiceImplementation } from "@bitwarden/common/auth/services/devices-api.service.implementation";
|
||||||
import { KeyConnectorService } from "@bitwarden/common/auth/services/key-connector.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";
|
import { SsoLoginService } from "@bitwarden/common/auth/services/sso-login.service";
|
||||||
import { TokenService } from "@bitwarden/common/auth/services/token.service";
|
import { TokenService } from "@bitwarden/common/auth/services/token.service";
|
||||||
import { TwoFactorService } from "@bitwarden/common/auth/services/two-factor.service";
|
import { TwoFactorService } from "@bitwarden/common/auth/services/two-factor.service";
|
||||||
@@ -244,7 +242,6 @@ export default class MainBackground {
|
|||||||
keyGenerationService: KeyGenerationServiceAbstraction;
|
keyGenerationService: KeyGenerationServiceAbstraction;
|
||||||
cryptoService: CryptoServiceAbstraction;
|
cryptoService: CryptoServiceAbstraction;
|
||||||
cryptoFunctionService: CryptoFunctionServiceAbstraction;
|
cryptoFunctionService: CryptoFunctionServiceAbstraction;
|
||||||
masterPasswordService: InternalMasterPasswordServiceAbstraction;
|
|
||||||
tokenService: TokenServiceAbstraction;
|
tokenService: TokenServiceAbstraction;
|
||||||
appIdService: AppIdServiceAbstraction;
|
appIdService: AppIdServiceAbstraction;
|
||||||
apiService: ApiServiceAbstraction;
|
apiService: ApiServiceAbstraction;
|
||||||
@@ -483,11 +480,8 @@ export default class MainBackground {
|
|||||||
|
|
||||||
const themeStateService = new DefaultThemeStateService(this.globalStateProvider);
|
const themeStateService = new DefaultThemeStateService(this.globalStateProvider);
|
||||||
|
|
||||||
this.masterPasswordService = new MasterPasswordService(this.stateProvider);
|
|
||||||
|
|
||||||
this.i18nService = new I18nService(BrowserApi.getUILanguage(), this.globalStateProvider);
|
this.i18nService = new I18nService(BrowserApi.getUILanguage(), this.globalStateProvider);
|
||||||
this.cryptoService = new BrowserCryptoService(
|
this.cryptoService = new BrowserCryptoService(
|
||||||
this.masterPasswordService,
|
|
||||||
this.keyGenerationService,
|
this.keyGenerationService,
|
||||||
this.cryptoFunctionService,
|
this.cryptoFunctionService,
|
||||||
this.encryptService,
|
this.encryptService,
|
||||||
@@ -531,8 +525,6 @@ export default class MainBackground {
|
|||||||
this.badgeSettingsService = new BadgeSettingsService(this.stateProvider);
|
this.badgeSettingsService = new BadgeSettingsService(this.stateProvider);
|
||||||
this.policyApiService = new PolicyApiService(this.policyService, this.apiService);
|
this.policyApiService = new PolicyApiService(this.policyService, this.apiService);
|
||||||
this.keyConnectorService = new KeyConnectorService(
|
this.keyConnectorService = new KeyConnectorService(
|
||||||
this.accountService,
|
|
||||||
this.masterPasswordService,
|
|
||||||
this.cryptoService,
|
this.cryptoService,
|
||||||
this.apiService,
|
this.apiService,
|
||||||
this.tokenService,
|
this.tokenService,
|
||||||
@@ -586,10 +578,9 @@ export default class MainBackground {
|
|||||||
|
|
||||||
this.authRequestService = new AuthRequestService(
|
this.authRequestService = new AuthRequestService(
|
||||||
this.appIdService,
|
this.appIdService,
|
||||||
this.accountService,
|
|
||||||
this.masterPasswordService,
|
|
||||||
this.cryptoService,
|
this.cryptoService,
|
||||||
this.apiService,
|
this.apiService,
|
||||||
|
this.stateService,
|
||||||
);
|
);
|
||||||
|
|
||||||
this.authService = new AuthService(
|
this.authService = new AuthService(
|
||||||
@@ -606,8 +597,6 @@ export default class MainBackground {
|
|||||||
);
|
);
|
||||||
|
|
||||||
this.loginStrategyService = new LoginStrategyService(
|
this.loginStrategyService = new LoginStrategyService(
|
||||||
this.accountService,
|
|
||||||
this.masterPasswordService,
|
|
||||||
this.cryptoService,
|
this.cryptoService,
|
||||||
this.apiService,
|
this.apiService,
|
||||||
this.tokenService,
|
this.tokenService,
|
||||||
@@ -683,8 +672,6 @@ export default class MainBackground {
|
|||||||
this.userVerificationService = new UserVerificationService(
|
this.userVerificationService = new UserVerificationService(
|
||||||
this.stateService,
|
this.stateService,
|
||||||
this.cryptoService,
|
this.cryptoService,
|
||||||
this.accountService,
|
|
||||||
this.masterPasswordService,
|
|
||||||
this.i18nService,
|
this.i18nService,
|
||||||
this.userVerificationApiService,
|
this.userVerificationApiService,
|
||||||
this.userDecryptionOptionsService,
|
this.userDecryptionOptionsService,
|
||||||
@@ -707,8 +694,6 @@ export default class MainBackground {
|
|||||||
this.vaultSettingsService = new VaultSettingsService(this.stateProvider);
|
this.vaultSettingsService = new VaultSettingsService(this.stateProvider);
|
||||||
|
|
||||||
this.vaultTimeoutService = new VaultTimeoutService(
|
this.vaultTimeoutService = new VaultTimeoutService(
|
||||||
this.accountService,
|
|
||||||
this.masterPasswordService,
|
|
||||||
this.cipherService,
|
this.cipherService,
|
||||||
this.folderService,
|
this.folderService,
|
||||||
this.collectionService,
|
this.collectionService,
|
||||||
@@ -744,8 +729,6 @@ export default class MainBackground {
|
|||||||
this.providerService = new ProviderService(this.stateProvider);
|
this.providerService = new ProviderService(this.stateProvider);
|
||||||
|
|
||||||
this.syncService = new SyncService(
|
this.syncService = new SyncService(
|
||||||
this.masterPasswordService,
|
|
||||||
this.accountService,
|
|
||||||
this.apiService,
|
this.apiService,
|
||||||
this.domainSettingsService,
|
this.domainSettingsService,
|
||||||
this.folderService,
|
this.folderService,
|
||||||
@@ -895,8 +878,6 @@ export default class MainBackground {
|
|||||||
this.fido2Service,
|
this.fido2Service,
|
||||||
);
|
);
|
||||||
this.nativeMessagingBackground = new NativeMessagingBackground(
|
this.nativeMessagingBackground = new NativeMessagingBackground(
|
||||||
this.accountService,
|
|
||||||
this.masterPasswordService,
|
|
||||||
this.cryptoService,
|
this.cryptoService,
|
||||||
this.cryptoFunctionService,
|
this.cryptoFunctionService,
|
||||||
this.runtimeBackground,
|
this.runtimeBackground,
|
||||||
@@ -1125,7 +1106,7 @@ export default class MainBackground {
|
|||||||
|
|
||||||
const status = await this.authService.getAuthStatus(userId);
|
const status = await this.authService.getAuthStatus(userId);
|
||||||
const forcePasswordReset =
|
const forcePasswordReset =
|
||||||
(await firstValueFrom(this.masterPasswordService.forceSetPasswordReason$(userId))) !=
|
(await this.stateService.getForceSetPasswordReason({ userId: userId })) !=
|
||||||
ForceSetPasswordReason.None;
|
ForceSetPasswordReason.None;
|
||||||
|
|
||||||
await this.systemService.clearPendingClipboard();
|
await this.systemService.clearPendingClipboard();
|
||||||
|
|||||||
@@ -1,8 +1,6 @@
|
|||||||
import { firstValueFrom } from "rxjs";
|
import { firstValueFrom } from "rxjs";
|
||||||
|
|
||||||
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
|
||||||
import { AuthService } from "@bitwarden/common/auth/abstractions/auth.service";
|
import { AuthService } from "@bitwarden/common/auth/abstractions/auth.service";
|
||||||
import { InternalMasterPasswordServiceAbstraction } from "@bitwarden/common/auth/abstractions/master-password.service.abstraction";
|
|
||||||
import { AuthenticationStatus } from "@bitwarden/common/auth/enums/authentication-status";
|
import { AuthenticationStatus } from "@bitwarden/common/auth/enums/authentication-status";
|
||||||
import { AppIdService } from "@bitwarden/common/platform/abstractions/app-id.service";
|
import { AppIdService } from "@bitwarden/common/platform/abstractions/app-id.service";
|
||||||
import { CryptoFunctionService } from "@bitwarden/common/platform/abstractions/crypto-function.service";
|
import { CryptoFunctionService } from "@bitwarden/common/platform/abstractions/crypto-function.service";
|
||||||
@@ -73,8 +71,6 @@ export class NativeMessagingBackground {
|
|||||||
private validatingFingerprint: boolean;
|
private validatingFingerprint: boolean;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private accountService: AccountService,
|
|
||||||
private masterPasswordService: InternalMasterPasswordServiceAbstraction,
|
|
||||||
private cryptoService: CryptoService,
|
private cryptoService: CryptoService,
|
||||||
private cryptoFunctionService: CryptoFunctionService,
|
private cryptoFunctionService: CryptoFunctionService,
|
||||||
private runtimeBackground: RuntimeBackground,
|
private runtimeBackground: RuntimeBackground,
|
||||||
@@ -340,14 +336,10 @@ export class NativeMessagingBackground {
|
|||||||
) as UserKey;
|
) as UserKey;
|
||||||
await this.cryptoService.setUserKey(userKey);
|
await this.cryptoService.setUserKey(userKey);
|
||||||
} else if (message.keyB64) {
|
} else if (message.keyB64) {
|
||||||
const userId = (await firstValueFrom(this.accountService.activeAccount$))?.id;
|
|
||||||
// Backwards compatibility to support cases in which the user hasn't updated their desktop app
|
// Backwards compatibility to support cases in which the user hasn't updated their desktop app
|
||||||
// TODO: Remove after 2023.10 release (https://bitwarden.atlassian.net/browse/PM-3472)
|
// TODO: Remove after 2023.10 release (https://bitwarden.atlassian.net/browse/PM-3472)
|
||||||
const encUserKeyPrim = await this.stateService.getEncryptedCryptoSymmetricKey();
|
let encUserKey = await this.stateService.getEncryptedCryptoSymmetricKey();
|
||||||
const encUserKey =
|
encUserKey ||= await this.stateService.getMasterKeyEncryptedUserKey();
|
||||||
encUserKeyPrim != null
|
|
||||||
? new EncString(encUserKeyPrim)
|
|
||||||
: await this.masterPasswordService.getMasterKeyEncryptedUserKey(userId);
|
|
||||||
if (!encUserKey) {
|
if (!encUserKey) {
|
||||||
throw new Error("No encrypted user key found");
|
throw new Error("No encrypted user key found");
|
||||||
}
|
}
|
||||||
@@ -356,9 +348,9 @@ export class NativeMessagingBackground {
|
|||||||
) as MasterKey;
|
) as MasterKey;
|
||||||
const userKey = await this.cryptoService.decryptUserKeyWithMasterKey(
|
const userKey = await this.cryptoService.decryptUserKeyWithMasterKey(
|
||||||
masterKey,
|
masterKey,
|
||||||
encUserKey,
|
new EncString(encUserKey),
|
||||||
);
|
);
|
||||||
await this.masterPasswordService.setMasterKey(masterKey, userId);
|
await this.cryptoService.setMasterKey(masterKey);
|
||||||
await this.cryptoService.setUserKey(userKey);
|
await this.cryptoService.setUserKey(userKey);
|
||||||
} else {
|
} else {
|
||||||
throw new Error("No key received");
|
throw new Error("No key received");
|
||||||
|
|||||||
@@ -1,17 +1,9 @@
|
|||||||
import { VaultTimeoutService as AbstractVaultTimeoutService } from "@bitwarden/common/abstractions/vault-timeout/vault-timeout.service";
|
import { VaultTimeoutService as AbstractVaultTimeoutService } from "@bitwarden/common/abstractions/vault-timeout/vault-timeout.service";
|
||||||
|
|
||||||
import {
|
|
||||||
accountServiceFactory,
|
|
||||||
AccountServiceInitOptions,
|
|
||||||
} from "../../auth/background/service-factories/account-service.factory";
|
|
||||||
import {
|
import {
|
||||||
authServiceFactory,
|
authServiceFactory,
|
||||||
AuthServiceInitOptions,
|
AuthServiceInitOptions,
|
||||||
} from "../../auth/background/service-factories/auth-service.factory";
|
} from "../../auth/background/service-factories/auth-service.factory";
|
||||||
import {
|
|
||||||
internalMasterPasswordServiceFactory,
|
|
||||||
MasterPasswordServiceInitOptions,
|
|
||||||
} from "../../auth/background/service-factories/master-password-service.factory";
|
|
||||||
import {
|
import {
|
||||||
CryptoServiceInitOptions,
|
CryptoServiceInitOptions,
|
||||||
cryptoServiceFactory,
|
cryptoServiceFactory,
|
||||||
@@ -65,8 +57,6 @@ type VaultTimeoutServiceFactoryOptions = FactoryOptions & {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export type VaultTimeoutServiceInitOptions = VaultTimeoutServiceFactoryOptions &
|
export type VaultTimeoutServiceInitOptions = VaultTimeoutServiceFactoryOptions &
|
||||||
AccountServiceInitOptions &
|
|
||||||
MasterPasswordServiceInitOptions &
|
|
||||||
CipherServiceInitOptions &
|
CipherServiceInitOptions &
|
||||||
FolderServiceInitOptions &
|
FolderServiceInitOptions &
|
||||||
CollectionServiceInitOptions &
|
CollectionServiceInitOptions &
|
||||||
@@ -89,8 +79,6 @@ export function vaultTimeoutServiceFactory(
|
|||||||
opts,
|
opts,
|
||||||
async () =>
|
async () =>
|
||||||
new VaultTimeoutService(
|
new VaultTimeoutService(
|
||||||
await accountServiceFactory(cache, opts),
|
|
||||||
await internalMasterPasswordServiceFactory(cache, opts),
|
|
||||||
await cipherServiceFactory(cache, opts),
|
await cipherServiceFactory(cache, opts),
|
||||||
await folderServiceFactory(cache, opts),
|
await folderServiceFactory(cache, opts),
|
||||||
await collectionServiceFactory(cache, opts),
|
await collectionServiceFactory(cache, opts),
|
||||||
|
|||||||
@@ -4,10 +4,6 @@ import {
|
|||||||
AccountServiceInitOptions,
|
AccountServiceInitOptions,
|
||||||
accountServiceFactory,
|
accountServiceFactory,
|
||||||
} from "../../../auth/background/service-factories/account-service.factory";
|
} from "../../../auth/background/service-factories/account-service.factory";
|
||||||
import {
|
|
||||||
internalMasterPasswordServiceFactory,
|
|
||||||
MasterPasswordServiceInitOptions,
|
|
||||||
} from "../../../auth/background/service-factories/master-password-service.factory";
|
|
||||||
import {
|
import {
|
||||||
StateServiceInitOptions,
|
StateServiceInitOptions,
|
||||||
stateServiceFactory,
|
stateServiceFactory,
|
||||||
@@ -38,7 +34,6 @@ import { StateProviderInitOptions, stateProviderFactory } from "./state-provider
|
|||||||
type CryptoServiceFactoryOptions = FactoryOptions;
|
type CryptoServiceFactoryOptions = FactoryOptions;
|
||||||
|
|
||||||
export type CryptoServiceInitOptions = CryptoServiceFactoryOptions &
|
export type CryptoServiceInitOptions = CryptoServiceFactoryOptions &
|
||||||
MasterPasswordServiceInitOptions &
|
|
||||||
KeyGenerationServiceInitOptions &
|
KeyGenerationServiceInitOptions &
|
||||||
CryptoFunctionServiceInitOptions &
|
CryptoFunctionServiceInitOptions &
|
||||||
EncryptServiceInitOptions &
|
EncryptServiceInitOptions &
|
||||||
@@ -58,7 +53,6 @@ export function cryptoServiceFactory(
|
|||||||
opts,
|
opts,
|
||||||
async () =>
|
async () =>
|
||||||
new BrowserCryptoService(
|
new BrowserCryptoService(
|
||||||
await internalMasterPasswordServiceFactory(cache, opts),
|
|
||||||
await keyGenerationServiceFactory(cache, opts),
|
await keyGenerationServiceFactory(cache, opts),
|
||||||
await cryptoFunctionServiceFactory(cache, opts),
|
await cryptoFunctionServiceFactory(cache, opts),
|
||||||
await encryptServiceFactory(cache, opts),
|
await encryptServiceFactory(cache, opts),
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
import { firstValueFrom } from "rxjs";
|
import { firstValueFrom } from "rxjs";
|
||||||
|
|
||||||
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
||||||
import { InternalMasterPasswordServiceAbstraction } from "@bitwarden/common/auth/abstractions/master-password.service.abstraction";
|
|
||||||
import { CryptoFunctionService } from "@bitwarden/common/platform/abstractions/crypto-function.service";
|
import { CryptoFunctionService } from "@bitwarden/common/platform/abstractions/crypto-function.service";
|
||||||
import { EncryptService } from "@bitwarden/common/platform/abstractions/encrypt.service";
|
import { EncryptService } from "@bitwarden/common/platform/abstractions/encrypt.service";
|
||||||
import { KeyGenerationService } from "@bitwarden/common/platform/abstractions/key-generation.service";
|
import { KeyGenerationService } from "@bitwarden/common/platform/abstractions/key-generation.service";
|
||||||
@@ -18,7 +17,6 @@ import { UserKey } from "@bitwarden/common/types/key";
|
|||||||
|
|
||||||
export class BrowserCryptoService extends CryptoService {
|
export class BrowserCryptoService extends CryptoService {
|
||||||
constructor(
|
constructor(
|
||||||
masterPasswordService: InternalMasterPasswordServiceAbstraction,
|
|
||||||
keyGenerationService: KeyGenerationService,
|
keyGenerationService: KeyGenerationService,
|
||||||
cryptoFunctionService: CryptoFunctionService,
|
cryptoFunctionService: CryptoFunctionService,
|
||||||
encryptService: EncryptService,
|
encryptService: EncryptService,
|
||||||
@@ -30,7 +28,6 @@ export class BrowserCryptoService extends CryptoService {
|
|||||||
private biometricStateService: BiometricStateService,
|
private biometricStateService: BiometricStateService,
|
||||||
) {
|
) {
|
||||||
super(
|
super(
|
||||||
masterPasswordService,
|
|
||||||
keyGenerationService,
|
keyGenerationService,
|
||||||
cryptoFunctionService,
|
cryptoFunctionService,
|
||||||
encryptService,
|
encryptService,
|
||||||
|
|||||||
@@ -1,10 +1,6 @@
|
|||||||
import { firstValueFrom } from "rxjs";
|
|
||||||
|
|
||||||
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
||||||
import { OrganizationApiServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/organization/organization-api.service.abstraction";
|
import { OrganizationApiServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/organization/organization-api.service.abstraction";
|
||||||
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
|
||||||
import { KeyConnectorService } from "@bitwarden/common/auth/abstractions/key-connector.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";
|
import { SecretVerificationRequest } from "@bitwarden/common/auth/models/request/secret-verification.request";
|
||||||
import { CryptoFunctionService } from "@bitwarden/common/platform/abstractions/crypto-function.service";
|
import { CryptoFunctionService } from "@bitwarden/common/platform/abstractions/crypto-function.service";
|
||||||
import { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.service";
|
import { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.service";
|
||||||
@@ -22,8 +18,6 @@ import { CliUtils } from "../../utils";
|
|||||||
|
|
||||||
export class UnlockCommand {
|
export class UnlockCommand {
|
||||||
constructor(
|
constructor(
|
||||||
private accountService: AccountService,
|
|
||||||
private masterPasswordService: InternalMasterPasswordServiceAbstraction,
|
|
||||||
private cryptoService: CryptoService,
|
private cryptoService: CryptoService,
|
||||||
private stateService: StateService,
|
private stateService: StateService,
|
||||||
private cryptoFunctionService: CryptoFunctionService,
|
private cryptoFunctionService: CryptoFunctionService,
|
||||||
@@ -51,14 +45,11 @@ export class UnlockCommand {
|
|||||||
const kdf = await this.stateService.getKdfType();
|
const kdf = await this.stateService.getKdfType();
|
||||||
const kdfConfig = await this.stateService.getKdfConfig();
|
const kdfConfig = await this.stateService.getKdfConfig();
|
||||||
const masterKey = await this.cryptoService.makeMasterKey(password, email, kdf, kdfConfig);
|
const masterKey = await this.cryptoService.makeMasterKey(password, email, kdf, kdfConfig);
|
||||||
const userId = (await firstValueFrom(this.accountService.activeAccount$))?.id;
|
const storedKeyHash = await this.cryptoService.getMasterKeyHash();
|
||||||
const storedMasterKeyHash = await firstValueFrom(
|
|
||||||
this.masterPasswordService.masterKeyHash$(userId),
|
|
||||||
);
|
|
||||||
|
|
||||||
let passwordValid = false;
|
let passwordValid = false;
|
||||||
if (masterKey != null) {
|
if (masterKey != null) {
|
||||||
if (storedMasterKeyHash != null) {
|
if (storedKeyHash != null) {
|
||||||
passwordValid = await this.cryptoService.compareAndUpdateKeyHash(password, masterKey);
|
passwordValid = await this.cryptoService.compareAndUpdateKeyHash(password, masterKey);
|
||||||
} else {
|
} else {
|
||||||
const serverKeyHash = await this.cryptoService.hashMasterKey(
|
const serverKeyHash = await this.cryptoService.hashMasterKey(
|
||||||
@@ -76,7 +67,7 @@ export class UnlockCommand {
|
|||||||
masterKey,
|
masterKey,
|
||||||
HashPurpose.LocalAuthorization,
|
HashPurpose.LocalAuthorization,
|
||||||
);
|
);
|
||||||
await this.masterPasswordService.setMasterKeyHash(localKeyHash, userId);
|
await this.cryptoService.setMasterKeyHash(localKeyHash);
|
||||||
} catch {
|
} catch {
|
||||||
// Ignore
|
// Ignore
|
||||||
}
|
}
|
||||||
@@ -84,8 +75,7 @@ export class UnlockCommand {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (passwordValid) {
|
if (passwordValid) {
|
||||||
const userId = (await firstValueFrom(this.accountService.activeAccount$))?.id;
|
await this.cryptoService.setMasterKey(masterKey);
|
||||||
await this.masterPasswordService.setMasterKey(masterKey, userId);
|
|
||||||
const userKey = await this.cryptoService.decryptUserKeyWithMasterKey(masterKey);
|
const userKey = await this.cryptoService.decryptUserKeyWithMasterKey(masterKey);
|
||||||
await this.cryptoService.setUserKey(userKey);
|
await this.cryptoService.setUserKey(userKey);
|
||||||
|
|
||||||
|
|||||||
@@ -28,7 +28,6 @@ import { AccountService } from "@bitwarden/common/auth/abstractions/account.serv
|
|||||||
import { AvatarService as AvatarServiceAbstraction } from "@bitwarden/common/auth/abstractions/avatar.service";
|
import { AvatarService as AvatarServiceAbstraction } from "@bitwarden/common/auth/abstractions/avatar.service";
|
||||||
import { DeviceTrustCryptoServiceAbstraction } from "@bitwarden/common/auth/abstractions/device-trust-crypto.service.abstraction";
|
import { DeviceTrustCryptoServiceAbstraction } from "@bitwarden/common/auth/abstractions/device-trust-crypto.service.abstraction";
|
||||||
import { DevicesApiServiceAbstraction } from "@bitwarden/common/auth/abstractions/devices-api.service.abstraction";
|
import { DevicesApiServiceAbstraction } from "@bitwarden/common/auth/abstractions/devices-api.service.abstraction";
|
||||||
import { InternalMasterPasswordServiceAbstraction } from "@bitwarden/common/auth/abstractions/master-password.service.abstraction";
|
|
||||||
import { AccountServiceImplementation } from "@bitwarden/common/auth/services/account.service";
|
import { AccountServiceImplementation } from "@bitwarden/common/auth/services/account.service";
|
||||||
import { AuthService } from "@bitwarden/common/auth/services/auth.service";
|
import { AuthService } from "@bitwarden/common/auth/services/auth.service";
|
||||||
import { AvatarService } from "@bitwarden/common/auth/services/avatar.service";
|
import { AvatarService } from "@bitwarden/common/auth/services/avatar.service";
|
||||||
@@ -169,7 +168,6 @@ export class Main {
|
|||||||
organizationUserService: OrganizationUserService;
|
organizationUserService: OrganizationUserService;
|
||||||
collectionService: CollectionService;
|
collectionService: CollectionService;
|
||||||
vaultTimeoutService: VaultTimeoutService;
|
vaultTimeoutService: VaultTimeoutService;
|
||||||
masterPasswordService: InternalMasterPasswordServiceAbstraction;
|
|
||||||
vaultTimeoutSettingsService: VaultTimeoutSettingsService;
|
vaultTimeoutSettingsService: VaultTimeoutSettingsService;
|
||||||
syncService: SyncService;
|
syncService: SyncService;
|
||||||
eventCollectionService: EventCollectionServiceAbstraction;
|
eventCollectionService: EventCollectionServiceAbstraction;
|
||||||
@@ -354,7 +352,6 @@ export class Main {
|
|||||||
);
|
);
|
||||||
|
|
||||||
this.cryptoService = new CryptoService(
|
this.cryptoService = new CryptoService(
|
||||||
this.masterPasswordService,
|
|
||||||
this.keyGenerationService,
|
this.keyGenerationService,
|
||||||
this.cryptoFunctionService,
|
this.cryptoFunctionService,
|
||||||
this.encryptService,
|
this.encryptService,
|
||||||
@@ -435,8 +432,6 @@ export class Main {
|
|||||||
this.policyApiService = new PolicyApiService(this.policyService, this.apiService);
|
this.policyApiService = new PolicyApiService(this.policyService, this.apiService);
|
||||||
|
|
||||||
this.keyConnectorService = new KeyConnectorService(
|
this.keyConnectorService = new KeyConnectorService(
|
||||||
this.accountService,
|
|
||||||
this.masterPasswordService,
|
|
||||||
this.cryptoService,
|
this.cryptoService,
|
||||||
this.apiService,
|
this.apiService,
|
||||||
this.tokenService,
|
this.tokenService,
|
||||||
@@ -476,10 +471,9 @@ export class Main {
|
|||||||
|
|
||||||
this.authRequestService = new AuthRequestService(
|
this.authRequestService = new AuthRequestService(
|
||||||
this.appIdService,
|
this.appIdService,
|
||||||
this.accountService,
|
|
||||||
this.masterPasswordService,
|
|
||||||
this.cryptoService,
|
this.cryptoService,
|
||||||
this.apiService,
|
this.apiService,
|
||||||
|
this.stateService,
|
||||||
);
|
);
|
||||||
|
|
||||||
this.billingAccountProfileStateService = new DefaultBillingAccountProfileStateService(
|
this.billingAccountProfileStateService = new DefaultBillingAccountProfileStateService(
|
||||||
@@ -487,8 +481,6 @@ export class Main {
|
|||||||
);
|
);
|
||||||
|
|
||||||
this.loginStrategyService = new LoginStrategyService(
|
this.loginStrategyService = new LoginStrategyService(
|
||||||
this.accountService,
|
|
||||||
this.masterPasswordService,
|
|
||||||
this.cryptoService,
|
this.cryptoService,
|
||||||
this.apiService,
|
this.apiService,
|
||||||
this.tokenService,
|
this.tokenService,
|
||||||
@@ -576,8 +568,6 @@ export class Main {
|
|||||||
this.userVerificationService = new UserVerificationService(
|
this.userVerificationService = new UserVerificationService(
|
||||||
this.stateService,
|
this.stateService,
|
||||||
this.cryptoService,
|
this.cryptoService,
|
||||||
this.accountService,
|
|
||||||
this.masterPasswordService,
|
|
||||||
this.i18nService,
|
this.i18nService,
|
||||||
this.userVerificationApiService,
|
this.userVerificationApiService,
|
||||||
this.userDecryptionOptionsService,
|
this.userDecryptionOptionsService,
|
||||||
@@ -588,8 +578,6 @@ export class Main {
|
|||||||
);
|
);
|
||||||
|
|
||||||
this.vaultTimeoutService = new VaultTimeoutService(
|
this.vaultTimeoutService = new VaultTimeoutService(
|
||||||
this.accountService,
|
|
||||||
this.masterPasswordService,
|
|
||||||
this.cipherService,
|
this.cipherService,
|
||||||
this.folderService,
|
this.folderService,
|
||||||
this.collectionService,
|
this.collectionService,
|
||||||
@@ -608,8 +596,6 @@ export class Main {
|
|||||||
this.avatarService = new AvatarService(this.apiService, this.stateProvider);
|
this.avatarService = new AvatarService(this.apiService, this.stateProvider);
|
||||||
|
|
||||||
this.syncService = new SyncService(
|
this.syncService = new SyncService(
|
||||||
this.masterPasswordService,
|
|
||||||
this.accountService,
|
|
||||||
this.apiService,
|
this.apiService,
|
||||||
this.domainSettingsService,
|
this.domainSettingsService,
|
||||||
this.folderService,
|
this.folderService,
|
||||||
|
|||||||
@@ -122,8 +122,6 @@ export class ServeCommand {
|
|||||||
this.shareCommand = new ShareCommand(this.main.cipherService);
|
this.shareCommand = new ShareCommand(this.main.cipherService);
|
||||||
this.lockCommand = new LockCommand(this.main.vaultTimeoutService);
|
this.lockCommand = new LockCommand(this.main.vaultTimeoutService);
|
||||||
this.unlockCommand = new UnlockCommand(
|
this.unlockCommand = new UnlockCommand(
|
||||||
this.main.accountService,
|
|
||||||
this.main.masterPasswordService,
|
|
||||||
this.main.cryptoService,
|
this.main.cryptoService,
|
||||||
this.main.stateService,
|
this.main.stateService,
|
||||||
this.main.cryptoFunctionService,
|
this.main.cryptoFunctionService,
|
||||||
|
|||||||
@@ -253,8 +253,6 @@ export class Program {
|
|||||||
if (!cmd.check) {
|
if (!cmd.check) {
|
||||||
await this.exitIfNotAuthed();
|
await this.exitIfNotAuthed();
|
||||||
const command = new UnlockCommand(
|
const command = new UnlockCommand(
|
||||||
this.main.accountService,
|
|
||||||
this.main.masterPasswordService,
|
|
||||||
this.main.cryptoService,
|
this.main.cryptoService,
|
||||||
this.main.stateService,
|
this.main.stateService,
|
||||||
this.main.cryptoFunctionService,
|
this.main.cryptoFunctionService,
|
||||||
@@ -615,8 +613,6 @@ export class Program {
|
|||||||
this.processResponse(response, true);
|
this.processResponse(response, true);
|
||||||
} else {
|
} else {
|
||||||
const command = new UnlockCommand(
|
const command = new UnlockCommand(
|
||||||
this.main.accountService,
|
|
||||||
this.main.masterPasswordService,
|
|
||||||
this.main.cryptoService,
|
this.main.cryptoService,
|
||||||
this.main.stateService,
|
this.main.stateService,
|
||||||
this.main.cryptoFunctionService,
|
this.main.cryptoFunctionService,
|
||||||
|
|||||||
@@ -26,7 +26,6 @@ import { InternalPolicyService } from "@bitwarden/common/admin-console/abstracti
|
|||||||
import { ProviderService } from "@bitwarden/common/admin-console/abstractions/provider.service";
|
import { ProviderService } from "@bitwarden/common/admin-console/abstractions/provider.service";
|
||||||
import { AuthService } from "@bitwarden/common/auth/abstractions/auth.service";
|
import { AuthService } from "@bitwarden/common/auth/abstractions/auth.service";
|
||||||
import { KeyConnectorService } from "@bitwarden/common/auth/abstractions/key-connector.service";
|
import { KeyConnectorService } from "@bitwarden/common/auth/abstractions/key-connector.service";
|
||||||
import { MasterPasswordServiceAbstraction } from "@bitwarden/common/auth/abstractions/master-password.service.abstraction";
|
|
||||||
import { UserVerificationService } from "@bitwarden/common/auth/abstractions/user-verification/user-verification.service.abstraction";
|
import { UserVerificationService } from "@bitwarden/common/auth/abstractions/user-verification/user-verification.service.abstraction";
|
||||||
import { AuthenticationStatus } from "@bitwarden/common/auth/enums/authentication-status";
|
import { AuthenticationStatus } from "@bitwarden/common/auth/enums/authentication-status";
|
||||||
import { ForceSetPasswordReason } from "@bitwarden/common/auth/models/domain/force-set-password-reason";
|
import { ForceSetPasswordReason } from "@bitwarden/common/auth/models/domain/force-set-password-reason";
|
||||||
@@ -121,7 +120,6 @@ export class AppComponent implements OnInit, OnDestroy {
|
|||||||
private accountCleanUpInProgress: { [userId: string]: boolean } = {};
|
private accountCleanUpInProgress: { [userId: string]: boolean } = {};
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private masterPasswordService: MasterPasswordServiceAbstraction,
|
|
||||||
private broadcasterService: BroadcasterService,
|
private broadcasterService: BroadcasterService,
|
||||||
private folderService: InternalFolderService,
|
private folderService: InternalFolderService,
|
||||||
private syncService: SyncService,
|
private syncService: SyncService,
|
||||||
@@ -410,9 +408,8 @@ export class AppComponent implements OnInit, OnDestroy {
|
|||||||
(await this.authService.getAuthStatus(message.userId)) ===
|
(await this.authService.getAuthStatus(message.userId)) ===
|
||||||
AuthenticationStatus.Locked;
|
AuthenticationStatus.Locked;
|
||||||
const forcedPasswordReset =
|
const forcedPasswordReset =
|
||||||
(await firstValueFrom(
|
(await this.stateService.getForceSetPasswordReason({ userId: message.userId })) !=
|
||||||
this.masterPasswordService.forceSetPasswordReason$(message.userId),
|
ForceSetPasswordReason.None;
|
||||||
)) != ForceSetPasswordReason.None;
|
|
||||||
if (locked) {
|
if (locked) {
|
||||||
this.messagingService.send("locked", { userId: message.userId });
|
this.messagingService.send("locked", { userId: message.userId });
|
||||||
} else if (forcedPasswordReset) {
|
} else if (forcedPasswordReset) {
|
||||||
|
|||||||
@@ -20,7 +20,6 @@ import { VaultTimeoutSettingsService } from "@bitwarden/common/abstractions/vaul
|
|||||||
import { PolicyService as PolicyServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction";
|
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 { AccountService as AccountServiceAbstraction } from "@bitwarden/common/auth/abstractions/account.service";
|
||||||
import { AuthService as AuthServiceAbstraction } from "@bitwarden/common/auth/abstractions/auth.service";
|
import { AuthService as AuthServiceAbstraction } from "@bitwarden/common/auth/abstractions/auth.service";
|
||||||
import { InternalMasterPasswordServiceAbstraction } from "@bitwarden/common/auth/abstractions/master-password.service.abstraction";
|
|
||||||
import { TokenService } from "@bitwarden/common/auth/abstractions/token.service";
|
import { TokenService } from "@bitwarden/common/auth/abstractions/token.service";
|
||||||
import { AutofillSettingsServiceAbstraction } from "@bitwarden/common/autofill/services/autofill-settings.service";
|
import { AutofillSettingsServiceAbstraction } from "@bitwarden/common/autofill/services/autofill-settings.service";
|
||||||
import { BroadcasterService as BroadcasterServiceAbstraction } from "@bitwarden/common/platform/abstractions/broadcaster.service";
|
import { BroadcasterService as BroadcasterServiceAbstraction } from "@bitwarden/common/platform/abstractions/broadcaster.service";
|
||||||
@@ -229,7 +228,6 @@ const safeProviders: SafeProvider[] = [
|
|||||||
provide: CryptoServiceAbstraction,
|
provide: CryptoServiceAbstraction,
|
||||||
useClass: ElectronCryptoService,
|
useClass: ElectronCryptoService,
|
||||||
deps: [
|
deps: [
|
||||||
InternalMasterPasswordServiceAbstraction,
|
|
||||||
KeyGenerationServiceAbstraction,
|
KeyGenerationServiceAbstraction,
|
||||||
CryptoFunctionServiceAbstraction,
|
CryptoFunctionServiceAbstraction,
|
||||||
EncryptService,
|
EncryptService,
|
||||||
|
|||||||
@@ -14,9 +14,7 @@ import { PolicyApiServiceAbstraction } from "@bitwarden/common/admin-console/abs
|
|||||||
import { InternalPolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction";
|
import { InternalPolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction";
|
||||||
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
||||||
import { DeviceTrustCryptoServiceAbstraction } from "@bitwarden/common/auth/abstractions/device-trust-crypto.service.abstraction";
|
import { DeviceTrustCryptoServiceAbstraction } from "@bitwarden/common/auth/abstractions/device-trust-crypto.service.abstraction";
|
||||||
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 { 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";
|
|
||||||
import { BroadcasterService } from "@bitwarden/common/platform/abstractions/broadcaster.service";
|
import { BroadcasterService } from "@bitwarden/common/platform/abstractions/broadcaster.service";
|
||||||
import { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.service";
|
import { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.service";
|
||||||
import { EnvironmentService } from "@bitwarden/common/platform/abstractions/environment.service";
|
import { EnvironmentService } from "@bitwarden/common/platform/abstractions/environment.service";
|
||||||
@@ -54,7 +52,6 @@ describe("LockComponent", () => {
|
|||||||
let broadcasterServiceMock: MockProxy<BroadcasterService>;
|
let broadcasterServiceMock: MockProxy<BroadcasterService>;
|
||||||
let platformUtilsServiceMock: MockProxy<PlatformUtilsService>;
|
let platformUtilsServiceMock: MockProxy<PlatformUtilsService>;
|
||||||
let activatedRouteMock: MockProxy<ActivatedRoute>;
|
let activatedRouteMock: MockProxy<ActivatedRoute>;
|
||||||
let mockMasterPasswordService: FakeMasterPasswordService;
|
|
||||||
|
|
||||||
const mockUserId = Utils.newGuid() as UserId;
|
const mockUserId = Utils.newGuid() as UserId;
|
||||||
const accountService: FakeAccountService = mockAccountServiceWith(mockUserId);
|
const accountService: FakeAccountService = mockAccountServiceWith(mockUserId);
|
||||||
@@ -70,8 +67,6 @@ describe("LockComponent", () => {
|
|||||||
activatedRouteMock = mock<ActivatedRoute>();
|
activatedRouteMock = mock<ActivatedRoute>();
|
||||||
activatedRouteMock.queryParams = mock<ActivatedRoute["queryParams"]>();
|
activatedRouteMock.queryParams = mock<ActivatedRoute["queryParams"]>();
|
||||||
|
|
||||||
mockMasterPasswordService = new FakeMasterPasswordService();
|
|
||||||
|
|
||||||
biometricStateService.dismissedRequirePasswordOnStartCallout$ = of(false);
|
biometricStateService.dismissedRequirePasswordOnStartCallout$ = of(false);
|
||||||
biometricStateService.promptAutomatically$ = of(false);
|
biometricStateService.promptAutomatically$ = of(false);
|
||||||
biometricStateService.promptCancelled$ = of(false);
|
biometricStateService.promptCancelled$ = of(false);
|
||||||
@@ -79,7 +74,6 @@ describe("LockComponent", () => {
|
|||||||
await TestBed.configureTestingModule({
|
await TestBed.configureTestingModule({
|
||||||
declarations: [LockComponent, I18nPipe],
|
declarations: [LockComponent, I18nPipe],
|
||||||
providers: [
|
providers: [
|
||||||
{ provide: InternalMasterPasswordServiceAbstraction, useValue: mockMasterPasswordService },
|
|
||||||
{
|
{
|
||||||
provide: I18nService,
|
provide: I18nService,
|
||||||
useValue: mock<I18nService>(),
|
useValue: mock<I18nService>(),
|
||||||
|
|||||||
@@ -11,7 +11,6 @@ import { PolicyApiServiceAbstraction } from "@bitwarden/common/admin-console/abs
|
|||||||
import { InternalPolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction";
|
import { InternalPolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction";
|
||||||
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
||||||
import { DeviceTrustCryptoServiceAbstraction } from "@bitwarden/common/auth/abstractions/device-trust-crypto.service.abstraction";
|
import { DeviceTrustCryptoServiceAbstraction } from "@bitwarden/common/auth/abstractions/device-trust-crypto.service.abstraction";
|
||||||
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 { UserVerificationService } from "@bitwarden/common/auth/abstractions/user-verification/user-verification.service.abstraction";
|
||||||
import { DeviceType } from "@bitwarden/common/enums";
|
import { DeviceType } from "@bitwarden/common/enums";
|
||||||
import { BroadcasterService } from "@bitwarden/common/platform/abstractions/broadcaster.service";
|
import { BroadcasterService } from "@bitwarden/common/platform/abstractions/broadcaster.service";
|
||||||
@@ -39,7 +38,6 @@ export class LockComponent extends BaseLockComponent {
|
|||||||
private autoPromptBiometric = false;
|
private autoPromptBiometric = false;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
masterPasswordService: InternalMasterPasswordServiceAbstraction,
|
|
||||||
router: Router,
|
router: Router,
|
||||||
i18nService: I18nService,
|
i18nService: I18nService,
|
||||||
platformUtilsService: PlatformUtilsService,
|
platformUtilsService: PlatformUtilsService,
|
||||||
@@ -65,7 +63,6 @@ export class LockComponent extends BaseLockComponent {
|
|||||||
accountService: AccountService,
|
accountService: AccountService,
|
||||||
) {
|
) {
|
||||||
super(
|
super(
|
||||||
masterPasswordService,
|
|
||||||
router,
|
router,
|
||||||
i18nService,
|
i18nService,
|
||||||
platformUtilsService,
|
platformUtilsService,
|
||||||
|
|||||||
@@ -8,8 +8,6 @@ import { OrganizationApiServiceAbstraction } from "@bitwarden/common/admin-conso
|
|||||||
import { OrganizationUserService } from "@bitwarden/common/admin-console/abstractions/organization-user/organization-user.service";
|
import { OrganizationUserService } from "@bitwarden/common/admin-console/abstractions/organization-user/organization-user.service";
|
||||||
import { PolicyApiServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/policy/policy-api.service.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 { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction";
|
||||||
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
|
||||||
import { InternalMasterPasswordServiceAbstraction } from "@bitwarden/common/auth/abstractions/master-password.service.abstraction";
|
|
||||||
import { SsoLoginServiceAbstraction } from "@bitwarden/common/auth/abstractions/sso-login.service.abstraction";
|
import { SsoLoginServiceAbstraction } from "@bitwarden/common/auth/abstractions/sso-login.service.abstraction";
|
||||||
import { BroadcasterService } from "@bitwarden/common/platform/abstractions/broadcaster.service";
|
import { BroadcasterService } from "@bitwarden/common/platform/abstractions/broadcaster.service";
|
||||||
import { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.service";
|
import { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.service";
|
||||||
@@ -31,8 +29,6 @@ const BroadcasterSubscriptionId = "SetPasswordComponent";
|
|||||||
})
|
})
|
||||||
export class SetPasswordComponent extends BaseSetPasswordComponent implements OnDestroy {
|
export class SetPasswordComponent extends BaseSetPasswordComponent implements OnDestroy {
|
||||||
constructor(
|
constructor(
|
||||||
accountService: AccountService,
|
|
||||||
masterPasswordService: InternalMasterPasswordServiceAbstraction,
|
|
||||||
apiService: ApiService,
|
apiService: ApiService,
|
||||||
i18nService: I18nService,
|
i18nService: I18nService,
|
||||||
cryptoService: CryptoService,
|
cryptoService: CryptoService,
|
||||||
@@ -54,8 +50,6 @@ export class SetPasswordComponent extends BaseSetPasswordComponent implements On
|
|||||||
dialogService: DialogService,
|
dialogService: DialogService,
|
||||||
) {
|
) {
|
||||||
super(
|
super(
|
||||||
accountService,
|
|
||||||
masterPasswordService,
|
|
||||||
i18nService,
|
i18nService,
|
||||||
cryptoService,
|
cryptoService,
|
||||||
messagingService,
|
messagingService,
|
||||||
|
|||||||
@@ -7,8 +7,6 @@ import {
|
|||||||
UserDecryptionOptionsServiceAbstraction,
|
UserDecryptionOptionsServiceAbstraction,
|
||||||
} from "@bitwarden/auth/common";
|
} from "@bitwarden/auth/common";
|
||||||
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
||||||
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
|
||||||
import { InternalMasterPasswordServiceAbstraction } from "@bitwarden/common/auth/abstractions/master-password.service.abstraction";
|
|
||||||
import { SsoLoginServiceAbstraction } from "@bitwarden/common/auth/abstractions/sso-login.service.abstraction";
|
import { SsoLoginServiceAbstraction } from "@bitwarden/common/auth/abstractions/sso-login.service.abstraction";
|
||||||
import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service";
|
import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service";
|
||||||
import { CryptoFunctionService } from "@bitwarden/common/platform/abstractions/crypto-function.service";
|
import { CryptoFunctionService } from "@bitwarden/common/platform/abstractions/crypto-function.service";
|
||||||
@@ -41,8 +39,6 @@ export class SsoComponent extends BaseSsoComponent {
|
|||||||
logService: LogService,
|
logService: LogService,
|
||||||
userDecryptionOptionsService: UserDecryptionOptionsServiceAbstraction,
|
userDecryptionOptionsService: UserDecryptionOptionsServiceAbstraction,
|
||||||
configService: ConfigService,
|
configService: ConfigService,
|
||||||
masterPasswordService: InternalMasterPasswordServiceAbstraction,
|
|
||||||
accountService: AccountService,
|
|
||||||
) {
|
) {
|
||||||
super(
|
super(
|
||||||
ssoLoginService,
|
ssoLoginService,
|
||||||
@@ -59,8 +55,6 @@ export class SsoComponent extends BaseSsoComponent {
|
|||||||
logService,
|
logService,
|
||||||
userDecryptionOptionsService,
|
userDecryptionOptionsService,
|
||||||
configService,
|
configService,
|
||||||
masterPasswordService,
|
|
||||||
accountService,
|
|
||||||
);
|
);
|
||||||
super.onSuccessfulLogin = async () => {
|
super.onSuccessfulLogin = async () => {
|
||||||
// FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling.
|
// FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling.
|
||||||
|
|||||||
@@ -11,8 +11,6 @@ import {
|
|||||||
UserDecryptionOptionsServiceAbstraction,
|
UserDecryptionOptionsServiceAbstraction,
|
||||||
} from "@bitwarden/auth/common";
|
} from "@bitwarden/auth/common";
|
||||||
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
||||||
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
|
||||||
import { InternalMasterPasswordServiceAbstraction } from "@bitwarden/common/auth/abstractions/master-password.service.abstraction";
|
|
||||||
import { SsoLoginServiceAbstraction } from "@bitwarden/common/auth/abstractions/sso-login.service.abstraction";
|
import { SsoLoginServiceAbstraction } from "@bitwarden/common/auth/abstractions/sso-login.service.abstraction";
|
||||||
import { TwoFactorService } from "@bitwarden/common/auth/abstractions/two-factor.service";
|
import { TwoFactorService } from "@bitwarden/common/auth/abstractions/two-factor.service";
|
||||||
import { TwoFactorProviderType } from "@bitwarden/common/auth/enums/two-factor-provider-type";
|
import { TwoFactorProviderType } from "@bitwarden/common/auth/enums/two-factor-provider-type";
|
||||||
@@ -62,8 +60,6 @@ export class TwoFactorComponent extends BaseTwoFactorComponent {
|
|||||||
userDecryptionOptionsService: UserDecryptionOptionsServiceAbstraction,
|
userDecryptionOptionsService: UserDecryptionOptionsServiceAbstraction,
|
||||||
ssoLoginService: SsoLoginServiceAbstraction,
|
ssoLoginService: SsoLoginServiceAbstraction,
|
||||||
configService: ConfigService,
|
configService: ConfigService,
|
||||||
masterPasswordService: InternalMasterPasswordServiceAbstraction,
|
|
||||||
accountService: AccountService,
|
|
||||||
@Inject(WINDOW) protected win: Window,
|
@Inject(WINDOW) protected win: Window,
|
||||||
) {
|
) {
|
||||||
super(
|
super(
|
||||||
@@ -83,8 +79,6 @@ export class TwoFactorComponent extends BaseTwoFactorComponent {
|
|||||||
userDecryptionOptionsService,
|
userDecryptionOptionsService,
|
||||||
ssoLoginService,
|
ssoLoginService,
|
||||||
configService,
|
configService,
|
||||||
masterPasswordService,
|
|
||||||
accountService,
|
|
||||||
);
|
);
|
||||||
super.onSuccessfulLogin = async () => {
|
super.onSuccessfulLogin = async () => {
|
||||||
// FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling.
|
// FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling.
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
import { FakeStateProvider } from "@bitwarden/common/../spec/fake-state-provider";
|
import { FakeStateProvider } from "@bitwarden/common/../spec/fake-state-provider";
|
||||||
import { mock } from "jest-mock-extended";
|
import { mock } from "jest-mock-extended";
|
||||||
|
|
||||||
import { FakeMasterPasswordService } from "@bitwarden/common/auth/services/master-password/fake-master-password.service";
|
|
||||||
import { CryptoFunctionService } from "@bitwarden/common/platform/abstractions/crypto-function.service";
|
import { CryptoFunctionService } from "@bitwarden/common/platform/abstractions/crypto-function.service";
|
||||||
import { EncryptService } from "@bitwarden/common/platform/abstractions/encrypt.service";
|
import { EncryptService } from "@bitwarden/common/platform/abstractions/encrypt.service";
|
||||||
import { KeyGenerationService } from "@bitwarden/common/platform/abstractions/key-generation.service";
|
import { KeyGenerationService } from "@bitwarden/common/platform/abstractions/key-generation.service";
|
||||||
@@ -31,7 +30,6 @@ describe("electronCryptoService", () => {
|
|||||||
const platformUtilService = mock<PlatformUtilsService>();
|
const platformUtilService = mock<PlatformUtilsService>();
|
||||||
const logService = mock<LogService>();
|
const logService = mock<LogService>();
|
||||||
const stateService = mock<StateService>();
|
const stateService = mock<StateService>();
|
||||||
let masterPasswordService: FakeMasterPasswordService;
|
|
||||||
let accountService: FakeAccountService;
|
let accountService: FakeAccountService;
|
||||||
let stateProvider: FakeStateProvider;
|
let stateProvider: FakeStateProvider;
|
||||||
const biometricStateService = mock<BiometricStateService>();
|
const biometricStateService = mock<BiometricStateService>();
|
||||||
@@ -40,11 +38,9 @@ describe("electronCryptoService", () => {
|
|||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
accountService = mockAccountServiceWith("userId" as UserId);
|
accountService = mockAccountServiceWith("userId" as UserId);
|
||||||
masterPasswordService = new FakeMasterPasswordService();
|
|
||||||
stateProvider = new FakeStateProvider(accountService);
|
stateProvider = new FakeStateProvider(accountService);
|
||||||
|
|
||||||
sut = new ElectronCryptoService(
|
sut = new ElectronCryptoService(
|
||||||
masterPasswordService,
|
|
||||||
keyGenerationService,
|
keyGenerationService,
|
||||||
cryptoFunctionService,
|
cryptoFunctionService,
|
||||||
encryptService,
|
encryptService,
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
import { firstValueFrom } from "rxjs";
|
import { firstValueFrom } from "rxjs";
|
||||||
|
|
||||||
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
||||||
import { InternalMasterPasswordServiceAbstraction } from "@bitwarden/common/auth/abstractions/master-password.service.abstraction";
|
|
||||||
import { CryptoFunctionService } from "@bitwarden/common/platform/abstractions/crypto-function.service";
|
import { CryptoFunctionService } from "@bitwarden/common/platform/abstractions/crypto-function.service";
|
||||||
import { EncryptService } from "@bitwarden/common/platform/abstractions/encrypt.service";
|
import { EncryptService } from "@bitwarden/common/platform/abstractions/encrypt.service";
|
||||||
import { KeyGenerationService } from "@bitwarden/common/platform/abstractions/key-generation.service";
|
import { KeyGenerationService } from "@bitwarden/common/platform/abstractions/key-generation.service";
|
||||||
@@ -21,7 +20,6 @@ import { UserKey, MasterKey } from "@bitwarden/common/types/key";
|
|||||||
|
|
||||||
export class ElectronCryptoService extends CryptoService {
|
export class ElectronCryptoService extends CryptoService {
|
||||||
constructor(
|
constructor(
|
||||||
masterPasswordService: InternalMasterPasswordServiceAbstraction,
|
|
||||||
keyGenerationService: KeyGenerationService,
|
keyGenerationService: KeyGenerationService,
|
||||||
cryptoFunctionService: CryptoFunctionService,
|
cryptoFunctionService: CryptoFunctionService,
|
||||||
encryptService: EncryptService,
|
encryptService: EncryptService,
|
||||||
@@ -33,7 +31,6 @@ export class ElectronCryptoService extends CryptoService {
|
|||||||
private biometricStateService: BiometricStateService,
|
private biometricStateService: BiometricStateService,
|
||||||
) {
|
) {
|
||||||
super(
|
super(
|
||||||
masterPasswordService,
|
|
||||||
keyGenerationService,
|
keyGenerationService,
|
||||||
cryptoFunctionService,
|
cryptoFunctionService,
|
||||||
encryptService,
|
encryptService,
|
||||||
@@ -162,16 +159,12 @@ export class ElectronCryptoService extends CryptoService {
|
|||||||
const oldBiometricKey = await this.stateService.getCryptoMasterKeyBiometric({ userId });
|
const oldBiometricKey = await this.stateService.getCryptoMasterKeyBiometric({ userId });
|
||||||
// decrypt
|
// decrypt
|
||||||
const masterKey = new SymmetricCryptoKey(Utils.fromB64ToArray(oldBiometricKey)) as MasterKey;
|
const masterKey = new SymmetricCryptoKey(Utils.fromB64ToArray(oldBiometricKey)) as MasterKey;
|
||||||
userId ??= (await firstValueFrom(this.accountService.activeAccount$))?.id;
|
let encUserKey = await this.stateService.getEncryptedCryptoSymmetricKey();
|
||||||
const encUserKeyPrim = await this.stateService.getEncryptedCryptoSymmetricKey();
|
encUserKey = encUserKey ?? (await this.stateService.getMasterKeyEncryptedUserKey());
|
||||||
const encUserKey =
|
|
||||||
encUserKeyPrim != null
|
|
||||||
? new EncString(encUserKeyPrim)
|
|
||||||
: await this.masterPasswordService.getMasterKeyEncryptedUserKey(userId);
|
|
||||||
if (!encUserKey) {
|
if (!encUserKey) {
|
||||||
throw new Error("No user key found during biometric migration");
|
throw new Error("No user key found during biometric migration");
|
||||||
}
|
}
|
||||||
const userKey = await this.decryptUserKeyWithMasterKey(masterKey, encUserKey);
|
const userKey = await this.decryptUserKeyWithMasterKey(masterKey, new EncString(encUserKey));
|
||||||
// migrate
|
// migrate
|
||||||
await this.storeBiometricKey(userKey, userId);
|
await this.storeBiometricKey(userKey, userId);
|
||||||
await this.stateService.setCryptoMasterKeyBiometric(null, { userId });
|
await this.stateService.setCryptoMasterKeyBiometric(null, { userId });
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
import { Injectable, NgZone } from "@angular/core";
|
import { Injectable, NgZone } from "@angular/core";
|
||||||
import { firstValueFrom } from "rxjs";
|
import { firstValueFrom } from "rxjs";
|
||||||
|
|
||||||
import { MasterPasswordServiceAbstraction } from "@bitwarden/common/auth/abstractions/master-password.service.abstraction";
|
|
||||||
import { CryptoFunctionService } from "@bitwarden/common/platform/abstractions/crypto-function.service";
|
import { CryptoFunctionService } from "@bitwarden/common/platform/abstractions/crypto-function.service";
|
||||||
import { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.service";
|
import { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.service";
|
||||||
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
|
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
|
||||||
@@ -31,7 +30,6 @@ export class NativeMessagingService {
|
|||||||
private sharedSecrets = new Map<string, SymmetricCryptoKey>();
|
private sharedSecrets = new Map<string, SymmetricCryptoKey>();
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private masterPasswordService: MasterPasswordServiceAbstraction,
|
|
||||||
private cryptoFunctionService: CryptoFunctionService,
|
private cryptoFunctionService: CryptoFunctionService,
|
||||||
private cryptoService: CryptoService,
|
private cryptoService: CryptoService,
|
||||||
private platformUtilService: PlatformUtilsService,
|
private platformUtilService: PlatformUtilsService,
|
||||||
@@ -164,9 +162,7 @@ export class NativeMessagingService {
|
|||||||
KeySuffixOptions.Biometric,
|
KeySuffixOptions.Biometric,
|
||||||
message.userId,
|
message.userId,
|
||||||
);
|
);
|
||||||
const masterKey = await firstValueFrom(
|
const masterKey = await this.cryptoService.getMasterKey(message.userId);
|
||||||
this.masterPasswordService.masterKey$(message.userId as UserId),
|
|
||||||
);
|
|
||||||
|
|
||||||
if (userKey != null) {
|
if (userKey != null) {
|
||||||
// we send the master key still for backwards compatibility
|
// we send the master key still for backwards compatibility
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ import { mock, MockProxy } from "jest-mock-extended";
|
|||||||
import { BehaviorSubject } from "rxjs";
|
import { BehaviorSubject } from "rxjs";
|
||||||
|
|
||||||
import { DeviceTrustCryptoServiceAbstraction } from "@bitwarden/common/auth/abstractions/device-trust-crypto.service.abstraction";
|
import { DeviceTrustCryptoServiceAbstraction } from "@bitwarden/common/auth/abstractions/device-trust-crypto.service.abstraction";
|
||||||
import { FakeMasterPasswordService } from "@bitwarden/common/auth/services/master-password/fake-master-password.service";
|
|
||||||
import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service";
|
import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service";
|
||||||
import { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.service";
|
import { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.service";
|
||||||
import { EncryptService } from "@bitwarden/common/platform/abstractions/encrypt.service";
|
import { EncryptService } from "@bitwarden/common/platform/abstractions/encrypt.service";
|
||||||
@@ -10,6 +9,7 @@ import { EncryptionType } from "@bitwarden/common/platform/enums";
|
|||||||
import { Utils } from "@bitwarden/common/platform/misc/utils";
|
import { Utils } from "@bitwarden/common/platform/misc/utils";
|
||||||
import { EncString } from "@bitwarden/common/platform/models/domain/enc-string";
|
import { EncString } from "@bitwarden/common/platform/models/domain/enc-string";
|
||||||
import { SymmetricCryptoKey } from "@bitwarden/common/platform/models/domain/symmetric-crypto-key";
|
import { SymmetricCryptoKey } from "@bitwarden/common/platform/models/domain/symmetric-crypto-key";
|
||||||
|
import { FakeAccountService, mockAccountServiceWith } from "@bitwarden/common/spec";
|
||||||
import { Send } from "@bitwarden/common/tools/send/models/domain/send";
|
import { Send } from "@bitwarden/common/tools/send/models/domain/send";
|
||||||
import { SendService } from "@bitwarden/common/tools/send/services/send.service.abstraction";
|
import { SendService } from "@bitwarden/common/tools/send/services/send.service.abstraction";
|
||||||
import { UserId } from "@bitwarden/common/types/guid";
|
import { UserId } from "@bitwarden/common/types/guid";
|
||||||
@@ -22,10 +22,6 @@ import { Folder } from "@bitwarden/common/vault/models/domain/folder";
|
|||||||
import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view";
|
import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view";
|
||||||
import { FolderView } from "@bitwarden/common/vault/models/view/folder.view";
|
import { FolderView } from "@bitwarden/common/vault/models/view/folder.view";
|
||||||
|
|
||||||
import {
|
|
||||||
FakeAccountService,
|
|
||||||
mockAccountServiceWith,
|
|
||||||
} from "../../../../../../libs/common/spec/fake-account-service";
|
|
||||||
import { OrganizationUserResetPasswordService } from "../../admin-console/organizations/members/services/organization-user-reset-password/organization-user-reset-password.service";
|
import { OrganizationUserResetPasswordService } from "../../admin-console/organizations/members/services/organization-user-reset-password/organization-user-reset-password.service";
|
||||||
import { StateService } from "../../core";
|
import { StateService } from "../../core";
|
||||||
import { EmergencyAccessService } from "../emergency-access";
|
import { EmergencyAccessService } from "../emergency-access";
|
||||||
@@ -50,10 +46,8 @@ describe("KeyRotationService", () => {
|
|||||||
|
|
||||||
const mockUserId = Utils.newGuid() as UserId;
|
const mockUserId = Utils.newGuid() as UserId;
|
||||||
const mockAccountService: FakeAccountService = mockAccountServiceWith(mockUserId);
|
const mockAccountService: FakeAccountService = mockAccountServiceWith(mockUserId);
|
||||||
let mockMasterPasswordService: FakeMasterPasswordService = new FakeMasterPasswordService();
|
|
||||||
|
|
||||||
beforeAll(() => {
|
beforeAll(() => {
|
||||||
mockMasterPasswordService = new FakeMasterPasswordService();
|
|
||||||
mockApiService = mock<UserKeyRotationApiService>();
|
mockApiService = mock<UserKeyRotationApiService>();
|
||||||
mockCipherService = mock<CipherService>();
|
mockCipherService = mock<CipherService>();
|
||||||
mockFolderService = mock<FolderService>();
|
mockFolderService = mock<FolderService>();
|
||||||
@@ -67,7 +61,6 @@ describe("KeyRotationService", () => {
|
|||||||
mockConfigService = mock<ConfigService>();
|
mockConfigService = mock<ConfigService>();
|
||||||
|
|
||||||
keyRotationService = new UserKeyRotationService(
|
keyRotationService = new UserKeyRotationService(
|
||||||
mockMasterPasswordService,
|
|
||||||
mockApiService,
|
mockApiService,
|
||||||
mockCipherService,
|
mockCipherService,
|
||||||
mockFolderService,
|
mockFolderService,
|
||||||
@@ -181,10 +174,7 @@ describe("KeyRotationService", () => {
|
|||||||
it("saves the master key in state after creation", async () => {
|
it("saves the master key in state after creation", async () => {
|
||||||
await keyRotationService.rotateUserKeyAndEncryptedData("mockMasterPassword");
|
await keyRotationService.rotateUserKeyAndEncryptedData("mockMasterPassword");
|
||||||
|
|
||||||
expect(mockMasterPasswordService.mock.setMasterKey).toHaveBeenCalledWith(
|
expect(mockCryptoService.setMasterKey).toHaveBeenCalledWith("mockMasterKey" as any);
|
||||||
"mockMasterKey" as any,
|
|
||||||
mockUserId,
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it("uses legacy rotation if feature flag is off", async () => {
|
it("uses legacy rotation if feature flag is off", async () => {
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ import { firstValueFrom } from "rxjs";
|
|||||||
|
|
||||||
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
||||||
import { DeviceTrustCryptoServiceAbstraction } from "@bitwarden/common/auth/abstractions/device-trust-crypto.service.abstraction";
|
import { DeviceTrustCryptoServiceAbstraction } from "@bitwarden/common/auth/abstractions/device-trust-crypto.service.abstraction";
|
||||||
import { InternalMasterPasswordServiceAbstraction } from "@bitwarden/common/auth/abstractions/master-password.service.abstraction";
|
|
||||||
import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum";
|
import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum";
|
||||||
import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service";
|
import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service";
|
||||||
import { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.service";
|
import { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.service";
|
||||||
@@ -26,7 +25,6 @@ import { UserKeyRotationApiService } from "./user-key-rotation-api.service";
|
|||||||
@Injectable()
|
@Injectable()
|
||||||
export class UserKeyRotationService {
|
export class UserKeyRotationService {
|
||||||
constructor(
|
constructor(
|
||||||
private masterPasswordService: InternalMasterPasswordServiceAbstraction,
|
|
||||||
private apiService: UserKeyRotationApiService,
|
private apiService: UserKeyRotationApiService,
|
||||||
private cipherService: CipherService,
|
private cipherService: CipherService,
|
||||||
private folderService: FolderService,
|
private folderService: FolderService,
|
||||||
@@ -63,8 +61,7 @@ export class UserKeyRotationService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Set master key again in case it was lost (could be lost on refresh)
|
// Set master key again in case it was lost (could be lost on refresh)
|
||||||
const userId = (await firstValueFrom(this.accountService.activeAccount$))?.id;
|
await this.cryptoService.setMasterKey(masterKey);
|
||||||
await this.masterPasswordService.setMasterKey(masterKey, userId);
|
|
||||||
const [newUserKey, newEncUserKey] = await this.cryptoService.makeUserKey(masterKey);
|
const [newUserKey, newEncUserKey] = await this.cryptoService.makeUserKey(masterKey);
|
||||||
|
|
||||||
if (!newUserKey || !newEncUserKey) {
|
if (!newUserKey || !newEncUserKey) {
|
||||||
|
|||||||
@@ -1,12 +1,80 @@
|
|||||||
import { Component } from "@angular/core";
|
import { Component, NgZone } from "@angular/core";
|
||||||
|
import { Router } from "@angular/router";
|
||||||
|
|
||||||
import { LockComponent as BaseLockComponent } from "@bitwarden/angular/auth/components/lock.component";
|
import { LockComponent as BaseLockComponent } from "@bitwarden/angular/auth/components/lock.component";
|
||||||
|
import { PinCryptoServiceAbstraction } from "@bitwarden/auth/common";
|
||||||
|
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
||||||
|
import { VaultTimeoutSettingsService } from "@bitwarden/common/abstractions/vault-timeout/vault-timeout-settings.service";
|
||||||
|
import { VaultTimeoutService } from "@bitwarden/common/abstractions/vault-timeout/vault-timeout.service";
|
||||||
|
import { PolicyApiServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/policy/policy-api.service.abstraction";
|
||||||
|
import { InternalPolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction";
|
||||||
|
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
||||||
|
import { DeviceTrustCryptoServiceAbstraction } from "@bitwarden/common/auth/abstractions/device-trust-crypto.service.abstraction";
|
||||||
|
import { UserVerificationService } from "@bitwarden/common/auth/abstractions/user-verification/user-verification.service.abstraction";
|
||||||
|
import { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.service";
|
||||||
|
import { EnvironmentService } from "@bitwarden/common/platform/abstractions/environment.service";
|
||||||
|
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||||
|
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 { BiometricStateService } from "@bitwarden/common/platform/biometrics/biometric-state.service";
|
||||||
|
import { PasswordStrengthServiceAbstraction } from "@bitwarden/common/tools/password-strength";
|
||||||
|
import { DialogService } from "@bitwarden/components";
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: "app-lock",
|
selector: "app-lock",
|
||||||
templateUrl: "lock.component.html",
|
templateUrl: "lock.component.html",
|
||||||
})
|
})
|
||||||
export class LockComponent extends BaseLockComponent {
|
export class LockComponent extends BaseLockComponent {
|
||||||
|
constructor(
|
||||||
|
router: Router,
|
||||||
|
i18nService: I18nService,
|
||||||
|
platformUtilsService: PlatformUtilsService,
|
||||||
|
messagingService: MessagingService,
|
||||||
|
cryptoService: CryptoService,
|
||||||
|
vaultTimeoutService: VaultTimeoutService,
|
||||||
|
vaultTimeoutSettingsService: VaultTimeoutSettingsService,
|
||||||
|
environmentService: EnvironmentService,
|
||||||
|
stateService: StateService,
|
||||||
|
apiService: ApiService,
|
||||||
|
logService: LogService,
|
||||||
|
ngZone: NgZone,
|
||||||
|
policyApiService: PolicyApiServiceAbstraction,
|
||||||
|
policyService: InternalPolicyService,
|
||||||
|
passwordStrengthService: PasswordStrengthServiceAbstraction,
|
||||||
|
dialogService: DialogService,
|
||||||
|
deviceTrustCryptoService: DeviceTrustCryptoServiceAbstraction,
|
||||||
|
userVerificationService: UserVerificationService,
|
||||||
|
pinCryptoService: PinCryptoServiceAbstraction,
|
||||||
|
biometricStateService: BiometricStateService,
|
||||||
|
accountService: AccountService,
|
||||||
|
) {
|
||||||
|
super(
|
||||||
|
router,
|
||||||
|
i18nService,
|
||||||
|
platformUtilsService,
|
||||||
|
messagingService,
|
||||||
|
cryptoService,
|
||||||
|
vaultTimeoutService,
|
||||||
|
vaultTimeoutSettingsService,
|
||||||
|
environmentService,
|
||||||
|
stateService,
|
||||||
|
apiService,
|
||||||
|
logService,
|
||||||
|
ngZone,
|
||||||
|
policyApiService,
|
||||||
|
policyService,
|
||||||
|
passwordStrengthService,
|
||||||
|
dialogService,
|
||||||
|
deviceTrustCryptoService,
|
||||||
|
userVerificationService,
|
||||||
|
pinCryptoService,
|
||||||
|
biometricStateService,
|
||||||
|
accountService,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
async ngOnInit() {
|
async ngOnInit() {
|
||||||
await super.ngOnInit();
|
await super.ngOnInit();
|
||||||
this.onSuccessfulSubmit = async () => {
|
this.onSuccessfulSubmit = async () => {
|
||||||
|
|||||||
@@ -10,8 +10,6 @@ import {
|
|||||||
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
||||||
import { OrgDomainApiServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/organization-domain/org-domain-api.service.abstraction";
|
import { OrgDomainApiServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/organization-domain/org-domain-api.service.abstraction";
|
||||||
import { OrganizationDomainSsoDetailsResponse } from "@bitwarden/common/admin-console/abstractions/organization-domain/responses/organization-domain-sso-details.response";
|
import { OrganizationDomainSsoDetailsResponse } from "@bitwarden/common/admin-console/abstractions/organization-domain/responses/organization-domain-sso-details.response";
|
||||||
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
|
||||||
import { InternalMasterPasswordServiceAbstraction } from "@bitwarden/common/auth/abstractions/master-password.service.abstraction";
|
|
||||||
import { SsoLoginServiceAbstraction } from "@bitwarden/common/auth/abstractions/sso-login.service.abstraction";
|
import { SsoLoginServiceAbstraction } from "@bitwarden/common/auth/abstractions/sso-login.service.abstraction";
|
||||||
import { HttpStatusCode } from "@bitwarden/common/enums";
|
import { HttpStatusCode } from "@bitwarden/common/enums";
|
||||||
import { ErrorResponse } from "@bitwarden/common/models/response/error.response";
|
import { ErrorResponse } from "@bitwarden/common/models/response/error.response";
|
||||||
@@ -48,8 +46,6 @@ export class SsoComponent extends BaseSsoComponent {
|
|||||||
private validationService: ValidationService,
|
private validationService: ValidationService,
|
||||||
userDecryptionOptionsService: UserDecryptionOptionsServiceAbstraction,
|
userDecryptionOptionsService: UserDecryptionOptionsServiceAbstraction,
|
||||||
configService: ConfigService,
|
configService: ConfigService,
|
||||||
masterPasswordService: InternalMasterPasswordServiceAbstraction,
|
|
||||||
accountService: AccountService,
|
|
||||||
) {
|
) {
|
||||||
super(
|
super(
|
||||||
ssoLoginService,
|
ssoLoginService,
|
||||||
@@ -66,8 +62,6 @@ export class SsoComponent extends BaseSsoComponent {
|
|||||||
logService,
|
logService,
|
||||||
userDecryptionOptionsService,
|
userDecryptionOptionsService,
|
||||||
configService,
|
configService,
|
||||||
masterPasswordService,
|
|
||||||
accountService,
|
|
||||||
);
|
);
|
||||||
this.redirectUri = window.location.origin + "/sso-connector.html";
|
this.redirectUri = window.location.origin + "/sso-connector.html";
|
||||||
this.clientId = "web";
|
this.clientId = "web";
|
||||||
|
|||||||
@@ -10,8 +10,6 @@ import {
|
|||||||
UserDecryptionOptionsServiceAbstraction,
|
UserDecryptionOptionsServiceAbstraction,
|
||||||
} from "@bitwarden/auth/common";
|
} from "@bitwarden/auth/common";
|
||||||
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
||||||
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
|
||||||
import { InternalMasterPasswordServiceAbstraction } from "@bitwarden/common/auth/abstractions/master-password.service.abstraction";
|
|
||||||
import { SsoLoginServiceAbstraction } from "@bitwarden/common/auth/abstractions/sso-login.service.abstraction";
|
import { SsoLoginServiceAbstraction } from "@bitwarden/common/auth/abstractions/sso-login.service.abstraction";
|
||||||
import { TwoFactorService } from "@bitwarden/common/auth/abstractions/two-factor.service";
|
import { TwoFactorService } from "@bitwarden/common/auth/abstractions/two-factor.service";
|
||||||
import { TwoFactorProviderType } from "@bitwarden/common/auth/enums/two-factor-provider-type";
|
import { TwoFactorProviderType } from "@bitwarden/common/auth/enums/two-factor-provider-type";
|
||||||
@@ -52,8 +50,6 @@ export class TwoFactorComponent extends BaseTwoFactorComponent implements OnDest
|
|||||||
userDecryptionOptionsService: UserDecryptionOptionsServiceAbstraction,
|
userDecryptionOptionsService: UserDecryptionOptionsServiceAbstraction,
|
||||||
ssoLoginService: SsoLoginServiceAbstraction,
|
ssoLoginService: SsoLoginServiceAbstraction,
|
||||||
configService: ConfigService,
|
configService: ConfigService,
|
||||||
masterPasswordService: InternalMasterPasswordServiceAbstraction,
|
|
||||||
accountService: AccountService,
|
|
||||||
@Inject(WINDOW) protected win: Window,
|
@Inject(WINDOW) protected win: Window,
|
||||||
) {
|
) {
|
||||||
super(
|
super(
|
||||||
@@ -73,8 +69,6 @@ export class TwoFactorComponent extends BaseTwoFactorComponent implements OnDest
|
|||||||
userDecryptionOptionsService,
|
userDecryptionOptionsService,
|
||||||
ssoLoginService,
|
ssoLoginService,
|
||||||
configService,
|
configService,
|
||||||
masterPasswordService,
|
|
||||||
accountService,
|
|
||||||
);
|
);
|
||||||
this.onSuccessfulLoginNavigate = this.goAfterLogIn;
|
this.onSuccessfulLoginNavigate = this.goAfterLogIn;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,11 +10,7 @@ module.exports = {
|
|||||||
displayName: "libs/angular tests",
|
displayName: "libs/angular tests",
|
||||||
preset: "jest-preset-angular",
|
preset: "jest-preset-angular",
|
||||||
setupFilesAfterEnv: ["<rootDir>/test.setup.ts"],
|
setupFilesAfterEnv: ["<rootDir>/test.setup.ts"],
|
||||||
moduleNameMapper: pathsToModuleNameMapper(
|
moduleNameMapper: pathsToModuleNameMapper(compilerOptions?.paths || {}, {
|
||||||
// lets us use @bitwarden/common/spec in tests
|
prefix: "<rootDir>/",
|
||||||
{ "@bitwarden/common/spec": ["../common/spec"], ...(compilerOptions?.paths ?? {}) },
|
}),
|
||||||
{
|
|
||||||
prefix: "<rootDir>/",
|
|
||||||
},
|
|
||||||
),
|
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -12,7 +12,6 @@ import { InternalPolicyService } from "@bitwarden/common/admin-console/abstracti
|
|||||||
import { MasterPasswordPolicyOptions } from "@bitwarden/common/admin-console/models/domain/master-password-policy-options";
|
import { MasterPasswordPolicyOptions } from "@bitwarden/common/admin-console/models/domain/master-password-policy-options";
|
||||||
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
||||||
import { DeviceTrustCryptoServiceAbstraction } from "@bitwarden/common/auth/abstractions/device-trust-crypto.service.abstraction";
|
import { DeviceTrustCryptoServiceAbstraction } from "@bitwarden/common/auth/abstractions/device-trust-crypto.service.abstraction";
|
||||||
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 { UserVerificationService } from "@bitwarden/common/auth/abstractions/user-verification/user-verification.service.abstraction";
|
||||||
import { ForceSetPasswordReason } from "@bitwarden/common/auth/models/domain/force-set-password-reason";
|
import { ForceSetPasswordReason } from "@bitwarden/common/auth/models/domain/force-set-password-reason";
|
||||||
import { SecretVerificationRequest } from "@bitwarden/common/auth/models/request/secret-verification.request";
|
import { SecretVerificationRequest } from "@bitwarden/common/auth/models/request/secret-verification.request";
|
||||||
@@ -57,7 +56,6 @@ export class LockComponent implements OnInit, OnDestroy {
|
|||||||
private destroy$ = new Subject<void>();
|
private destroy$ = new Subject<void>();
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
protected masterPasswordService: InternalMasterPasswordServiceAbstraction,
|
|
||||||
protected router: Router,
|
protected router: Router,
|
||||||
protected i18nService: I18nService,
|
protected i18nService: I18nService,
|
||||||
protected platformUtilsService: PlatformUtilsService,
|
protected platformUtilsService: PlatformUtilsService,
|
||||||
@@ -208,7 +206,6 @@ export class LockComponent implements OnInit, OnDestroy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private async doUnlockWithMasterPassword() {
|
private async doUnlockWithMasterPassword() {
|
||||||
const userId = (await firstValueFrom(this.accountService.activeAccount$))?.id;
|
|
||||||
const kdf = await this.stateService.getKdfType();
|
const kdf = await this.stateService.getKdfType();
|
||||||
const kdfConfig = await this.stateService.getKdfConfig();
|
const kdfConfig = await this.stateService.getKdfConfig();
|
||||||
|
|
||||||
@@ -218,13 +215,11 @@ export class LockComponent implements OnInit, OnDestroy {
|
|||||||
kdf,
|
kdf,
|
||||||
kdfConfig,
|
kdfConfig,
|
||||||
);
|
);
|
||||||
const storedMasterKeyHash = await firstValueFrom(
|
const storedPasswordHash = await this.cryptoService.getMasterKeyHash();
|
||||||
this.masterPasswordService.masterKeyHash$(userId),
|
|
||||||
);
|
|
||||||
|
|
||||||
let passwordValid = false;
|
let passwordValid = false;
|
||||||
|
|
||||||
if (storedMasterKeyHash != null) {
|
if (storedPasswordHash != null) {
|
||||||
// Offline unlock possible
|
// Offline unlock possible
|
||||||
passwordValid = await this.cryptoService.compareAndUpdateKeyHash(
|
passwordValid = await this.cryptoService.compareAndUpdateKeyHash(
|
||||||
this.masterPassword,
|
this.masterPassword,
|
||||||
@@ -249,7 +244,7 @@ export class LockComponent implements OnInit, OnDestroy {
|
|||||||
masterKey,
|
masterKey,
|
||||||
HashPurpose.LocalAuthorization,
|
HashPurpose.LocalAuthorization,
|
||||||
);
|
);
|
||||||
await this.masterPasswordService.setMasterKeyHash(localKeyHash, userId);
|
await this.cryptoService.setMasterKeyHash(localKeyHash);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
this.logService.error(e);
|
this.logService.error(e);
|
||||||
} finally {
|
} finally {
|
||||||
@@ -267,7 +262,7 @@ export class LockComponent implements OnInit, OnDestroy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const userKey = await this.cryptoService.decryptUserKeyWithMasterKey(masterKey);
|
const userKey = await this.cryptoService.decryptUserKeyWithMasterKey(masterKey);
|
||||||
await this.masterPasswordService.setMasterKey(masterKey, userId);
|
await this.cryptoService.setMasterKey(masterKey);
|
||||||
await this.setUserKeyAndContinue(userKey, true);
|
await this.setUserKeyAndContinue(userKey, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -297,10 +292,8 @@ export class LockComponent implements OnInit, OnDestroy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (this.requirePasswordChange()) {
|
if (this.requirePasswordChange()) {
|
||||||
const userId = (await firstValueFrom(this.accountService.activeAccount$))?.id;
|
await this.stateService.setForceSetPasswordReason(
|
||||||
await this.masterPasswordService.setForceSetPasswordReason(
|
|
||||||
ForceSetPasswordReason.WeakMasterPassword,
|
ForceSetPasswordReason.WeakMasterPassword,
|
||||||
userId,
|
|
||||||
);
|
);
|
||||||
// FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling.
|
// FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling.
|
||||||
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
||||||
|
|||||||
@@ -12,8 +12,6 @@ import { PolicyApiServiceAbstraction } from "@bitwarden/common/admin-console/abs
|
|||||||
import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction";
|
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 { 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 { OrganizationAutoEnrollStatusResponse } from "@bitwarden/common/admin-console/models/response/organization-auto-enroll-status.response";
|
||||||
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
|
||||||
import { InternalMasterPasswordServiceAbstraction } from "@bitwarden/common/auth/abstractions/master-password.service.abstraction";
|
|
||||||
import { SsoLoginServiceAbstraction } from "@bitwarden/common/auth/abstractions/sso-login.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";
|
import { ForceSetPasswordReason } from "@bitwarden/common/auth/models/domain/force-set-password-reason";
|
||||||
import { SetPasswordRequest } from "@bitwarden/common/auth/models/request/set-password.request";
|
import { SetPasswordRequest } from "@bitwarden/common/auth/models/request/set-password.request";
|
||||||
@@ -31,7 +29,6 @@ import {
|
|||||||
import { Utils } from "@bitwarden/common/platform/misc/utils";
|
import { Utils } from "@bitwarden/common/platform/misc/utils";
|
||||||
import { EncString } from "@bitwarden/common/platform/models/domain/enc-string";
|
import { EncString } from "@bitwarden/common/platform/models/domain/enc-string";
|
||||||
import { PasswordGenerationServiceAbstraction } from "@bitwarden/common/tools/generator/password";
|
import { PasswordGenerationServiceAbstraction } from "@bitwarden/common/tools/generator/password";
|
||||||
import { UserId } from "@bitwarden/common/types/guid";
|
|
||||||
import { MasterKey, UserKey } from "@bitwarden/common/types/key";
|
import { MasterKey, UserKey } from "@bitwarden/common/types/key";
|
||||||
import { SyncService } from "@bitwarden/common/vault/abstractions/sync/sync.service.abstraction";
|
import { SyncService } from "@bitwarden/common/vault/abstractions/sync/sync.service.abstraction";
|
||||||
import { DialogService } from "@bitwarden/components";
|
import { DialogService } from "@bitwarden/components";
|
||||||
@@ -48,14 +45,11 @@ export class SetPasswordComponent extends BaseChangePasswordComponent {
|
|||||||
resetPasswordAutoEnroll = false;
|
resetPasswordAutoEnroll = false;
|
||||||
onSuccessfulChangePassword: () => Promise<void>;
|
onSuccessfulChangePassword: () => Promise<void>;
|
||||||
successRoute = "vault";
|
successRoute = "vault";
|
||||||
userId: UserId;
|
|
||||||
|
|
||||||
forceSetPasswordReason: ForceSetPasswordReason = ForceSetPasswordReason.None;
|
forceSetPasswordReason: ForceSetPasswordReason = ForceSetPasswordReason.None;
|
||||||
ForceSetPasswordReason = ForceSetPasswordReason;
|
ForceSetPasswordReason = ForceSetPasswordReason;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private accountService: AccountService,
|
|
||||||
private masterPasswordService: InternalMasterPasswordServiceAbstraction,
|
|
||||||
i18nService: I18nService,
|
i18nService: I18nService,
|
||||||
cryptoService: CryptoService,
|
cryptoService: CryptoService,
|
||||||
messagingService: MessagingService,
|
messagingService: MessagingService,
|
||||||
@@ -94,11 +88,7 @@ export class SetPasswordComponent extends BaseChangePasswordComponent {
|
|||||||
await this.syncService.fullSync(true);
|
await this.syncService.fullSync(true);
|
||||||
this.syncLoading = false;
|
this.syncLoading = false;
|
||||||
|
|
||||||
this.userId = (await firstValueFrom(this.accountService.activeAccount$))?.id;
|
this.forceSetPasswordReason = await this.stateService.getForceSetPasswordReason();
|
||||||
|
|
||||||
this.forceSetPasswordReason = await firstValueFrom(
|
|
||||||
this.masterPasswordService.forceSetPasswordReason$(this.userId),
|
|
||||||
);
|
|
||||||
|
|
||||||
this.route.queryParams
|
this.route.queryParams
|
||||||
.pipe(
|
.pipe(
|
||||||
@@ -186,6 +176,7 @@ export class SetPasswordComponent extends BaseChangePasswordComponent {
|
|||||||
if (response == null) {
|
if (response == null) {
|
||||||
throw new Error(this.i18nService.t("resetPasswordOrgKeysError"));
|
throw new Error(this.i18nService.t("resetPasswordOrgKeysError"));
|
||||||
}
|
}
|
||||||
|
const userId = await this.stateService.getUserId();
|
||||||
const publicKey = Utils.fromB64ToArray(response.publicKey);
|
const publicKey = Utils.fromB64ToArray(response.publicKey);
|
||||||
|
|
||||||
// RSA Encrypt user key with organization public key
|
// RSA Encrypt user key with organization public key
|
||||||
@@ -198,7 +189,7 @@ export class SetPasswordComponent extends BaseChangePasswordComponent {
|
|||||||
|
|
||||||
return this.organizationUserService.putOrganizationUserResetPasswordEnrollment(
|
return this.organizationUserService.putOrganizationUserResetPasswordEnrollment(
|
||||||
this.orgId,
|
this.orgId,
|
||||||
this.userId,
|
userId,
|
||||||
resetRequest,
|
resetRequest,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
@@ -235,10 +226,7 @@ export class SetPasswordComponent extends BaseChangePasswordComponent {
|
|||||||
keyPair: [string, EncString] | null,
|
keyPair: [string, EncString] | null,
|
||||||
) {
|
) {
|
||||||
// Clear force set password reason to allow navigation back to vault.
|
// Clear force set password reason to allow navigation back to vault.
|
||||||
await this.masterPasswordService.setForceSetPasswordReason(
|
await this.stateService.setForceSetPasswordReason(ForceSetPasswordReason.None);
|
||||||
ForceSetPasswordReason.None,
|
|
||||||
this.userId,
|
|
||||||
);
|
|
||||||
|
|
||||||
// User now has a password so update account decryption options in state
|
// User now has a password so update account decryption options in state
|
||||||
const userDecryptionOpts = await firstValueFrom(
|
const userDecryptionOpts = await firstValueFrom(
|
||||||
@@ -249,7 +237,7 @@ export class SetPasswordComponent extends BaseChangePasswordComponent {
|
|||||||
|
|
||||||
await this.stateService.setKdfType(this.kdf);
|
await this.stateService.setKdfType(this.kdf);
|
||||||
await this.stateService.setKdfConfig(this.kdfConfig);
|
await this.stateService.setKdfConfig(this.kdfConfig);
|
||||||
await this.masterPasswordService.setMasterKey(masterKey, this.userId);
|
await this.cryptoService.setMasterKey(masterKey);
|
||||||
await this.cryptoService.setUserKey(userKey[0]);
|
await this.cryptoService.setUserKey(userKey[0]);
|
||||||
|
|
||||||
// Set private key only for new JIT provisioned users in MP encryption orgs
|
// Set private key only for new JIT provisioned users in MP encryption orgs
|
||||||
@@ -267,6 +255,6 @@ export class SetPasswordComponent extends BaseChangePasswordComponent {
|
|||||||
masterKey,
|
masterKey,
|
||||||
HashPurpose.LocalAuthorization,
|
HashPurpose.LocalAuthorization,
|
||||||
);
|
);
|
||||||
await this.masterPasswordService.setMasterKeyHash(localMasterKeyHash, this.userId);
|
await this.cryptoService.setMasterKeyHash(localMasterKeyHash);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,13 +12,10 @@ import {
|
|||||||
UserDecryptionOptionsServiceAbstraction,
|
UserDecryptionOptionsServiceAbstraction,
|
||||||
} from "@bitwarden/auth/common";
|
} from "@bitwarden/auth/common";
|
||||||
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
||||||
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
|
||||||
import { InternalMasterPasswordServiceAbstraction } from "@bitwarden/common/auth/abstractions/master-password.service.abstraction";
|
|
||||||
import { SsoLoginServiceAbstraction } from "@bitwarden/common/auth/abstractions/sso-login.service.abstraction";
|
import { SsoLoginServiceAbstraction } from "@bitwarden/common/auth/abstractions/sso-login.service.abstraction";
|
||||||
import { TwoFactorProviderType } from "@bitwarden/common/auth/enums/two-factor-provider-type";
|
import { TwoFactorProviderType } from "@bitwarden/common/auth/enums/two-factor-provider-type";
|
||||||
import { AuthResult } from "@bitwarden/common/auth/models/domain/auth-result";
|
import { AuthResult } from "@bitwarden/common/auth/models/domain/auth-result";
|
||||||
import { ForceSetPasswordReason } from "@bitwarden/common/auth/models/domain/force-set-password-reason";
|
import { ForceSetPasswordReason } from "@bitwarden/common/auth/models/domain/force-set-password-reason";
|
||||||
import { FakeMasterPasswordService } from "@bitwarden/common/auth/services/master-password/fake-master-password.service";
|
|
||||||
import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service";
|
import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service";
|
||||||
import { CryptoFunctionService } from "@bitwarden/common/platform/abstractions/crypto-function.service";
|
import { CryptoFunctionService } from "@bitwarden/common/platform/abstractions/crypto-function.service";
|
||||||
import { EnvironmentService } from "@bitwarden/common/platform/abstractions/environment.service";
|
import { EnvironmentService } from "@bitwarden/common/platform/abstractions/environment.service";
|
||||||
@@ -26,9 +23,7 @@ import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.servic
|
|||||||
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
|
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
|
||||||
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
||||||
import { StateService } from "@bitwarden/common/platform/abstractions/state.service";
|
import { StateService } from "@bitwarden/common/platform/abstractions/state.service";
|
||||||
import { FakeAccountService, mockAccountServiceWith } from "@bitwarden/common/spec";
|
|
||||||
import { PasswordGenerationServiceAbstraction } from "@bitwarden/common/tools/generator/password";
|
import { PasswordGenerationServiceAbstraction } from "@bitwarden/common/tools/generator/password";
|
||||||
import { UserId } from "@bitwarden/common/types/guid";
|
|
||||||
|
|
||||||
import { SsoComponent } from "./sso.component";
|
import { SsoComponent } from "./sso.component";
|
||||||
// test component that extends the SsoComponent
|
// test component that extends the SsoComponent
|
||||||
@@ -53,7 +48,6 @@ describe("SsoComponent", () => {
|
|||||||
let component: TestSsoComponent;
|
let component: TestSsoComponent;
|
||||||
let _component: SsoComponentProtected;
|
let _component: SsoComponentProtected;
|
||||||
let fixture: ComponentFixture<TestSsoComponent>;
|
let fixture: ComponentFixture<TestSsoComponent>;
|
||||||
const userId = "userId" as UserId;
|
|
||||||
|
|
||||||
// Mock Services
|
// Mock Services
|
||||||
let mockLoginStrategyService: MockProxy<LoginStrategyServiceAbstraction>;
|
let mockLoginStrategyService: MockProxy<LoginStrategyServiceAbstraction>;
|
||||||
@@ -73,8 +67,6 @@ describe("SsoComponent", () => {
|
|||||||
let mockLogService: MockProxy<LogService>;
|
let mockLogService: MockProxy<LogService>;
|
||||||
let mockUserDecryptionOptionsService: MockProxy<UserDecryptionOptionsServiceAbstraction>;
|
let mockUserDecryptionOptionsService: MockProxy<UserDecryptionOptionsServiceAbstraction>;
|
||||||
let mockConfigService: MockProxy<ConfigService>;
|
let mockConfigService: MockProxy<ConfigService>;
|
||||||
let mockMasterPasswordService: FakeMasterPasswordService;
|
|
||||||
let mockAccountService: FakeAccountService;
|
|
||||||
|
|
||||||
// Mock authService.logIn params
|
// Mock authService.logIn params
|
||||||
let code: string;
|
let code: string;
|
||||||
@@ -125,8 +117,6 @@ describe("SsoComponent", () => {
|
|||||||
mockLogService = mock();
|
mockLogService = mock();
|
||||||
mockUserDecryptionOptionsService = mock();
|
mockUserDecryptionOptionsService = mock();
|
||||||
mockConfigService = mock();
|
mockConfigService = mock();
|
||||||
mockAccountService = mockAccountServiceWith(userId);
|
|
||||||
mockMasterPasswordService = new FakeMasterPasswordService();
|
|
||||||
|
|
||||||
// Mock loginStrategyService.logIn params
|
// Mock loginStrategyService.logIn params
|
||||||
code = "code";
|
code = "code";
|
||||||
@@ -209,8 +199,6 @@ describe("SsoComponent", () => {
|
|||||||
},
|
},
|
||||||
{ provide: LogService, useValue: mockLogService },
|
{ provide: LogService, useValue: mockLogService },
|
||||||
{ provide: ConfigService, useValue: mockConfigService },
|
{ provide: ConfigService, useValue: mockConfigService },
|
||||||
{ provide: InternalMasterPasswordServiceAbstraction, useValue: mockMasterPasswordService },
|
|
||||||
{ provide: AccountService, useValue: mockAccountService },
|
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -377,9 +365,8 @@ describe("SsoComponent", () => {
|
|||||||
await _component.logIn(code, codeVerifier, orgIdFromState);
|
await _component.logIn(code, codeVerifier, orgIdFromState);
|
||||||
expect(mockLoginStrategyService.logIn).toHaveBeenCalledTimes(1);
|
expect(mockLoginStrategyService.logIn).toHaveBeenCalledTimes(1);
|
||||||
|
|
||||||
expect(mockMasterPasswordService.mock.setForceSetPasswordReason).toHaveBeenCalledWith(
|
expect(mockStateService.setForceSetPasswordReason).toHaveBeenCalledWith(
|
||||||
ForceSetPasswordReason.TdeUserWithoutPasswordHasPasswordResetPermission,
|
ForceSetPasswordReason.TdeUserWithoutPasswordHasPasswordResetPermission,
|
||||||
userId,
|
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(mockOnSuccessfulLoginTdeNavigate).not.toHaveBeenCalled();
|
expect(mockOnSuccessfulLoginTdeNavigate).not.toHaveBeenCalled();
|
||||||
|
|||||||
@@ -11,8 +11,6 @@ import {
|
|||||||
UserDecryptionOptionsServiceAbstraction,
|
UserDecryptionOptionsServiceAbstraction,
|
||||||
} from "@bitwarden/auth/common";
|
} from "@bitwarden/auth/common";
|
||||||
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
||||||
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
|
||||||
import { InternalMasterPasswordServiceAbstraction } from "@bitwarden/common/auth/abstractions/master-password.service.abstraction";
|
|
||||||
import { SsoLoginServiceAbstraction } from "@bitwarden/common/auth/abstractions/sso-login.service.abstraction";
|
import { SsoLoginServiceAbstraction } from "@bitwarden/common/auth/abstractions/sso-login.service.abstraction";
|
||||||
import { AuthResult } from "@bitwarden/common/auth/models/domain/auth-result";
|
import { AuthResult } from "@bitwarden/common/auth/models/domain/auth-result";
|
||||||
import { ForceSetPasswordReason } from "@bitwarden/common/auth/models/domain/force-set-password-reason";
|
import { ForceSetPasswordReason } from "@bitwarden/common/auth/models/domain/force-set-password-reason";
|
||||||
@@ -68,8 +66,6 @@ export class SsoComponent {
|
|||||||
protected logService: LogService,
|
protected logService: LogService,
|
||||||
protected userDecryptionOptionsService: UserDecryptionOptionsServiceAbstraction,
|
protected userDecryptionOptionsService: UserDecryptionOptionsServiceAbstraction,
|
||||||
protected configService: ConfigService,
|
protected configService: ConfigService,
|
||||||
protected masterPasswordService: InternalMasterPasswordServiceAbstraction,
|
|
||||||
protected accountService: AccountService,
|
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
async ngOnInit() {
|
async ngOnInit() {
|
||||||
@@ -294,10 +290,8 @@ export class SsoComponent {
|
|||||||
// Set flag so that auth guard can redirect to set password screen after decryption (trusted or untrusted device)
|
// Set flag so that auth guard can redirect to set password screen after decryption (trusted or untrusted device)
|
||||||
// Note: we cannot directly navigate in this scenario as we are in a pre-decryption state, and
|
// Note: we cannot directly navigate in this scenario as we are in a pre-decryption state, and
|
||||||
// if you try to set a new MP before decrypting, you will invalidate the user's data by making a new user key.
|
// if you try to set a new MP before decrypting, you will invalidate the user's data by making a new user key.
|
||||||
const userId = (await firstValueFrom(this.accountService.activeAccount$))?.id;
|
await this.stateService.setForceSetPasswordReason(
|
||||||
await this.masterPasswordService.setForceSetPasswordReason(
|
|
||||||
ForceSetPasswordReason.TdeUserWithoutPasswordHasPasswordResetPermission,
|
ForceSetPasswordReason.TdeUserWithoutPasswordHasPasswordResetPermission,
|
||||||
userId,
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -15,14 +15,11 @@ import {
|
|||||||
UserDecryptionOptionsServiceAbstraction,
|
UserDecryptionOptionsServiceAbstraction,
|
||||||
} from "@bitwarden/auth/common";
|
} from "@bitwarden/auth/common";
|
||||||
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
||||||
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
|
||||||
import { InternalMasterPasswordServiceAbstraction } from "@bitwarden/common/auth/abstractions/master-password.service.abstraction";
|
|
||||||
import { SsoLoginServiceAbstraction } from "@bitwarden/common/auth/abstractions/sso-login.service.abstraction";
|
import { SsoLoginServiceAbstraction } from "@bitwarden/common/auth/abstractions/sso-login.service.abstraction";
|
||||||
import { TwoFactorService } from "@bitwarden/common/auth/abstractions/two-factor.service";
|
import { TwoFactorService } from "@bitwarden/common/auth/abstractions/two-factor.service";
|
||||||
import { AuthResult } from "@bitwarden/common/auth/models/domain/auth-result";
|
import { AuthResult } from "@bitwarden/common/auth/models/domain/auth-result";
|
||||||
import { ForceSetPasswordReason } from "@bitwarden/common/auth/models/domain/force-set-password-reason";
|
import { ForceSetPasswordReason } from "@bitwarden/common/auth/models/domain/force-set-password-reason";
|
||||||
import { TokenTwoFactorRequest } from "@bitwarden/common/auth/models/request/identity-token/token-two-factor.request";
|
import { TokenTwoFactorRequest } from "@bitwarden/common/auth/models/request/identity-token/token-two-factor.request";
|
||||||
import { FakeMasterPasswordService } from "@bitwarden/common/auth/services/master-password/fake-master-password.service";
|
|
||||||
import { AppIdService } from "@bitwarden/common/platform/abstractions/app-id.service";
|
import { AppIdService } from "@bitwarden/common/platform/abstractions/app-id.service";
|
||||||
import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service";
|
import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service";
|
||||||
import { EnvironmentService } from "@bitwarden/common/platform/abstractions/environment.service";
|
import { EnvironmentService } from "@bitwarden/common/platform/abstractions/environment.service";
|
||||||
@@ -30,8 +27,6 @@ import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.servic
|
|||||||
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
|
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
|
||||||
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
||||||
import { StateService } from "@bitwarden/common/platform/abstractions/state.service";
|
import { StateService } from "@bitwarden/common/platform/abstractions/state.service";
|
||||||
import { FakeAccountService, mockAccountServiceWith } from "@bitwarden/common/spec";
|
|
||||||
import { UserId } from "@bitwarden/common/types/guid";
|
|
||||||
|
|
||||||
import { TwoFactorComponent } from "./two-factor.component";
|
import { TwoFactorComponent } from "./two-factor.component";
|
||||||
|
|
||||||
@@ -51,7 +46,6 @@ describe("TwoFactorComponent", () => {
|
|||||||
let _component: TwoFactorComponentProtected;
|
let _component: TwoFactorComponentProtected;
|
||||||
|
|
||||||
let fixture: ComponentFixture<TestTwoFactorComponent>;
|
let fixture: ComponentFixture<TestTwoFactorComponent>;
|
||||||
const userId = "userId" as UserId;
|
|
||||||
|
|
||||||
// Mock Services
|
// Mock Services
|
||||||
let mockLoginStrategyService: MockProxy<LoginStrategyServiceAbstraction>;
|
let mockLoginStrategyService: MockProxy<LoginStrategyServiceAbstraction>;
|
||||||
@@ -69,8 +63,6 @@ describe("TwoFactorComponent", () => {
|
|||||||
let mockUserDecryptionOptionsService: MockProxy<UserDecryptionOptionsServiceAbstraction>;
|
let mockUserDecryptionOptionsService: MockProxy<UserDecryptionOptionsServiceAbstraction>;
|
||||||
let mockSsoLoginService: MockProxy<SsoLoginServiceAbstraction>;
|
let mockSsoLoginService: MockProxy<SsoLoginServiceAbstraction>;
|
||||||
let mockConfigService: MockProxy<ConfigService>;
|
let mockConfigService: MockProxy<ConfigService>;
|
||||||
let mockMasterPasswordService: FakeMasterPasswordService;
|
|
||||||
let mockAccountService: FakeAccountService;
|
|
||||||
|
|
||||||
let mockUserDecryptionOpts: {
|
let mockUserDecryptionOpts: {
|
||||||
noMasterPassword: UserDecryptionOptions;
|
noMasterPassword: UserDecryptionOptions;
|
||||||
@@ -101,8 +93,6 @@ describe("TwoFactorComponent", () => {
|
|||||||
mockUserDecryptionOptionsService = mock<UserDecryptionOptionsServiceAbstraction>();
|
mockUserDecryptionOptionsService = mock<UserDecryptionOptionsServiceAbstraction>();
|
||||||
mockSsoLoginService = mock<SsoLoginServiceAbstraction>();
|
mockSsoLoginService = mock<SsoLoginServiceAbstraction>();
|
||||||
mockConfigService = mock<ConfigService>();
|
mockConfigService = mock<ConfigService>();
|
||||||
mockAccountService = mockAccountServiceWith(userId);
|
|
||||||
mockMasterPasswordService = new FakeMasterPasswordService();
|
|
||||||
|
|
||||||
mockUserDecryptionOpts = {
|
mockUserDecryptionOpts = {
|
||||||
noMasterPassword: new UserDecryptionOptions({
|
noMasterPassword: new UserDecryptionOptions({
|
||||||
@@ -180,8 +170,6 @@ describe("TwoFactorComponent", () => {
|
|||||||
},
|
},
|
||||||
{ provide: SsoLoginServiceAbstraction, useValue: mockSsoLoginService },
|
{ provide: SsoLoginServiceAbstraction, useValue: mockSsoLoginService },
|
||||||
{ provide: ConfigService, useValue: mockConfigService },
|
{ provide: ConfigService, useValue: mockConfigService },
|
||||||
{ provide: InternalMasterPasswordServiceAbstraction, useValue: mockMasterPasswordService },
|
|
||||||
{ provide: AccountService, useValue: mockAccountService },
|
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -419,9 +407,9 @@ describe("TwoFactorComponent", () => {
|
|||||||
await component.doSubmit();
|
await component.doSubmit();
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
expect(mockMasterPasswordService.mock.setForceSetPasswordReason).toHaveBeenCalledWith(
|
|
||||||
|
expect(mockStateService.setForceSetPasswordReason).toHaveBeenCalledWith(
|
||||||
ForceSetPasswordReason.TdeUserWithoutPasswordHasPasswordResetPermission,
|
ForceSetPasswordReason.TdeUserWithoutPasswordHasPasswordResetPermission,
|
||||||
userId,
|
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(mockRouter.navigate).toHaveBeenCalledTimes(1);
|
expect(mockRouter.navigate).toHaveBeenCalledTimes(1);
|
||||||
|
|||||||
@@ -14,8 +14,6 @@ import {
|
|||||||
UserDecryptionOptionsServiceAbstraction,
|
UserDecryptionOptionsServiceAbstraction,
|
||||||
} from "@bitwarden/auth/common";
|
} from "@bitwarden/auth/common";
|
||||||
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
||||||
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
|
||||||
import { InternalMasterPasswordServiceAbstraction } from "@bitwarden/common/auth/abstractions/master-password.service.abstraction";
|
|
||||||
import { SsoLoginServiceAbstraction } from "@bitwarden/common/auth/abstractions/sso-login.service.abstraction";
|
import { SsoLoginServiceAbstraction } from "@bitwarden/common/auth/abstractions/sso-login.service.abstraction";
|
||||||
import { TwoFactorService } from "@bitwarden/common/auth/abstractions/two-factor.service";
|
import { TwoFactorService } from "@bitwarden/common/auth/abstractions/two-factor.service";
|
||||||
import { AuthenticationType } from "@bitwarden/common/auth/enums/authentication-type";
|
import { AuthenticationType } from "@bitwarden/common/auth/enums/authentication-type";
|
||||||
@@ -94,8 +92,6 @@ export class TwoFactorComponent extends CaptchaProtectedComponent implements OnI
|
|||||||
protected userDecryptionOptionsService: UserDecryptionOptionsServiceAbstraction,
|
protected userDecryptionOptionsService: UserDecryptionOptionsServiceAbstraction,
|
||||||
protected ssoLoginService: SsoLoginServiceAbstraction,
|
protected ssoLoginService: SsoLoginServiceAbstraction,
|
||||||
protected configService: ConfigService,
|
protected configService: ConfigService,
|
||||||
protected masterPasswordService: InternalMasterPasswordServiceAbstraction,
|
|
||||||
protected accountService: AccountService,
|
|
||||||
) {
|
) {
|
||||||
super(environmentService, i18nService, platformUtilsService);
|
super(environmentService, i18nService, platformUtilsService);
|
||||||
this.webAuthnSupported = this.platformUtilsService.supportsWebAuthn(win);
|
this.webAuthnSupported = this.platformUtilsService.supportsWebAuthn(win);
|
||||||
@@ -346,10 +342,8 @@ export class TwoFactorComponent extends CaptchaProtectedComponent implements OnI
|
|||||||
// Set flag so that auth guard can redirect to set password screen after decryption (trusted or untrusted device)
|
// Set flag so that auth guard can redirect to set password screen after decryption (trusted or untrusted device)
|
||||||
// Note: we cannot directly navigate to the set password screen in this scenario as we are in a pre-decryption state, and
|
// Note: we cannot directly navigate to the set password screen in this scenario as we are in a pre-decryption state, and
|
||||||
// if you try to set a new MP before decrypting, you will invalidate the user's data by making a new user key.
|
// if you try to set a new MP before decrypting, you will invalidate the user's data by making a new user key.
|
||||||
const userId = (await firstValueFrom(this.accountService.activeAccount$))?.id;
|
await this.stateService.setForceSetPasswordReason(
|
||||||
await this.masterPasswordService.setForceSetPasswordReason(
|
|
||||||
ForceSetPasswordReason.TdeUserWithoutPasswordHasPasswordResetPermission,
|
ForceSetPasswordReason.TdeUserWithoutPasswordHasPasswordResetPermission,
|
||||||
userId,
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,12 +1,9 @@
|
|||||||
import { Directive } from "@angular/core";
|
import { Directive } from "@angular/core";
|
||||||
import { Router } from "@angular/router";
|
import { Router } from "@angular/router";
|
||||||
import { firstValueFrom } from "rxjs";
|
|
||||||
|
|
||||||
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
||||||
import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction";
|
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 { MasterPasswordPolicyOptions } from "@bitwarden/common/admin-console/models/domain/master-password-policy-options";
|
||||||
import { AccountService } from "@bitwarden/common/auth/abstractions/account.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 { UserVerificationService } from "@bitwarden/common/auth/abstractions/user-verification/user-verification.service.abstraction";
|
||||||
import { VerificationType } from "@bitwarden/common/auth/enums/verification-type";
|
import { VerificationType } from "@bitwarden/common/auth/enums/verification-type";
|
||||||
import { ForceSetPasswordReason } from "@bitwarden/common/auth/models/domain/force-set-password-reason";
|
import { ForceSetPasswordReason } from "@bitwarden/common/auth/models/domain/force-set-password-reason";
|
||||||
@@ -59,8 +56,6 @@ export class UpdateTempPasswordComponent extends BaseChangePasswordComponent {
|
|||||||
private userVerificationService: UserVerificationService,
|
private userVerificationService: UserVerificationService,
|
||||||
protected router: Router,
|
protected router: Router,
|
||||||
dialogService: DialogService,
|
dialogService: DialogService,
|
||||||
private accountService: AccountService,
|
|
||||||
private masterPasswordService: InternalMasterPasswordServiceAbstraction,
|
|
||||||
) {
|
) {
|
||||||
super(
|
super(
|
||||||
i18nService,
|
i18nService,
|
||||||
@@ -77,8 +72,7 @@ export class UpdateTempPasswordComponent extends BaseChangePasswordComponent {
|
|||||||
async ngOnInit() {
|
async ngOnInit() {
|
||||||
await this.syncService.fullSync(true);
|
await this.syncService.fullSync(true);
|
||||||
|
|
||||||
const userId = (await firstValueFrom(this.accountService.activeAccount$))?.id;
|
this.reason = await this.stateService.getForceSetPasswordReason();
|
||||||
this.reason = await firstValueFrom(this.masterPasswordService.forceSetPasswordReason$(userId));
|
|
||||||
|
|
||||||
// If we somehow end up here without a reason, go back to the home page
|
// If we somehow end up here without a reason, go back to the home page
|
||||||
if (this.reason == ForceSetPasswordReason.None) {
|
if (this.reason == ForceSetPasswordReason.None) {
|
||||||
@@ -169,11 +163,7 @@ export class UpdateTempPasswordComponent extends BaseChangePasswordComponent {
|
|||||||
this.i18nService.t("updatedMasterPassword"),
|
this.i18nService.t("updatedMasterPassword"),
|
||||||
);
|
);
|
||||||
|
|
||||||
const userId = (await firstValueFrom(this.accountService.activeAccount$))?.id;
|
await this.stateService.setForceSetPasswordReason(ForceSetPasswordReason.None);
|
||||||
await this.masterPasswordService.setForceSetPasswordReason(
|
|
||||||
ForceSetPasswordReason.None,
|
|
||||||
userId,
|
|
||||||
);
|
|
||||||
|
|
||||||
if (this.onSuccessfulChangePassword != null) {
|
if (this.onSuccessfulChangePassword != null) {
|
||||||
// FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling.
|
// FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling.
|
||||||
|
|||||||
@@ -1,14 +1,12 @@
|
|||||||
import { Injectable } from "@angular/core";
|
import { Injectable } from "@angular/core";
|
||||||
import { ActivatedRouteSnapshot, CanActivate, Router, RouterStateSnapshot } from "@angular/router";
|
import { ActivatedRouteSnapshot, CanActivate, Router, RouterStateSnapshot } from "@angular/router";
|
||||||
import { firstValueFrom } from "rxjs";
|
|
||||||
|
|
||||||
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
|
||||||
import { AuthService } from "@bitwarden/common/auth/abstractions/auth.service";
|
import { AuthService } from "@bitwarden/common/auth/abstractions/auth.service";
|
||||||
import { KeyConnectorService } from "@bitwarden/common/auth/abstractions/key-connector.service";
|
import { KeyConnectorService } from "@bitwarden/common/auth/abstractions/key-connector.service";
|
||||||
import { MasterPasswordServiceAbstraction } from "@bitwarden/common/auth/abstractions/master-password.service.abstraction";
|
|
||||||
import { AuthenticationStatus } from "@bitwarden/common/auth/enums/authentication-status";
|
import { AuthenticationStatus } from "@bitwarden/common/auth/enums/authentication-status";
|
||||||
import { ForceSetPasswordReason } from "@bitwarden/common/auth/models/domain/force-set-password-reason";
|
import { ForceSetPasswordReason } from "@bitwarden/common/auth/models/domain/force-set-password-reason";
|
||||||
import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service";
|
import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service";
|
||||||
|
import { StateService } from "@bitwarden/common/platform/abstractions/state.service";
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class AuthGuard implements CanActivate {
|
export class AuthGuard implements CanActivate {
|
||||||
@@ -17,8 +15,7 @@ export class AuthGuard implements CanActivate {
|
|||||||
private router: Router,
|
private router: Router,
|
||||||
private messagingService: MessagingService,
|
private messagingService: MessagingService,
|
||||||
private keyConnectorService: KeyConnectorService,
|
private keyConnectorService: KeyConnectorService,
|
||||||
private accountService: AccountService,
|
private stateService: StateService,
|
||||||
private masterPasswordService: MasterPasswordServiceAbstraction,
|
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
async canActivate(route: ActivatedRouteSnapshot, routerState: RouterStateSnapshot) {
|
async canActivate(route: ActivatedRouteSnapshot, routerState: RouterStateSnapshot) {
|
||||||
@@ -43,10 +40,7 @@ export class AuthGuard implements CanActivate {
|
|||||||
return this.router.createUrlTree(["/remove-password"]);
|
return this.router.createUrlTree(["/remove-password"]);
|
||||||
}
|
}
|
||||||
|
|
||||||
const userId = (await firstValueFrom(this.accountService.activeAccount$)).id;
|
const forceSetPasswordReason = await this.stateService.getForceSetPasswordReason();
|
||||||
const forceSetPasswordReason = await firstValueFrom(
|
|
||||||
this.masterPasswordService.forceSetPasswordReason$(userId),
|
|
||||||
);
|
|
||||||
|
|
||||||
if (
|
if (
|
||||||
forceSetPasswordReason ===
|
forceSetPasswordReason ===
|
||||||
|
|||||||
@@ -60,10 +60,6 @@ import { DeviceTrustCryptoServiceAbstraction } from "@bitwarden/common/auth/abst
|
|||||||
import { DevicesServiceAbstraction } from "@bitwarden/common/auth/abstractions/devices/devices.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 { DevicesApiServiceAbstraction } from "@bitwarden/common/auth/abstractions/devices-api.service.abstraction";
|
||||||
import { KeyConnectorService as KeyConnectorServiceAbstraction } from "@bitwarden/common/auth/abstractions/key-connector.service";
|
import { KeyConnectorService as KeyConnectorServiceAbstraction } from "@bitwarden/common/auth/abstractions/key-connector.service";
|
||||||
import {
|
|
||||||
InternalMasterPasswordServiceAbstraction,
|
|
||||||
MasterPasswordServiceAbstraction,
|
|
||||||
} from "@bitwarden/common/auth/abstractions/master-password.service.abstraction";
|
|
||||||
import { PasswordResetEnrollmentServiceAbstraction } from "@bitwarden/common/auth/abstractions/password-reset-enrollment.service.abstraction";
|
import { PasswordResetEnrollmentServiceAbstraction } from "@bitwarden/common/auth/abstractions/password-reset-enrollment.service.abstraction";
|
||||||
import { SsoLoginServiceAbstraction } from "@bitwarden/common/auth/abstractions/sso-login.service.abstraction";
|
import { SsoLoginServiceAbstraction } from "@bitwarden/common/auth/abstractions/sso-login.service.abstraction";
|
||||||
import { TokenService as TokenServiceAbstraction } from "@bitwarden/common/auth/abstractions/token.service";
|
import { TokenService as TokenServiceAbstraction } from "@bitwarden/common/auth/abstractions/token.service";
|
||||||
@@ -82,7 +78,6 @@ import { DeviceTrustCryptoService } from "@bitwarden/common/auth/services/device
|
|||||||
import { DevicesServiceImplementation } from "@bitwarden/common/auth/services/devices/devices.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 { DevicesApiServiceImplementation } from "@bitwarden/common/auth/services/devices-api.service.implementation";
|
||||||
import { KeyConnectorService } from "@bitwarden/common/auth/services/key-connector.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";
|
import { PasswordResetEnrollmentServiceImplementation } from "@bitwarden/common/auth/services/password-reset-enrollment.service.implementation";
|
||||||
import { SsoLoginService } from "@bitwarden/common/auth/services/sso-login.service";
|
import { SsoLoginService } from "@bitwarden/common/auth/services/sso-login.service";
|
||||||
import { TokenService } from "@bitwarden/common/auth/services/token.service";
|
import { TokenService } from "@bitwarden/common/auth/services/token.service";
|
||||||
@@ -364,8 +359,6 @@ const safeProviders: SafeProvider[] = [
|
|||||||
provide: LoginStrategyServiceAbstraction,
|
provide: LoginStrategyServiceAbstraction,
|
||||||
useClass: LoginStrategyService,
|
useClass: LoginStrategyService,
|
||||||
deps: [
|
deps: [
|
||||||
AccountServiceAbstraction,
|
|
||||||
InternalMasterPasswordServiceAbstraction,
|
|
||||||
CryptoServiceAbstraction,
|
CryptoServiceAbstraction,
|
||||||
ApiServiceAbstraction,
|
ApiServiceAbstraction,
|
||||||
TokenServiceAbstraction,
|
TokenServiceAbstraction,
|
||||||
@@ -528,7 +521,6 @@ const safeProviders: SafeProvider[] = [
|
|||||||
provide: CryptoServiceAbstraction,
|
provide: CryptoServiceAbstraction,
|
||||||
useClass: CryptoService,
|
useClass: CryptoService,
|
||||||
deps: [
|
deps: [
|
||||||
InternalMasterPasswordServiceAbstraction,
|
|
||||||
KeyGenerationServiceAbstraction,
|
KeyGenerationServiceAbstraction,
|
||||||
CryptoFunctionServiceAbstraction,
|
CryptoFunctionServiceAbstraction,
|
||||||
EncryptService,
|
EncryptService,
|
||||||
@@ -595,8 +587,6 @@ const safeProviders: SafeProvider[] = [
|
|||||||
provide: SyncServiceAbstraction,
|
provide: SyncServiceAbstraction,
|
||||||
useClass: SyncService,
|
useClass: SyncService,
|
||||||
deps: [
|
deps: [
|
||||||
InternalMasterPasswordServiceAbstraction,
|
|
||||||
AccountServiceAbstraction,
|
|
||||||
ApiServiceAbstraction,
|
ApiServiceAbstraction,
|
||||||
DomainSettingsService,
|
DomainSettingsService,
|
||||||
InternalFolderService,
|
InternalFolderService,
|
||||||
@@ -636,8 +626,6 @@ const safeProviders: SafeProvider[] = [
|
|||||||
provide: VaultTimeoutService,
|
provide: VaultTimeoutService,
|
||||||
useClass: VaultTimeoutService,
|
useClass: VaultTimeoutService,
|
||||||
deps: [
|
deps: [
|
||||||
AccountServiceAbstraction,
|
|
||||||
InternalMasterPasswordServiceAbstraction,
|
|
||||||
CipherServiceAbstraction,
|
CipherServiceAbstraction,
|
||||||
FolderServiceAbstraction,
|
FolderServiceAbstraction,
|
||||||
CollectionServiceAbstraction,
|
CollectionServiceAbstraction,
|
||||||
@@ -783,21 +771,10 @@ const safeProviders: SafeProvider[] = [
|
|||||||
useClass: PolicyApiService,
|
useClass: PolicyApiService,
|
||||||
deps: [InternalPolicyService, ApiServiceAbstraction],
|
deps: [InternalPolicyService, ApiServiceAbstraction],
|
||||||
}),
|
}),
|
||||||
safeProvider({
|
|
||||||
provide: InternalMasterPasswordServiceAbstraction,
|
|
||||||
useClass: MasterPasswordService,
|
|
||||||
deps: [StateProvider],
|
|
||||||
}),
|
|
||||||
safeProvider({
|
|
||||||
provide: MasterPasswordServiceAbstraction,
|
|
||||||
useExisting: MasterPasswordServiceAbstraction,
|
|
||||||
}),
|
|
||||||
safeProvider({
|
safeProvider({
|
||||||
provide: KeyConnectorServiceAbstraction,
|
provide: KeyConnectorServiceAbstraction,
|
||||||
useClass: KeyConnectorService,
|
useClass: KeyConnectorService,
|
||||||
deps: [
|
deps: [
|
||||||
AccountServiceAbstraction,
|
|
||||||
InternalMasterPasswordServiceAbstraction,
|
|
||||||
CryptoServiceAbstraction,
|
CryptoServiceAbstraction,
|
||||||
ApiServiceAbstraction,
|
ApiServiceAbstraction,
|
||||||
TokenServiceAbstraction,
|
TokenServiceAbstraction,
|
||||||
@@ -814,8 +791,6 @@ const safeProviders: SafeProvider[] = [
|
|||||||
deps: [
|
deps: [
|
||||||
StateServiceAbstraction,
|
StateServiceAbstraction,
|
||||||
CryptoServiceAbstraction,
|
CryptoServiceAbstraction,
|
||||||
AccountServiceAbstraction,
|
|
||||||
InternalMasterPasswordServiceAbstraction,
|
|
||||||
I18nServiceAbstraction,
|
I18nServiceAbstraction,
|
||||||
UserVerificationApiServiceAbstraction,
|
UserVerificationApiServiceAbstraction,
|
||||||
UserDecryptionOptionsServiceAbstraction,
|
UserDecryptionOptionsServiceAbstraction,
|
||||||
@@ -959,10 +934,9 @@ const safeProviders: SafeProvider[] = [
|
|||||||
useClass: AuthRequestService,
|
useClass: AuthRequestService,
|
||||||
deps: [
|
deps: [
|
||||||
AppIdServiceAbstraction,
|
AppIdServiceAbstraction,
|
||||||
AccountServiceAbstraction,
|
|
||||||
InternalMasterPasswordServiceAbstraction,
|
|
||||||
CryptoServiceAbstraction,
|
CryptoServiceAbstraction,
|
||||||
ApiServiceAbstraction,
|
ApiServiceAbstraction,
|
||||||
|
StateServiceAbstraction,
|
||||||
],
|
],
|
||||||
}),
|
}),
|
||||||
safeProvider({
|
safeProvider({
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ import { DeviceTrustCryptoServiceAbstraction } from "@bitwarden/common/auth/abst
|
|||||||
import { TokenService } from "@bitwarden/common/auth/abstractions/token.service";
|
import { TokenService } from "@bitwarden/common/auth/abstractions/token.service";
|
||||||
import { TwoFactorService } from "@bitwarden/common/auth/abstractions/two-factor.service";
|
import { TwoFactorService } from "@bitwarden/common/auth/abstractions/two-factor.service";
|
||||||
import { IdentityTokenResponse } from "@bitwarden/common/auth/models/response/identity-token.response";
|
import { IdentityTokenResponse } from "@bitwarden/common/auth/models/response/identity-token.response";
|
||||||
import { FakeMasterPasswordService } from "@bitwarden/common/auth/services/master-password/fake-master-password.service";
|
|
||||||
import { BillingAccountProfileStateService } from "@bitwarden/common/billing/abstractions/account/billing-account-profile-state.service";
|
import { BillingAccountProfileStateService } from "@bitwarden/common/billing/abstractions/account/billing-account-profile-state.service";
|
||||||
import { AppIdService } from "@bitwarden/common/platform/abstractions/app-id.service";
|
import { AppIdService } from "@bitwarden/common/platform/abstractions/app-id.service";
|
||||||
import { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.service";
|
import { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.service";
|
||||||
@@ -15,9 +14,7 @@ import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/pl
|
|||||||
import { StateService } from "@bitwarden/common/platform/abstractions/state.service";
|
import { StateService } from "@bitwarden/common/platform/abstractions/state.service";
|
||||||
import { Utils } from "@bitwarden/common/platform/misc/utils";
|
import { Utils } from "@bitwarden/common/platform/misc/utils";
|
||||||
import { SymmetricCryptoKey } from "@bitwarden/common/platform/models/domain/symmetric-crypto-key";
|
import { SymmetricCryptoKey } from "@bitwarden/common/platform/models/domain/symmetric-crypto-key";
|
||||||
import { FakeAccountService, mockAccountServiceWith } from "@bitwarden/common/spec";
|
|
||||||
import { CsprngArray } from "@bitwarden/common/types/csprng";
|
import { CsprngArray } from "@bitwarden/common/types/csprng";
|
||||||
import { UserId } from "@bitwarden/common/types/guid";
|
|
||||||
import { MasterKey, UserKey } from "@bitwarden/common/types/key";
|
import { MasterKey, UserKey } from "@bitwarden/common/types/key";
|
||||||
|
|
||||||
import { InternalUserDecryptionOptionsServiceAbstraction } from "../abstractions/user-decryption-options.service.abstraction";
|
import { InternalUserDecryptionOptionsServiceAbstraction } from "../abstractions/user-decryption-options.service.abstraction";
|
||||||
@@ -45,10 +42,6 @@ describe("AuthRequestLoginStrategy", () => {
|
|||||||
let deviceTrustCryptoService: MockProxy<DeviceTrustCryptoServiceAbstraction>;
|
let deviceTrustCryptoService: MockProxy<DeviceTrustCryptoServiceAbstraction>;
|
||||||
let billingAccountProfileStateService: MockProxy<BillingAccountProfileStateService>;
|
let billingAccountProfileStateService: MockProxy<BillingAccountProfileStateService>;
|
||||||
|
|
||||||
const mockUserId = Utils.newGuid() as UserId;
|
|
||||||
let accountService: FakeAccountService;
|
|
||||||
let masterPasswordService: FakeMasterPasswordService;
|
|
||||||
|
|
||||||
let authRequestLoginStrategy: AuthRequestLoginStrategy;
|
let authRequestLoginStrategy: AuthRequestLoginStrategy;
|
||||||
let credentials: AuthRequestLoginCredentials;
|
let credentials: AuthRequestLoginCredentials;
|
||||||
let tokenResponse: IdentityTokenResponse;
|
let tokenResponse: IdentityTokenResponse;
|
||||||
@@ -78,17 +71,12 @@ describe("AuthRequestLoginStrategy", () => {
|
|||||||
deviceTrustCryptoService = mock<DeviceTrustCryptoServiceAbstraction>();
|
deviceTrustCryptoService = mock<DeviceTrustCryptoServiceAbstraction>();
|
||||||
billingAccountProfileStateService = mock<BillingAccountProfileStateService>();
|
billingAccountProfileStateService = mock<BillingAccountProfileStateService>();
|
||||||
|
|
||||||
accountService = mockAccountServiceWith(mockUserId);
|
|
||||||
masterPasswordService = new FakeMasterPasswordService();
|
|
||||||
|
|
||||||
tokenService.getTwoFactorToken.mockResolvedValue(null);
|
tokenService.getTwoFactorToken.mockResolvedValue(null);
|
||||||
appIdService.getAppId.mockResolvedValue(deviceId);
|
appIdService.getAppId.mockResolvedValue(deviceId);
|
||||||
tokenService.decodeAccessToken.mockResolvedValue({});
|
tokenService.decodeAccessToken.mockResolvedValue({});
|
||||||
|
|
||||||
authRequestLoginStrategy = new AuthRequestLoginStrategy(
|
authRequestLoginStrategy = new AuthRequestLoginStrategy(
|
||||||
cache,
|
cache,
|
||||||
accountService,
|
|
||||||
masterPasswordService,
|
|
||||||
cryptoService,
|
cryptoService,
|
||||||
apiService,
|
apiService,
|
||||||
tokenService,
|
tokenService,
|
||||||
@@ -120,16 +108,13 @@ describe("AuthRequestLoginStrategy", () => {
|
|||||||
const masterKey = new SymmetricCryptoKey(new Uint8Array(64).buffer as CsprngArray) as MasterKey;
|
const masterKey = new SymmetricCryptoKey(new Uint8Array(64).buffer as CsprngArray) as MasterKey;
|
||||||
const userKey = new SymmetricCryptoKey(new Uint8Array(64).buffer as CsprngArray) as UserKey;
|
const userKey = new SymmetricCryptoKey(new Uint8Array(64).buffer as CsprngArray) as UserKey;
|
||||||
|
|
||||||
masterPasswordService.masterKeySubject.next(masterKey);
|
cryptoService.getMasterKey.mockResolvedValue(masterKey);
|
||||||
cryptoService.decryptUserKeyWithMasterKey.mockResolvedValue(userKey);
|
cryptoService.decryptUserKeyWithMasterKey.mockResolvedValue(userKey);
|
||||||
|
|
||||||
await authRequestLoginStrategy.logIn(credentials);
|
await authRequestLoginStrategy.logIn(credentials);
|
||||||
|
|
||||||
expect(masterPasswordService.mock.setMasterKey).toHaveBeenCalledWith(masterKey, mockUserId);
|
expect(cryptoService.setMasterKey).toHaveBeenCalledWith(masterKey);
|
||||||
expect(masterPasswordService.mock.setMasterKeyHash).toHaveBeenCalledWith(
|
expect(cryptoService.setMasterKeyHash).toHaveBeenCalledWith(decMasterKeyHash);
|
||||||
decMasterKeyHash,
|
|
||||||
mockUserId,
|
|
||||||
);
|
|
||||||
expect(cryptoService.setMasterKeyEncryptedUserKey).toHaveBeenCalledWith(tokenResponse.key);
|
expect(cryptoService.setMasterKeyEncryptedUserKey).toHaveBeenCalledWith(tokenResponse.key);
|
||||||
expect(cryptoService.setUserKey).toHaveBeenCalledWith(userKey);
|
expect(cryptoService.setUserKey).toHaveBeenCalledWith(userKey);
|
||||||
expect(deviceTrustCryptoService.trustDeviceIfRequired).toHaveBeenCalled();
|
expect(deviceTrustCryptoService.trustDeviceIfRequired).toHaveBeenCalled();
|
||||||
@@ -151,8 +136,8 @@ describe("AuthRequestLoginStrategy", () => {
|
|||||||
await authRequestLoginStrategy.logIn(credentials);
|
await authRequestLoginStrategy.logIn(credentials);
|
||||||
|
|
||||||
// setMasterKey and setMasterKeyHash should not be called
|
// setMasterKey and setMasterKeyHash should not be called
|
||||||
expect(masterPasswordService.mock.setMasterKey).not.toHaveBeenCalled();
|
expect(cryptoService.setMasterKey).not.toHaveBeenCalled();
|
||||||
expect(masterPasswordService.mock.setMasterKeyHash).not.toHaveBeenCalled();
|
expect(cryptoService.setMasterKeyHash).not.toHaveBeenCalled();
|
||||||
|
|
||||||
// setMasterKeyEncryptedUserKey, setUserKey, and setPrivateKey should still be called
|
// setMasterKeyEncryptedUserKey, setUserKey, and setPrivateKey should still be called
|
||||||
expect(cryptoService.setMasterKeyEncryptedUserKey).toHaveBeenCalledWith(tokenResponse.key);
|
expect(cryptoService.setMasterKeyEncryptedUserKey).toHaveBeenCalledWith(tokenResponse.key);
|
||||||
|
|||||||
@@ -1,10 +1,8 @@
|
|||||||
import { firstValueFrom, Observable, map, BehaviorSubject } from "rxjs";
|
import { Observable, map, BehaviorSubject } from "rxjs";
|
||||||
import { Jsonify } from "type-fest";
|
import { Jsonify } from "type-fest";
|
||||||
|
|
||||||
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
||||||
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
|
||||||
import { DeviceTrustCryptoServiceAbstraction } from "@bitwarden/common/auth/abstractions/device-trust-crypto.service.abstraction";
|
import { DeviceTrustCryptoServiceAbstraction } from "@bitwarden/common/auth/abstractions/device-trust-crypto.service.abstraction";
|
||||||
import { InternalMasterPasswordServiceAbstraction } from "@bitwarden/common/auth/abstractions/master-password.service.abstraction";
|
|
||||||
import { TokenService } from "@bitwarden/common/auth/abstractions/token.service";
|
import { TokenService } from "@bitwarden/common/auth/abstractions/token.service";
|
||||||
import { TwoFactorService } from "@bitwarden/common/auth/abstractions/two-factor.service";
|
import { TwoFactorService } from "@bitwarden/common/auth/abstractions/two-factor.service";
|
||||||
import { AuthResult } from "@bitwarden/common/auth/models/domain/auth-result";
|
import { AuthResult } from "@bitwarden/common/auth/models/domain/auth-result";
|
||||||
@@ -49,8 +47,6 @@ export class AuthRequestLoginStrategy extends LoginStrategy {
|
|||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
data: AuthRequestLoginStrategyData,
|
data: AuthRequestLoginStrategyData,
|
||||||
accountService: AccountService,
|
|
||||||
masterPasswordService: InternalMasterPasswordServiceAbstraction,
|
|
||||||
cryptoService: CryptoService,
|
cryptoService: CryptoService,
|
||||||
apiService: ApiService,
|
apiService: ApiService,
|
||||||
tokenService: TokenService,
|
tokenService: TokenService,
|
||||||
@@ -65,8 +61,6 @@ export class AuthRequestLoginStrategy extends LoginStrategy {
|
|||||||
billingAccountProfileStateService: BillingAccountProfileStateService,
|
billingAccountProfileStateService: BillingAccountProfileStateService,
|
||||||
) {
|
) {
|
||||||
super(
|
super(
|
||||||
accountService,
|
|
||||||
masterPasswordService,
|
|
||||||
cryptoService,
|
cryptoService,
|
||||||
apiService,
|
apiService,
|
||||||
tokenService,
|
tokenService,
|
||||||
@@ -120,15 +114,8 @@ export class AuthRequestLoginStrategy extends LoginStrategy {
|
|||||||
authRequestCredentials.decryptedMasterKey &&
|
authRequestCredentials.decryptedMasterKey &&
|
||||||
authRequestCredentials.decryptedMasterKeyHash
|
authRequestCredentials.decryptedMasterKeyHash
|
||||||
) {
|
) {
|
||||||
const userId = (await firstValueFrom(this.accountService.activeAccount$))?.id;
|
await this.cryptoService.setMasterKey(authRequestCredentials.decryptedMasterKey);
|
||||||
await this.masterPasswordService.setMasterKey(
|
await this.cryptoService.setMasterKeyHash(authRequestCredentials.decryptedMasterKeyHash);
|
||||||
authRequestCredentials.decryptedMasterKey,
|
|
||||||
userId,
|
|
||||||
);
|
|
||||||
await this.masterPasswordService.setMasterKeyHash(
|
|
||||||
authRequestCredentials.decryptedMasterKeyHash,
|
|
||||||
userId,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -150,8 +137,7 @@ export class AuthRequestLoginStrategy extends LoginStrategy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private async trySetUserKeyWithMasterKey(): Promise<void> {
|
private async trySetUserKeyWithMasterKey(): Promise<void> {
|
||||||
const userId = (await firstValueFrom(this.accountService.activeAccount$))?.id;
|
const masterKey = await this.cryptoService.getMasterKey();
|
||||||
const masterKey = await firstValueFrom(this.masterPasswordService.masterKey$(userId));
|
|
||||||
if (masterKey) {
|
if (masterKey) {
|
||||||
const userKey = await this.cryptoService.decryptUserKeyWithMasterKey(masterKey);
|
const userKey = await this.cryptoService.decryptUserKeyWithMasterKey(masterKey);
|
||||||
await this.cryptoService.setUserKey(userKey);
|
await this.cryptoService.setUserKey(userKey);
|
||||||
|
|||||||
@@ -14,7 +14,6 @@ import { IdentityTokenResponse } from "@bitwarden/common/auth/models/response/id
|
|||||||
import { IdentityTwoFactorResponse } from "@bitwarden/common/auth/models/response/identity-two-factor.response";
|
import { IdentityTwoFactorResponse } from "@bitwarden/common/auth/models/response/identity-two-factor.response";
|
||||||
import { MasterPasswordPolicyResponse } from "@bitwarden/common/auth/models/response/master-password-policy.response";
|
import { MasterPasswordPolicyResponse } from "@bitwarden/common/auth/models/response/master-password-policy.response";
|
||||||
import { IUserDecryptionOptionsServerResponse } from "@bitwarden/common/auth/models/response/user-decryption-options/user-decryption-options.response";
|
import { IUserDecryptionOptionsServerResponse } from "@bitwarden/common/auth/models/response/user-decryption-options/user-decryption-options.response";
|
||||||
import { FakeMasterPasswordService } from "@bitwarden/common/auth/services/master-password/fake-master-password.service";
|
|
||||||
import { BillingAccountProfileStateService } from "@bitwarden/common/billing/abstractions/account/billing-account-profile-state.service";
|
import { BillingAccountProfileStateService } from "@bitwarden/common/billing/abstractions/account/billing-account-profile-state.service";
|
||||||
import { VaultTimeoutAction } from "@bitwarden/common/enums/vault-timeout-action.enum";
|
import { VaultTimeoutAction } from "@bitwarden/common/enums/vault-timeout-action.enum";
|
||||||
import { AppIdService } from "@bitwarden/common/platform/abstractions/app-id.service";
|
import { AppIdService } from "@bitwarden/common/platform/abstractions/app-id.service";
|
||||||
@@ -32,13 +31,11 @@ import {
|
|||||||
} from "@bitwarden/common/platform/models/domain/account";
|
} from "@bitwarden/common/platform/models/domain/account";
|
||||||
import { EncString } from "@bitwarden/common/platform/models/domain/enc-string";
|
import { EncString } from "@bitwarden/common/platform/models/domain/enc-string";
|
||||||
import { SymmetricCryptoKey } from "@bitwarden/common/platform/models/domain/symmetric-crypto-key";
|
import { SymmetricCryptoKey } from "@bitwarden/common/platform/models/domain/symmetric-crypto-key";
|
||||||
import { FakeAccountService, mockAccountServiceWith } from "@bitwarden/common/spec";
|
|
||||||
import {
|
import {
|
||||||
PasswordStrengthServiceAbstraction,
|
PasswordStrengthServiceAbstraction,
|
||||||
PasswordStrengthService,
|
PasswordStrengthService,
|
||||||
} from "@bitwarden/common/tools/password-strength";
|
} from "@bitwarden/common/tools/password-strength";
|
||||||
import { CsprngArray } from "@bitwarden/common/types/csprng";
|
import { CsprngArray } from "@bitwarden/common/types/csprng";
|
||||||
import { UserId } from "@bitwarden/common/types/guid";
|
|
||||||
import { UserKey, MasterKey } from "@bitwarden/common/types/key";
|
import { UserKey, MasterKey } from "@bitwarden/common/types/key";
|
||||||
|
|
||||||
import { LoginStrategyServiceAbstraction } from "../abstractions";
|
import { LoginStrategyServiceAbstraction } from "../abstractions";
|
||||||
@@ -59,7 +56,7 @@ const privateKey = "PRIVATE_KEY";
|
|||||||
const captchaSiteKey = "CAPTCHA_SITE_KEY";
|
const captchaSiteKey = "CAPTCHA_SITE_KEY";
|
||||||
const kdf = 0;
|
const kdf = 0;
|
||||||
const kdfIterations = 10000;
|
const kdfIterations = 10000;
|
||||||
const userId = Utils.newGuid() as UserId;
|
const userId = Utils.newGuid();
|
||||||
const masterPasswordHash = "MASTER_PASSWORD_HASH";
|
const masterPasswordHash = "MASTER_PASSWORD_HASH";
|
||||||
const name = "NAME";
|
const name = "NAME";
|
||||||
const defaultUserDecryptionOptionsServerResponse: IUserDecryptionOptionsServerResponse = {
|
const defaultUserDecryptionOptionsServerResponse: IUserDecryptionOptionsServerResponse = {
|
||||||
@@ -101,8 +98,6 @@ export function identityTokenResponseFactory(
|
|||||||
// TODO: add tests for latest changes to base class for TDE
|
// TODO: add tests for latest changes to base class for TDE
|
||||||
describe("LoginStrategy", () => {
|
describe("LoginStrategy", () => {
|
||||||
let cache: PasswordLoginStrategyData;
|
let cache: PasswordLoginStrategyData;
|
||||||
let accountService: FakeAccountService;
|
|
||||||
let masterPasswordService: FakeMasterPasswordService;
|
|
||||||
|
|
||||||
let loginStrategyService: MockProxy<LoginStrategyServiceAbstraction>;
|
let loginStrategyService: MockProxy<LoginStrategyServiceAbstraction>;
|
||||||
let cryptoService: MockProxy<CryptoService>;
|
let cryptoService: MockProxy<CryptoService>;
|
||||||
@@ -123,9 +118,6 @@ describe("LoginStrategy", () => {
|
|||||||
let credentials: PasswordLoginCredentials;
|
let credentials: PasswordLoginCredentials;
|
||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
accountService = mockAccountServiceWith(userId);
|
|
||||||
masterPasswordService = new FakeMasterPasswordService();
|
|
||||||
|
|
||||||
loginStrategyService = mock<LoginStrategyServiceAbstraction>();
|
loginStrategyService = mock<LoginStrategyServiceAbstraction>();
|
||||||
cryptoService = mock<CryptoService>();
|
cryptoService = mock<CryptoService>();
|
||||||
apiService = mock<ApiService>();
|
apiService = mock<ApiService>();
|
||||||
@@ -147,8 +139,6 @@ describe("LoginStrategy", () => {
|
|||||||
// The base class is abstract so we test it via PasswordLoginStrategy
|
// The base class is abstract so we test it via PasswordLoginStrategy
|
||||||
passwordLoginStrategy = new PasswordLoginStrategy(
|
passwordLoginStrategy = new PasswordLoginStrategy(
|
||||||
cache,
|
cache,
|
||||||
accountService,
|
|
||||||
masterPasswordService,
|
|
||||||
cryptoService,
|
cryptoService,
|
||||||
apiService,
|
apiService,
|
||||||
tokenService,
|
tokenService,
|
||||||
@@ -251,7 +241,7 @@ describe("LoginStrategy", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
apiService.postIdentityToken.mockResolvedValue(tokenResponse);
|
apiService.postIdentityToken.mockResolvedValue(tokenResponse);
|
||||||
masterPasswordService.masterKeySubject.next(masterKey);
|
cryptoService.getMasterKey.mockResolvedValue(masterKey);
|
||||||
cryptoService.decryptUserKeyWithMasterKey.mockResolvedValue(userKey);
|
cryptoService.decryptUserKeyWithMasterKey.mockResolvedValue(userKey);
|
||||||
|
|
||||||
const result = await passwordLoginStrategy.logIn(credentials);
|
const result = await passwordLoginStrategy.logIn(credentials);
|
||||||
@@ -270,7 +260,7 @@ describe("LoginStrategy", () => {
|
|||||||
cryptoService.makeKeyPair.mockResolvedValue(["PUBLIC_KEY", new EncString("PRIVATE_KEY")]);
|
cryptoService.makeKeyPair.mockResolvedValue(["PUBLIC_KEY", new EncString("PRIVATE_KEY")]);
|
||||||
|
|
||||||
apiService.postIdentityToken.mockResolvedValue(tokenResponse);
|
apiService.postIdentityToken.mockResolvedValue(tokenResponse);
|
||||||
masterPasswordService.masterKeySubject.next(masterKey);
|
cryptoService.getMasterKey.mockResolvedValue(masterKey);
|
||||||
cryptoService.decryptUserKeyWithMasterKey.mockResolvedValue(userKey);
|
cryptoService.decryptUserKeyWithMasterKey.mockResolvedValue(userKey);
|
||||||
|
|
||||||
await passwordLoginStrategy.logIn(credentials);
|
await passwordLoginStrategy.logIn(credentials);
|
||||||
@@ -392,8 +382,6 @@ describe("LoginStrategy", () => {
|
|||||||
|
|
||||||
passwordLoginStrategy = new PasswordLoginStrategy(
|
passwordLoginStrategy = new PasswordLoginStrategy(
|
||||||
cache,
|
cache,
|
||||||
accountService,
|
|
||||||
masterPasswordService,
|
|
||||||
cryptoService,
|
cryptoService,
|
||||||
apiService,
|
apiService,
|
||||||
tokenService,
|
tokenService,
|
||||||
|
|||||||
@@ -1,8 +1,6 @@
|
|||||||
import { BehaviorSubject } from "rxjs";
|
import { BehaviorSubject } from "rxjs";
|
||||||
|
|
||||||
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
||||||
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
|
||||||
import { InternalMasterPasswordServiceAbstraction } from "@bitwarden/common/auth/abstractions/master-password.service.abstraction";
|
|
||||||
import { TokenService } from "@bitwarden/common/auth/abstractions/token.service";
|
import { TokenService } from "@bitwarden/common/auth/abstractions/token.service";
|
||||||
import { TwoFactorService } from "@bitwarden/common/auth/abstractions/two-factor.service";
|
import { TwoFactorService } from "@bitwarden/common/auth/abstractions/two-factor.service";
|
||||||
import { TwoFactorProviderType } from "@bitwarden/common/auth/enums/two-factor-provider-type";
|
import { TwoFactorProviderType } from "@bitwarden/common/auth/enums/two-factor-provider-type";
|
||||||
@@ -62,8 +60,6 @@ export abstract class LoginStrategy {
|
|||||||
protected abstract cache: BehaviorSubject<LoginStrategyData>;
|
protected abstract cache: BehaviorSubject<LoginStrategyData>;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
protected accountService: AccountService,
|
|
||||||
protected masterPasswordService: InternalMasterPasswordServiceAbstraction,
|
|
||||||
protected cryptoService: CryptoService,
|
protected cryptoService: CryptoService,
|
||||||
protected apiService: ApiService,
|
protected apiService: ApiService,
|
||||||
protected tokenService: TokenService,
|
protected tokenService: TokenService,
|
||||||
|
|||||||
@@ -9,7 +9,6 @@ import { ForceSetPasswordReason } from "@bitwarden/common/auth/models/domain/for
|
|||||||
import { IdentityTokenResponse } from "@bitwarden/common/auth/models/response/identity-token.response";
|
import { IdentityTokenResponse } from "@bitwarden/common/auth/models/response/identity-token.response";
|
||||||
import { IdentityTwoFactorResponse } from "@bitwarden/common/auth/models/response/identity-two-factor.response";
|
import { IdentityTwoFactorResponse } from "@bitwarden/common/auth/models/response/identity-two-factor.response";
|
||||||
import { MasterPasswordPolicyResponse } from "@bitwarden/common/auth/models/response/master-password-policy.response";
|
import { MasterPasswordPolicyResponse } from "@bitwarden/common/auth/models/response/master-password-policy.response";
|
||||||
import { FakeMasterPasswordService } from "@bitwarden/common/auth/services/master-password/fake-master-password.service";
|
|
||||||
import { BillingAccountProfileStateService } from "@bitwarden/common/billing/abstractions/account/billing-account-profile-state.service";
|
import { BillingAccountProfileStateService } from "@bitwarden/common/billing/abstractions/account/billing-account-profile-state.service";
|
||||||
import { AppIdService } from "@bitwarden/common/platform/abstractions/app-id.service";
|
import { AppIdService } from "@bitwarden/common/platform/abstractions/app-id.service";
|
||||||
import { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.service";
|
import { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.service";
|
||||||
@@ -20,13 +19,11 @@ import { StateService } from "@bitwarden/common/platform/abstractions/state.serv
|
|||||||
import { HashPurpose } from "@bitwarden/common/platform/enums";
|
import { HashPurpose } from "@bitwarden/common/platform/enums";
|
||||||
import { Utils } from "@bitwarden/common/platform/misc/utils";
|
import { Utils } from "@bitwarden/common/platform/misc/utils";
|
||||||
import { SymmetricCryptoKey } from "@bitwarden/common/platform/models/domain/symmetric-crypto-key";
|
import { SymmetricCryptoKey } from "@bitwarden/common/platform/models/domain/symmetric-crypto-key";
|
||||||
import { FakeAccountService, mockAccountServiceWith } from "@bitwarden/common/spec";
|
|
||||||
import {
|
import {
|
||||||
PasswordStrengthServiceAbstraction,
|
PasswordStrengthServiceAbstraction,
|
||||||
PasswordStrengthService,
|
PasswordStrengthService,
|
||||||
} from "@bitwarden/common/tools/password-strength";
|
} from "@bitwarden/common/tools/password-strength";
|
||||||
import { CsprngArray } from "@bitwarden/common/types/csprng";
|
import { CsprngArray } from "@bitwarden/common/types/csprng";
|
||||||
import { UserId } from "@bitwarden/common/types/guid";
|
|
||||||
import { MasterKey, UserKey } from "@bitwarden/common/types/key";
|
import { MasterKey, UserKey } from "@bitwarden/common/types/key";
|
||||||
|
|
||||||
import { LoginStrategyServiceAbstraction } from "../abstractions";
|
import { LoginStrategyServiceAbstraction } from "../abstractions";
|
||||||
@@ -45,7 +42,6 @@ const masterKey = new SymmetricCryptoKey(
|
|||||||
"N2KWjlLpfi5uHjv+YcfUKIpZ1l+W+6HRensmIqD+BFYBf6N/dvFpJfWwYnVBdgFCK2tJTAIMLhqzIQQEUmGFgg==",
|
"N2KWjlLpfi5uHjv+YcfUKIpZ1l+W+6HRensmIqD+BFYBf6N/dvFpJfWwYnVBdgFCK2tJTAIMLhqzIQQEUmGFgg==",
|
||||||
),
|
),
|
||||||
) as MasterKey;
|
) as MasterKey;
|
||||||
const userId = Utils.newGuid() as UserId;
|
|
||||||
const deviceId = Utils.newGuid();
|
const deviceId = Utils.newGuid();
|
||||||
const masterPasswordPolicy = new MasterPasswordPolicyResponse({
|
const masterPasswordPolicy = new MasterPasswordPolicyResponse({
|
||||||
EnforceOnLogin: true,
|
EnforceOnLogin: true,
|
||||||
@@ -54,8 +50,6 @@ const masterPasswordPolicy = new MasterPasswordPolicyResponse({
|
|||||||
|
|
||||||
describe("PasswordLoginStrategy", () => {
|
describe("PasswordLoginStrategy", () => {
|
||||||
let cache: PasswordLoginStrategyData;
|
let cache: PasswordLoginStrategyData;
|
||||||
let accountService: FakeAccountService;
|
|
||||||
let masterPasswordService: FakeMasterPasswordService;
|
|
||||||
|
|
||||||
let loginStrategyService: MockProxy<LoginStrategyServiceAbstraction>;
|
let loginStrategyService: MockProxy<LoginStrategyServiceAbstraction>;
|
||||||
let cryptoService: MockProxy<CryptoService>;
|
let cryptoService: MockProxy<CryptoService>;
|
||||||
@@ -77,9 +71,6 @@ describe("PasswordLoginStrategy", () => {
|
|||||||
let tokenResponse: IdentityTokenResponse;
|
let tokenResponse: IdentityTokenResponse;
|
||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
accountService = mockAccountServiceWith(userId);
|
|
||||||
masterPasswordService = new FakeMasterPasswordService();
|
|
||||||
|
|
||||||
loginStrategyService = mock<LoginStrategyServiceAbstraction>();
|
loginStrategyService = mock<LoginStrategyServiceAbstraction>();
|
||||||
cryptoService = mock<CryptoService>();
|
cryptoService = mock<CryptoService>();
|
||||||
apiService = mock<ApiService>();
|
apiService = mock<ApiService>();
|
||||||
@@ -111,8 +102,6 @@ describe("PasswordLoginStrategy", () => {
|
|||||||
|
|
||||||
passwordLoginStrategy = new PasswordLoginStrategy(
|
passwordLoginStrategy = new PasswordLoginStrategy(
|
||||||
cache,
|
cache,
|
||||||
accountService,
|
|
||||||
masterPasswordService,
|
|
||||||
cryptoService,
|
cryptoService,
|
||||||
apiService,
|
apiService,
|
||||||
tokenService,
|
tokenService,
|
||||||
@@ -156,16 +145,13 @@ describe("PasswordLoginStrategy", () => {
|
|||||||
it("sets keys after a successful authentication", async () => {
|
it("sets keys after a successful authentication", async () => {
|
||||||
const userKey = new SymmetricCryptoKey(new Uint8Array(64).buffer as CsprngArray) as UserKey;
|
const userKey = new SymmetricCryptoKey(new Uint8Array(64).buffer as CsprngArray) as UserKey;
|
||||||
|
|
||||||
masterPasswordService.masterKeySubject.next(masterKey);
|
cryptoService.getMasterKey.mockResolvedValue(masterKey);
|
||||||
cryptoService.decryptUserKeyWithMasterKey.mockResolvedValue(userKey);
|
cryptoService.decryptUserKeyWithMasterKey.mockResolvedValue(userKey);
|
||||||
|
|
||||||
await passwordLoginStrategy.logIn(credentials);
|
await passwordLoginStrategy.logIn(credentials);
|
||||||
|
|
||||||
expect(masterPasswordService.mock.setMasterKey).toHaveBeenCalledWith(masterKey, userId);
|
expect(cryptoService.setMasterKey).toHaveBeenCalledWith(masterKey);
|
||||||
expect(masterPasswordService.mock.setMasterKeyHash).toHaveBeenCalledWith(
|
expect(cryptoService.setMasterKeyHash).toHaveBeenCalledWith(localHashedPassword);
|
||||||
localHashedPassword,
|
|
||||||
userId,
|
|
||||||
);
|
|
||||||
expect(cryptoService.setMasterKeyEncryptedUserKey).toHaveBeenCalledWith(tokenResponse.key);
|
expect(cryptoService.setMasterKeyEncryptedUserKey).toHaveBeenCalledWith(tokenResponse.key);
|
||||||
expect(cryptoService.setUserKey).toHaveBeenCalledWith(userKey);
|
expect(cryptoService.setUserKey).toHaveBeenCalledWith(userKey);
|
||||||
expect(cryptoService.setPrivateKey).toHaveBeenCalledWith(tokenResponse.privateKey);
|
expect(cryptoService.setPrivateKey).toHaveBeenCalledWith(tokenResponse.privateKey);
|
||||||
@@ -197,9 +183,8 @@ describe("PasswordLoginStrategy", () => {
|
|||||||
const result = await passwordLoginStrategy.logIn(credentials);
|
const result = await passwordLoginStrategy.logIn(credentials);
|
||||||
|
|
||||||
expect(policyService.evaluateMasterPassword).toHaveBeenCalled();
|
expect(policyService.evaluateMasterPassword).toHaveBeenCalled();
|
||||||
expect(masterPasswordService.mock.setForceSetPasswordReason).toHaveBeenCalledWith(
|
expect(stateService.setForceSetPasswordReason).toHaveBeenCalledWith(
|
||||||
ForceSetPasswordReason.WeakMasterPassword,
|
ForceSetPasswordReason.WeakMasterPassword,
|
||||||
userId,
|
|
||||||
);
|
);
|
||||||
expect(result.forcePasswordReset).toEqual(ForceSetPasswordReason.WeakMasterPassword);
|
expect(result.forcePasswordReset).toEqual(ForceSetPasswordReason.WeakMasterPassword);
|
||||||
});
|
});
|
||||||
@@ -237,9 +222,8 @@ describe("PasswordLoginStrategy", () => {
|
|||||||
expect(firstResult.forcePasswordReset).toEqual(ForceSetPasswordReason.None);
|
expect(firstResult.forcePasswordReset).toEqual(ForceSetPasswordReason.None);
|
||||||
|
|
||||||
// Second login attempt should save the force password reset options and return in result
|
// Second login attempt should save the force password reset options and return in result
|
||||||
expect(masterPasswordService.mock.setForceSetPasswordReason).toHaveBeenCalledWith(
|
expect(stateService.setForceSetPasswordReason).toHaveBeenCalledWith(
|
||||||
ForceSetPasswordReason.WeakMasterPassword,
|
ForceSetPasswordReason.WeakMasterPassword,
|
||||||
userId,
|
|
||||||
);
|
);
|
||||||
expect(secondResult.forcePasswordReset).toEqual(ForceSetPasswordReason.WeakMasterPassword);
|
expect(secondResult.forcePasswordReset).toEqual(ForceSetPasswordReason.WeakMasterPassword);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,11 +1,9 @@
|
|||||||
import { BehaviorSubject, firstValueFrom, map, Observable } from "rxjs";
|
import { BehaviorSubject, map, Observable } from "rxjs";
|
||||||
import { Jsonify } from "type-fest";
|
import { Jsonify } from "type-fest";
|
||||||
|
|
||||||
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
||||||
import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction";
|
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 { MasterPasswordPolicyOptions } from "@bitwarden/common/admin-console/models/domain/master-password-policy-options";
|
||||||
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
|
||||||
import { InternalMasterPasswordServiceAbstraction } from "@bitwarden/common/auth/abstractions/master-password.service.abstraction";
|
|
||||||
import { TokenService } from "@bitwarden/common/auth/abstractions/token.service";
|
import { TokenService } from "@bitwarden/common/auth/abstractions/token.service";
|
||||||
import { TwoFactorService } from "@bitwarden/common/auth/abstractions/two-factor.service";
|
import { TwoFactorService } from "@bitwarden/common/auth/abstractions/two-factor.service";
|
||||||
import { AuthResult } from "@bitwarden/common/auth/models/domain/auth-result";
|
import { AuthResult } from "@bitwarden/common/auth/models/domain/auth-result";
|
||||||
@@ -72,8 +70,6 @@ export class PasswordLoginStrategy extends LoginStrategy {
|
|||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
data: PasswordLoginStrategyData,
|
data: PasswordLoginStrategyData,
|
||||||
accountService: AccountService,
|
|
||||||
masterPasswordService: InternalMasterPasswordServiceAbstraction,
|
|
||||||
cryptoService: CryptoService,
|
cryptoService: CryptoService,
|
||||||
apiService: ApiService,
|
apiService: ApiService,
|
||||||
tokenService: TokenService,
|
tokenService: TokenService,
|
||||||
@@ -90,8 +86,6 @@ export class PasswordLoginStrategy extends LoginStrategy {
|
|||||||
billingAccountProfileStateService: BillingAccountProfileStateService,
|
billingAccountProfileStateService: BillingAccountProfileStateService,
|
||||||
) {
|
) {
|
||||||
super(
|
super(
|
||||||
accountService,
|
|
||||||
masterPasswordService,
|
|
||||||
cryptoService,
|
cryptoService,
|
||||||
apiService,
|
apiService,
|
||||||
tokenService,
|
tokenService,
|
||||||
@@ -163,10 +157,8 @@ export class PasswordLoginStrategy extends LoginStrategy {
|
|||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
// Authentication was successful, save the force update password options with the state service
|
// Authentication was successful, save the force update password options with the state service
|
||||||
const userId = (await firstValueFrom(this.accountService.activeAccount$))?.id;
|
await this.stateService.setForceSetPasswordReason(
|
||||||
await this.masterPasswordService.setForceSetPasswordReason(
|
|
||||||
ForceSetPasswordReason.WeakMasterPassword,
|
ForceSetPasswordReason.WeakMasterPassword,
|
||||||
userId,
|
|
||||||
);
|
);
|
||||||
authResult.forcePasswordReset = ForceSetPasswordReason.WeakMasterPassword;
|
authResult.forcePasswordReset = ForceSetPasswordReason.WeakMasterPassword;
|
||||||
}
|
}
|
||||||
@@ -192,8 +184,7 @@ export class PasswordLoginStrategy extends LoginStrategy {
|
|||||||
!result.requiresCaptcha &&
|
!result.requiresCaptcha &&
|
||||||
forcePasswordResetReason != ForceSetPasswordReason.None
|
forcePasswordResetReason != ForceSetPasswordReason.None
|
||||||
) {
|
) {
|
||||||
const userId = (await firstValueFrom(this.accountService.activeAccount$))?.id;
|
await this.stateService.setForceSetPasswordReason(forcePasswordResetReason);
|
||||||
await this.masterPasswordService.setForceSetPasswordReason(forcePasswordResetReason, userId);
|
|
||||||
result.forcePasswordReset = forcePasswordResetReason;
|
result.forcePasswordReset = forcePasswordResetReason;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -202,9 +193,8 @@ export class PasswordLoginStrategy extends LoginStrategy {
|
|||||||
|
|
||||||
protected override async setMasterKey(response: IdentityTokenResponse) {
|
protected override async setMasterKey(response: IdentityTokenResponse) {
|
||||||
const { masterKey, localMasterKeyHash } = this.cache.value;
|
const { masterKey, localMasterKeyHash } = this.cache.value;
|
||||||
const userId = (await firstValueFrom(this.accountService.activeAccount$))?.id;
|
await this.cryptoService.setMasterKey(masterKey);
|
||||||
await this.masterPasswordService.setMasterKey(masterKey, userId);
|
await this.cryptoService.setMasterKeyHash(localMasterKeyHash);
|
||||||
await this.masterPasswordService.setMasterKeyHash(localMasterKeyHash, userId);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override async setUserKey(response: IdentityTokenResponse): Promise<void> {
|
protected override async setUserKey(response: IdentityTokenResponse): Promise<void> {
|
||||||
@@ -214,8 +204,7 @@ export class PasswordLoginStrategy extends LoginStrategy {
|
|||||||
}
|
}
|
||||||
await this.cryptoService.setMasterKeyEncryptedUserKey(response.key);
|
await this.cryptoService.setMasterKeyEncryptedUserKey(response.key);
|
||||||
|
|
||||||
const userId = (await firstValueFrom(this.accountService.activeAccount$))?.id;
|
const masterKey = await this.cryptoService.getMasterKey();
|
||||||
const masterKey = await firstValueFrom(this.masterPasswordService.masterKey$(userId));
|
|
||||||
if (masterKey) {
|
if (masterKey) {
|
||||||
const userKey = await this.cryptoService.decryptUserKeyWithMasterKey(masterKey);
|
const userKey = await this.cryptoService.decryptUserKeyWithMasterKey(masterKey);
|
||||||
await this.cryptoService.setUserKey(userKey);
|
await this.cryptoService.setUserKey(userKey);
|
||||||
|
|||||||
@@ -9,7 +9,6 @@ import { AdminAuthRequestStorable } from "@bitwarden/common/auth/models/domain/a
|
|||||||
import { AuthRequestResponse } from "@bitwarden/common/auth/models/response/auth-request.response";
|
import { AuthRequestResponse } from "@bitwarden/common/auth/models/response/auth-request.response";
|
||||||
import { IdentityTokenResponse } from "@bitwarden/common/auth/models/response/identity-token.response";
|
import { IdentityTokenResponse } from "@bitwarden/common/auth/models/response/identity-token.response";
|
||||||
import { IUserDecryptionOptionsServerResponse } from "@bitwarden/common/auth/models/response/user-decryption-options/user-decryption-options.response";
|
import { IUserDecryptionOptionsServerResponse } from "@bitwarden/common/auth/models/response/user-decryption-options/user-decryption-options.response";
|
||||||
import { FakeMasterPasswordService } from "@bitwarden/common/auth/services/master-password/fake-master-password.service";
|
|
||||||
import { BillingAccountProfileStateService } from "@bitwarden/common/billing/abstractions/account/billing-account-profile-state.service";
|
import { BillingAccountProfileStateService } from "@bitwarden/common/billing/abstractions/account/billing-account-profile-state.service";
|
||||||
import { ErrorResponse } from "@bitwarden/common/models/response/error.response";
|
import { ErrorResponse } from "@bitwarden/common/models/response/error.response";
|
||||||
import { AppIdService } from "@bitwarden/common/platform/abstractions/app-id.service";
|
import { AppIdService } from "@bitwarden/common/platform/abstractions/app-id.service";
|
||||||
@@ -21,9 +20,7 @@ import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/pl
|
|||||||
import { StateService } from "@bitwarden/common/platform/abstractions/state.service";
|
import { StateService } from "@bitwarden/common/platform/abstractions/state.service";
|
||||||
import { Utils } from "@bitwarden/common/platform/misc/utils";
|
import { Utils } from "@bitwarden/common/platform/misc/utils";
|
||||||
import { SymmetricCryptoKey } from "@bitwarden/common/platform/models/domain/symmetric-crypto-key";
|
import { SymmetricCryptoKey } from "@bitwarden/common/platform/models/domain/symmetric-crypto-key";
|
||||||
import { FakeAccountService, mockAccountServiceWith } from "@bitwarden/common/spec";
|
|
||||||
import { CsprngArray } from "@bitwarden/common/types/csprng";
|
import { CsprngArray } from "@bitwarden/common/types/csprng";
|
||||||
import { UserId } from "@bitwarden/common/types/guid";
|
|
||||||
import { DeviceKey, UserKey, MasterKey } from "@bitwarden/common/types/key";
|
import { DeviceKey, UserKey, MasterKey } from "@bitwarden/common/types/key";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
@@ -36,9 +33,6 @@ import { identityTokenResponseFactory } from "./login.strategy.spec";
|
|||||||
import { SsoLoginStrategy } from "./sso-login.strategy";
|
import { SsoLoginStrategy } from "./sso-login.strategy";
|
||||||
|
|
||||||
describe("SsoLoginStrategy", () => {
|
describe("SsoLoginStrategy", () => {
|
||||||
let accountService: FakeAccountService;
|
|
||||||
let masterPasswordService: FakeMasterPasswordService;
|
|
||||||
|
|
||||||
let cryptoService: MockProxy<CryptoService>;
|
let cryptoService: MockProxy<CryptoService>;
|
||||||
let apiService: MockProxy<ApiService>;
|
let apiService: MockProxy<ApiService>;
|
||||||
let tokenService: MockProxy<TokenService>;
|
let tokenService: MockProxy<TokenService>;
|
||||||
@@ -58,7 +52,6 @@ describe("SsoLoginStrategy", () => {
|
|||||||
let ssoLoginStrategy: SsoLoginStrategy;
|
let ssoLoginStrategy: SsoLoginStrategy;
|
||||||
let credentials: SsoLoginCredentials;
|
let credentials: SsoLoginCredentials;
|
||||||
|
|
||||||
const userId = Utils.newGuid() as UserId;
|
|
||||||
const deviceId = Utils.newGuid();
|
const deviceId = Utils.newGuid();
|
||||||
const keyConnectorUrl = "KEY_CONNECTOR_URL";
|
const keyConnectorUrl = "KEY_CONNECTOR_URL";
|
||||||
|
|
||||||
@@ -68,9 +61,6 @@ describe("SsoLoginStrategy", () => {
|
|||||||
const ssoOrgId = "SSO_ORG_ID";
|
const ssoOrgId = "SSO_ORG_ID";
|
||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
accountService = mockAccountServiceWith(userId);
|
|
||||||
masterPasswordService = new FakeMasterPasswordService();
|
|
||||||
|
|
||||||
cryptoService = mock<CryptoService>();
|
cryptoService = mock<CryptoService>();
|
||||||
apiService = mock<ApiService>();
|
apiService = mock<ApiService>();
|
||||||
tokenService = mock<TokenService>();
|
tokenService = mock<TokenService>();
|
||||||
@@ -93,8 +83,6 @@ describe("SsoLoginStrategy", () => {
|
|||||||
|
|
||||||
ssoLoginStrategy = new SsoLoginStrategy(
|
ssoLoginStrategy = new SsoLoginStrategy(
|
||||||
null,
|
null,
|
||||||
accountService,
|
|
||||||
masterPasswordService,
|
|
||||||
cryptoService,
|
cryptoService,
|
||||||
apiService,
|
apiService,
|
||||||
tokenService,
|
tokenService,
|
||||||
@@ -142,7 +130,7 @@ describe("SsoLoginStrategy", () => {
|
|||||||
|
|
||||||
await ssoLoginStrategy.logIn(credentials);
|
await ssoLoginStrategy.logIn(credentials);
|
||||||
|
|
||||||
expect(masterPasswordService.mock.setMasterKey).not.toHaveBeenCalled();
|
expect(cryptoService.setMasterKey).not.toHaveBeenCalled();
|
||||||
expect(cryptoService.setUserKey).not.toHaveBeenCalled();
|
expect(cryptoService.setUserKey).not.toHaveBeenCalled();
|
||||||
expect(cryptoService.setPrivateKey).not.toHaveBeenCalled();
|
expect(cryptoService.setPrivateKey).not.toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
@@ -407,7 +395,7 @@ describe("SsoLoginStrategy", () => {
|
|||||||
) as MasterKey;
|
) as MasterKey;
|
||||||
|
|
||||||
apiService.postIdentityToken.mockResolvedValue(tokenResponse);
|
apiService.postIdentityToken.mockResolvedValue(tokenResponse);
|
||||||
masterPasswordService.masterKeySubject.next(masterKey);
|
cryptoService.getMasterKey.mockResolvedValue(masterKey);
|
||||||
|
|
||||||
await ssoLoginStrategy.logIn(credentials);
|
await ssoLoginStrategy.logIn(credentials);
|
||||||
|
|
||||||
@@ -434,7 +422,7 @@ describe("SsoLoginStrategy", () => {
|
|||||||
) as MasterKey;
|
) as MasterKey;
|
||||||
|
|
||||||
apiService.postIdentityToken.mockResolvedValue(tokenResponse);
|
apiService.postIdentityToken.mockResolvedValue(tokenResponse);
|
||||||
masterPasswordService.masterKeySubject.next(masterKey);
|
cryptoService.getMasterKey.mockResolvedValue(masterKey);
|
||||||
cryptoService.decryptUserKeyWithMasterKey.mockResolvedValue(userKey);
|
cryptoService.decryptUserKeyWithMasterKey.mockResolvedValue(userKey);
|
||||||
|
|
||||||
await ssoLoginStrategy.logIn(credentials);
|
await ssoLoginStrategy.logIn(credentials);
|
||||||
@@ -458,7 +446,7 @@ describe("SsoLoginStrategy", () => {
|
|||||||
) as MasterKey;
|
) as MasterKey;
|
||||||
|
|
||||||
apiService.postIdentityToken.mockResolvedValue(tokenResponse);
|
apiService.postIdentityToken.mockResolvedValue(tokenResponse);
|
||||||
masterPasswordService.masterKeySubject.next(masterKey);
|
cryptoService.getMasterKey.mockResolvedValue(masterKey);
|
||||||
|
|
||||||
await ssoLoginStrategy.logIn(credentials);
|
await ssoLoginStrategy.logIn(credentials);
|
||||||
|
|
||||||
@@ -485,7 +473,7 @@ describe("SsoLoginStrategy", () => {
|
|||||||
) as MasterKey;
|
) as MasterKey;
|
||||||
|
|
||||||
apiService.postIdentityToken.mockResolvedValue(tokenResponse);
|
apiService.postIdentityToken.mockResolvedValue(tokenResponse);
|
||||||
masterPasswordService.masterKeySubject.next(masterKey);
|
cryptoService.getMasterKey.mockResolvedValue(masterKey);
|
||||||
cryptoService.decryptUserKeyWithMasterKey.mockResolvedValue(userKey);
|
cryptoService.decryptUserKeyWithMasterKey.mockResolvedValue(userKey);
|
||||||
|
|
||||||
await ssoLoginStrategy.logIn(credentials);
|
await ssoLoginStrategy.logIn(credentials);
|
||||||
|
|||||||
@@ -1,11 +1,9 @@
|
|||||||
import { firstValueFrom, Observable, map, BehaviorSubject } from "rxjs";
|
import { Observable, map, BehaviorSubject } from "rxjs";
|
||||||
import { Jsonify } from "type-fest";
|
import { Jsonify } from "type-fest";
|
||||||
|
|
||||||
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
||||||
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
|
||||||
import { DeviceTrustCryptoServiceAbstraction } from "@bitwarden/common/auth/abstractions/device-trust-crypto.service.abstraction";
|
import { DeviceTrustCryptoServiceAbstraction } from "@bitwarden/common/auth/abstractions/device-trust-crypto.service.abstraction";
|
||||||
import { KeyConnectorService } from "@bitwarden/common/auth/abstractions/key-connector.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 { TokenService } from "@bitwarden/common/auth/abstractions/token.service";
|
||||||
import { TwoFactorService } from "@bitwarden/common/auth/abstractions/two-factor.service";
|
import { TwoFactorService } from "@bitwarden/common/auth/abstractions/two-factor.service";
|
||||||
import { ForceSetPasswordReason } from "@bitwarden/common/auth/models/domain/force-set-password-reason";
|
import { ForceSetPasswordReason } from "@bitwarden/common/auth/models/domain/force-set-password-reason";
|
||||||
@@ -81,8 +79,6 @@ export class SsoLoginStrategy extends LoginStrategy {
|
|||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
data: SsoLoginStrategyData,
|
data: SsoLoginStrategyData,
|
||||||
accountService: AccountService,
|
|
||||||
masterPasswordService: InternalMasterPasswordServiceAbstraction,
|
|
||||||
cryptoService: CryptoService,
|
cryptoService: CryptoService,
|
||||||
apiService: ApiService,
|
apiService: ApiService,
|
||||||
tokenService: TokenService,
|
tokenService: TokenService,
|
||||||
@@ -100,8 +96,6 @@ export class SsoLoginStrategy extends LoginStrategy {
|
|||||||
billingAccountProfileStateService: BillingAccountProfileStateService,
|
billingAccountProfileStateService: BillingAccountProfileStateService,
|
||||||
) {
|
) {
|
||||||
super(
|
super(
|
||||||
accountService,
|
|
||||||
masterPasswordService,
|
|
||||||
cryptoService,
|
cryptoService,
|
||||||
apiService,
|
apiService,
|
||||||
tokenService,
|
tokenService,
|
||||||
@@ -144,11 +138,7 @@ export class SsoLoginStrategy extends LoginStrategy {
|
|||||||
|
|
||||||
// Auth guard currently handles redirects for this.
|
// Auth guard currently handles redirects for this.
|
||||||
if (ssoAuthResult.forcePasswordReset == ForceSetPasswordReason.AdminForcePasswordReset) {
|
if (ssoAuthResult.forcePasswordReset == ForceSetPasswordReason.AdminForcePasswordReset) {
|
||||||
const userId = (await firstValueFrom(this.accountService.activeAccount$))?.id;
|
await this.stateService.setForceSetPasswordReason(ssoAuthResult.forcePasswordReset);
|
||||||
await this.masterPasswordService.setForceSetPasswordReason(
|
|
||||||
ssoAuthResult.forcePasswordReset,
|
|
||||||
userId,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this.cache.next({
|
this.cache.next({
|
||||||
@@ -333,8 +323,7 @@ export class SsoLoginStrategy extends LoginStrategy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private async trySetUserKeyWithMasterKey(): Promise<void> {
|
private async trySetUserKeyWithMasterKey(): Promise<void> {
|
||||||
const userId = (await firstValueFrom(this.accountService.activeAccount$))?.id;
|
const masterKey = await this.cryptoService.getMasterKey();
|
||||||
const masterKey = await firstValueFrom(this.masterPasswordService.masterKey$(userId));
|
|
||||||
|
|
||||||
// There is a scenario in which the master key is not set here. That will occur if the user
|
// There is a scenario in which the master key is not set here. That will occur if the user
|
||||||
// has a master password and is using Key Connector. In that case, we cannot set the master key
|
// has a master password and is using Key Connector. In that case, we cannot set the master key
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
|||||||
import { KeyConnectorService } from "@bitwarden/common/auth/abstractions/key-connector.service";
|
import { KeyConnectorService } from "@bitwarden/common/auth/abstractions/key-connector.service";
|
||||||
import { TokenService } from "@bitwarden/common/auth/abstractions/token.service";
|
import { TokenService } from "@bitwarden/common/auth/abstractions/token.service";
|
||||||
import { TwoFactorService } from "@bitwarden/common/auth/abstractions/two-factor.service";
|
import { TwoFactorService } from "@bitwarden/common/auth/abstractions/two-factor.service";
|
||||||
import { FakeMasterPasswordService } from "@bitwarden/common/auth/services/master-password/fake-master-password.service";
|
|
||||||
import { BillingAccountProfileStateService } from "@bitwarden/common/billing/abstractions/account/billing-account-profile-state.service";
|
import { BillingAccountProfileStateService } from "@bitwarden/common/billing/abstractions/account/billing-account-profile-state.service";
|
||||||
import { VaultTimeoutAction } from "@bitwarden/common/enums/vault-timeout-action.enum";
|
import { VaultTimeoutAction } from "@bitwarden/common/enums/vault-timeout-action.enum";
|
||||||
import { AppIdService } from "@bitwarden/common/platform/abstractions/app-id.service";
|
import { AppIdService } from "@bitwarden/common/platform/abstractions/app-id.service";
|
||||||
@@ -20,9 +19,7 @@ import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/pl
|
|||||||
import { StateService } from "@bitwarden/common/platform/abstractions/state.service";
|
import { StateService } from "@bitwarden/common/platform/abstractions/state.service";
|
||||||
import { Utils } from "@bitwarden/common/platform/misc/utils";
|
import { Utils } from "@bitwarden/common/platform/misc/utils";
|
||||||
import { SymmetricCryptoKey } from "@bitwarden/common/platform/models/domain/symmetric-crypto-key";
|
import { SymmetricCryptoKey } from "@bitwarden/common/platform/models/domain/symmetric-crypto-key";
|
||||||
import { FakeAccountService, mockAccountServiceWith } from "@bitwarden/common/spec";
|
|
||||||
import { CsprngArray } from "@bitwarden/common/types/csprng";
|
import { CsprngArray } from "@bitwarden/common/types/csprng";
|
||||||
import { UserId } from "@bitwarden/common/types/guid";
|
|
||||||
import { UserKey, MasterKey } from "@bitwarden/common/types/key";
|
import { UserKey, MasterKey } from "@bitwarden/common/types/key";
|
||||||
|
|
||||||
import { InternalUserDecryptionOptionsServiceAbstraction } from "../abstractions/user-decryption-options.service.abstraction";
|
import { InternalUserDecryptionOptionsServiceAbstraction } from "../abstractions/user-decryption-options.service.abstraction";
|
||||||
@@ -33,8 +30,6 @@ import { UserApiLoginStrategy, UserApiLoginStrategyData } from "./user-api-login
|
|||||||
|
|
||||||
describe("UserApiLoginStrategy", () => {
|
describe("UserApiLoginStrategy", () => {
|
||||||
let cache: UserApiLoginStrategyData;
|
let cache: UserApiLoginStrategyData;
|
||||||
let accountService: FakeAccountService;
|
|
||||||
let masterPasswordService: FakeMasterPasswordService;
|
|
||||||
|
|
||||||
let cryptoService: MockProxy<CryptoService>;
|
let cryptoService: MockProxy<CryptoService>;
|
||||||
let apiService: MockProxy<ApiService>;
|
let apiService: MockProxy<ApiService>;
|
||||||
@@ -53,16 +48,12 @@ describe("UserApiLoginStrategy", () => {
|
|||||||
let apiLogInStrategy: UserApiLoginStrategy;
|
let apiLogInStrategy: UserApiLoginStrategy;
|
||||||
let credentials: UserApiLoginCredentials;
|
let credentials: UserApiLoginCredentials;
|
||||||
|
|
||||||
const userId = Utils.newGuid() as UserId;
|
|
||||||
const deviceId = Utils.newGuid();
|
const deviceId = Utils.newGuid();
|
||||||
const keyConnectorUrl = "KEY_CONNECTOR_URL";
|
const keyConnectorUrl = "KEY_CONNECTOR_URL";
|
||||||
const apiClientId = "API_CLIENT_ID";
|
const apiClientId = "API_CLIENT_ID";
|
||||||
const apiClientSecret = "API_CLIENT_SECRET";
|
const apiClientSecret = "API_CLIENT_SECRET";
|
||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
accountService = mockAccountServiceWith(userId);
|
|
||||||
masterPasswordService = new FakeMasterPasswordService();
|
|
||||||
|
|
||||||
cryptoService = mock<CryptoService>();
|
cryptoService = mock<CryptoService>();
|
||||||
apiService = mock<ApiService>();
|
apiService = mock<ApiService>();
|
||||||
tokenService = mock<TokenService>();
|
tokenService = mock<TokenService>();
|
||||||
@@ -83,8 +74,6 @@ describe("UserApiLoginStrategy", () => {
|
|||||||
|
|
||||||
apiLogInStrategy = new UserApiLoginStrategy(
|
apiLogInStrategy = new UserApiLoginStrategy(
|
||||||
cache,
|
cache,
|
||||||
accountService,
|
|
||||||
masterPasswordService,
|
|
||||||
cryptoService,
|
cryptoService,
|
||||||
apiService,
|
apiService,
|
||||||
tokenService,
|
tokenService,
|
||||||
@@ -183,7 +172,7 @@ describe("UserApiLoginStrategy", () => {
|
|||||||
environmentService.environment$ = new BehaviorSubject(env);
|
environmentService.environment$ = new BehaviorSubject(env);
|
||||||
|
|
||||||
apiService.postIdentityToken.mockResolvedValue(tokenResponse);
|
apiService.postIdentityToken.mockResolvedValue(tokenResponse);
|
||||||
masterPasswordService.masterKeySubject.next(masterKey);
|
cryptoService.getMasterKey.mockResolvedValue(masterKey);
|
||||||
cryptoService.decryptUserKeyWithMasterKey.mockResolvedValue(userKey);
|
cryptoService.decryptUserKeyWithMasterKey.mockResolvedValue(userKey);
|
||||||
|
|
||||||
await apiLogInStrategy.logIn(credentials);
|
await apiLogInStrategy.logIn(credentials);
|
||||||
|
|||||||
@@ -2,9 +2,7 @@ import { firstValueFrom, BehaviorSubject } from "rxjs";
|
|||||||
import { Jsonify } from "type-fest";
|
import { Jsonify } from "type-fest";
|
||||||
|
|
||||||
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
||||||
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
|
||||||
import { KeyConnectorService } from "@bitwarden/common/auth/abstractions/key-connector.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 { TokenService } from "@bitwarden/common/auth/abstractions/token.service";
|
||||||
import { TwoFactorService } from "@bitwarden/common/auth/abstractions/two-factor.service";
|
import { TwoFactorService } from "@bitwarden/common/auth/abstractions/two-factor.service";
|
||||||
import { UserApiTokenRequest } from "@bitwarden/common/auth/models/request/identity-token/user-api-token.request";
|
import { UserApiTokenRequest } from "@bitwarden/common/auth/models/request/identity-token/user-api-token.request";
|
||||||
@@ -41,8 +39,6 @@ export class UserApiLoginStrategy extends LoginStrategy {
|
|||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
data: UserApiLoginStrategyData,
|
data: UserApiLoginStrategyData,
|
||||||
accountService: AccountService,
|
|
||||||
masterPasswordService: InternalMasterPasswordServiceAbstraction,
|
|
||||||
cryptoService: CryptoService,
|
cryptoService: CryptoService,
|
||||||
apiService: ApiService,
|
apiService: ApiService,
|
||||||
tokenService: TokenService,
|
tokenService: TokenService,
|
||||||
@@ -58,8 +54,6 @@ export class UserApiLoginStrategy extends LoginStrategy {
|
|||||||
billingAccountProfileStateService: BillingAccountProfileStateService,
|
billingAccountProfileStateService: BillingAccountProfileStateService,
|
||||||
) {
|
) {
|
||||||
super(
|
super(
|
||||||
accountService,
|
|
||||||
masterPasswordService,
|
|
||||||
cryptoService,
|
cryptoService,
|
||||||
apiService,
|
apiService,
|
||||||
tokenService,
|
tokenService,
|
||||||
@@ -101,8 +95,7 @@ export class UserApiLoginStrategy extends LoginStrategy {
|
|||||||
await this.cryptoService.setMasterKeyEncryptedUserKey(response.key);
|
await this.cryptoService.setMasterKeyEncryptedUserKey(response.key);
|
||||||
|
|
||||||
if (response.apiUseKeyConnector) {
|
if (response.apiUseKeyConnector) {
|
||||||
const userId = (await firstValueFrom(this.accountService.activeAccount$))?.id;
|
const masterKey = await this.cryptoService.getMasterKey();
|
||||||
const masterKey = await firstValueFrom(this.masterPasswordService.masterKey$(userId));
|
|
||||||
if (masterKey) {
|
if (masterKey) {
|
||||||
const userKey = await this.cryptoService.decryptUserKeyWithMasterKey(masterKey);
|
const userKey = await this.cryptoService.decryptUserKeyWithMasterKey(masterKey);
|
||||||
await this.cryptoService.setUserKey(userKey);
|
await this.cryptoService.setUserKey(userKey);
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ import { TwoFactorService } from "@bitwarden/common/auth/abstractions/two-factor
|
|||||||
import { AuthResult } from "@bitwarden/common/auth/models/domain/auth-result";
|
import { AuthResult } from "@bitwarden/common/auth/models/domain/auth-result";
|
||||||
import { IdentityTokenResponse } from "@bitwarden/common/auth/models/response/identity-token.response";
|
import { IdentityTokenResponse } from "@bitwarden/common/auth/models/response/identity-token.response";
|
||||||
import { IUserDecryptionOptionsServerResponse } from "@bitwarden/common/auth/models/response/user-decryption-options/user-decryption-options.response";
|
import { IUserDecryptionOptionsServerResponse } from "@bitwarden/common/auth/models/response/user-decryption-options/user-decryption-options.response";
|
||||||
import { FakeMasterPasswordService } from "@bitwarden/common/auth/services/master-password/fake-master-password.service";
|
|
||||||
import { WebAuthnLoginAssertionResponseRequest } from "@bitwarden/common/auth/services/webauthn-login/request/webauthn-login-assertion-response.request";
|
import { WebAuthnLoginAssertionResponseRequest } from "@bitwarden/common/auth/services/webauthn-login/request/webauthn-login-assertion-response.request";
|
||||||
import { BillingAccountProfileStateService } from "@bitwarden/common/billing/abstractions/account/billing-account-profile-state.service";
|
import { BillingAccountProfileStateService } from "@bitwarden/common/billing/abstractions/account/billing-account-profile-state.service";
|
||||||
import { AppIdService } from "@bitwarden/common/platform/abstractions/app-id.service";
|
import { AppIdService } from "@bitwarden/common/platform/abstractions/app-id.service";
|
||||||
@@ -17,7 +16,6 @@ import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/pl
|
|||||||
import { StateService } from "@bitwarden/common/platform/abstractions/state.service";
|
import { StateService } from "@bitwarden/common/platform/abstractions/state.service";
|
||||||
import { Utils } from "@bitwarden/common/platform/misc/utils";
|
import { Utils } from "@bitwarden/common/platform/misc/utils";
|
||||||
import { SymmetricCryptoKey } from "@bitwarden/common/platform/models/domain/symmetric-crypto-key";
|
import { SymmetricCryptoKey } from "@bitwarden/common/platform/models/domain/symmetric-crypto-key";
|
||||||
import { FakeAccountService } from "@bitwarden/common/spec";
|
|
||||||
import { PrfKey, UserKey } from "@bitwarden/common/types/key";
|
import { PrfKey, UserKey } from "@bitwarden/common/types/key";
|
||||||
|
|
||||||
import { InternalUserDecryptionOptionsServiceAbstraction } from "../abstractions/user-decryption-options.service.abstraction";
|
import { InternalUserDecryptionOptionsServiceAbstraction } from "../abstractions/user-decryption-options.service.abstraction";
|
||||||
@@ -28,8 +26,6 @@ import { WebAuthnLoginStrategy, WebAuthnLoginStrategyData } from "./webauthn-log
|
|||||||
|
|
||||||
describe("WebAuthnLoginStrategy", () => {
|
describe("WebAuthnLoginStrategy", () => {
|
||||||
let cache: WebAuthnLoginStrategyData;
|
let cache: WebAuthnLoginStrategyData;
|
||||||
let accountService: FakeAccountService;
|
|
||||||
let masterPasswordService: FakeMasterPasswordService;
|
|
||||||
|
|
||||||
let cryptoService!: MockProxy<CryptoService>;
|
let cryptoService!: MockProxy<CryptoService>;
|
||||||
let apiService!: MockProxy<ApiService>;
|
let apiService!: MockProxy<ApiService>;
|
||||||
@@ -67,9 +63,6 @@ describe("WebAuthnLoginStrategy", () => {
|
|||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
jest.clearAllMocks();
|
jest.clearAllMocks();
|
||||||
|
|
||||||
accountService = new FakeAccountService(null);
|
|
||||||
masterPasswordService = new FakeMasterPasswordService();
|
|
||||||
|
|
||||||
cryptoService = mock<CryptoService>();
|
cryptoService = mock<CryptoService>();
|
||||||
apiService = mock<ApiService>();
|
apiService = mock<ApiService>();
|
||||||
tokenService = mock<TokenService>();
|
tokenService = mock<TokenService>();
|
||||||
@@ -88,8 +81,6 @@ describe("WebAuthnLoginStrategy", () => {
|
|||||||
|
|
||||||
webAuthnLoginStrategy = new WebAuthnLoginStrategy(
|
webAuthnLoginStrategy = new WebAuthnLoginStrategy(
|
||||||
cache,
|
cache,
|
||||||
accountService,
|
|
||||||
masterPasswordService,
|
|
||||||
cryptoService,
|
cryptoService,
|
||||||
apiService,
|
apiService,
|
||||||
tokenService,
|
tokenService,
|
||||||
@@ -216,7 +207,7 @@ describe("WebAuthnLoginStrategy", () => {
|
|||||||
expect(cryptoService.setPrivateKey).toHaveBeenCalledWith(idTokenResponse.privateKey);
|
expect(cryptoService.setPrivateKey).toHaveBeenCalledWith(idTokenResponse.privateKey);
|
||||||
|
|
||||||
// Master key and private key should not be set
|
// Master key and private key should not be set
|
||||||
expect(masterPasswordService.mock.setMasterKey).not.toHaveBeenCalled();
|
expect(cryptoService.setMasterKey).not.toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
it("does not try to set the user key when prfKey is missing", async () => {
|
it("does not try to set the user key when prfKey is missing", async () => {
|
||||||
|
|||||||
@@ -2,8 +2,6 @@ import { BehaviorSubject } from "rxjs";
|
|||||||
import { Jsonify } from "type-fest";
|
import { Jsonify } from "type-fest";
|
||||||
|
|
||||||
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
||||||
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
|
||||||
import { InternalMasterPasswordServiceAbstraction } from "@bitwarden/common/auth/abstractions/master-password.service.abstraction";
|
|
||||||
import { TokenService } from "@bitwarden/common/auth/abstractions/token.service";
|
import { TokenService } from "@bitwarden/common/auth/abstractions/token.service";
|
||||||
import { TwoFactorService } from "@bitwarden/common/auth/abstractions/two-factor.service";
|
import { TwoFactorService } from "@bitwarden/common/auth/abstractions/two-factor.service";
|
||||||
import { AuthResult } from "@bitwarden/common/auth/models/domain/auth-result";
|
import { AuthResult } from "@bitwarden/common/auth/models/domain/auth-result";
|
||||||
@@ -43,8 +41,6 @@ export class WebAuthnLoginStrategy extends LoginStrategy {
|
|||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
data: WebAuthnLoginStrategyData,
|
data: WebAuthnLoginStrategyData,
|
||||||
accountService: AccountService,
|
|
||||||
masterPasswordService: InternalMasterPasswordServiceAbstraction,
|
|
||||||
cryptoService: CryptoService,
|
cryptoService: CryptoService,
|
||||||
apiService: ApiService,
|
apiService: ApiService,
|
||||||
tokenService: TokenService,
|
tokenService: TokenService,
|
||||||
@@ -58,8 +54,6 @@ export class WebAuthnLoginStrategy extends LoginStrategy {
|
|||||||
billingAccountProfileStateService: BillingAccountProfileStateService,
|
billingAccountProfileStateService: BillingAccountProfileStateService,
|
||||||
) {
|
) {
|
||||||
super(
|
super(
|
||||||
accountService,
|
|
||||||
masterPasswordService,
|
|
||||||
cryptoService,
|
cryptoService,
|
||||||
apiService,
|
apiService,
|
||||||
tokenService,
|
tokenService,
|
||||||
|
|||||||
@@ -2,15 +2,13 @@ import { mock } from "jest-mock-extended";
|
|||||||
|
|
||||||
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
||||||
import { AuthRequestResponse } from "@bitwarden/common/auth/models/response/auth-request.response";
|
import { AuthRequestResponse } from "@bitwarden/common/auth/models/response/auth-request.response";
|
||||||
import { FakeMasterPasswordService } from "@bitwarden/common/auth/services/master-password/fake-master-password.service";
|
|
||||||
import { AuthRequestPushNotification } from "@bitwarden/common/models/response/notification.response";
|
import { AuthRequestPushNotification } from "@bitwarden/common/models/response/notification.response";
|
||||||
import { AppIdService } from "@bitwarden/common/platform/abstractions/app-id.service";
|
import { AppIdService } from "@bitwarden/common/platform/abstractions/app-id.service";
|
||||||
import { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.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 { Utils } from "@bitwarden/common/platform/misc/utils";
|
||||||
import { EncString } from "@bitwarden/common/platform/models/domain/enc-string";
|
import { EncString } from "@bitwarden/common/platform/models/domain/enc-string";
|
||||||
import { SymmetricCryptoKey } from "@bitwarden/common/platform/models/domain/symmetric-crypto-key";
|
import { SymmetricCryptoKey } from "@bitwarden/common/platform/models/domain/symmetric-crypto-key";
|
||||||
import { FakeAccountService, mockAccountServiceWith } from "@bitwarden/common/spec";
|
|
||||||
import { UserId } from "@bitwarden/common/types/guid";
|
|
||||||
import { MasterKey, UserKey } from "@bitwarden/common/types/key";
|
import { MasterKey, UserKey } from "@bitwarden/common/types/key";
|
||||||
|
|
||||||
import { AuthRequestService } from "./auth-request.service";
|
import { AuthRequestService } from "./auth-request.service";
|
||||||
@@ -18,27 +16,17 @@ import { AuthRequestService } from "./auth-request.service";
|
|||||||
describe("AuthRequestService", () => {
|
describe("AuthRequestService", () => {
|
||||||
let sut: AuthRequestService;
|
let sut: AuthRequestService;
|
||||||
|
|
||||||
let accountService: FakeAccountService;
|
|
||||||
let masterPasswordService: FakeMasterPasswordService;
|
|
||||||
const appIdService = mock<AppIdService>();
|
const appIdService = mock<AppIdService>();
|
||||||
const cryptoService = mock<CryptoService>();
|
const cryptoService = mock<CryptoService>();
|
||||||
const apiService = mock<ApiService>();
|
const apiService = mock<ApiService>();
|
||||||
|
const stateService = mock<StateService>();
|
||||||
|
|
||||||
let mockPrivateKey: Uint8Array;
|
let mockPrivateKey: Uint8Array;
|
||||||
const mockUserId = Utils.newGuid() as UserId;
|
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
jest.clearAllMocks();
|
jest.clearAllMocks();
|
||||||
accountService = mockAccountServiceWith(mockUserId);
|
|
||||||
masterPasswordService = new FakeMasterPasswordService();
|
|
||||||
|
|
||||||
sut = new AuthRequestService(
|
sut = new AuthRequestService(appIdService, cryptoService, apiService, stateService);
|
||||||
appIdService,
|
|
||||||
accountService,
|
|
||||||
masterPasswordService,
|
|
||||||
cryptoService,
|
|
||||||
apiService,
|
|
||||||
);
|
|
||||||
|
|
||||||
mockPrivateKey = new Uint8Array(64);
|
mockPrivateKey = new Uint8Array(64);
|
||||||
});
|
});
|
||||||
@@ -79,8 +67,8 @@ describe("AuthRequestService", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it("should use the master key and hash if they exist", async () => {
|
it("should use the master key and hash if they exist", async () => {
|
||||||
masterPasswordService.masterKeySubject.next({ encKey: new Uint8Array(64) } as MasterKey);
|
cryptoService.getMasterKey.mockResolvedValueOnce({ encKey: new Uint8Array(64) } as MasterKey);
|
||||||
masterPasswordService.masterKeyHashSubject.next("MASTER_KEY_HASH");
|
stateService.getKeyHash.mockResolvedValueOnce("KEY_HASH");
|
||||||
|
|
||||||
await sut.approveOrDenyAuthRequest(
|
await sut.approveOrDenyAuthRequest(
|
||||||
true,
|
true,
|
||||||
@@ -142,8 +130,8 @@ describe("AuthRequestService", () => {
|
|||||||
masterKeyHash: mockDecryptedMasterKeyHash,
|
masterKeyHash: mockDecryptedMasterKeyHash,
|
||||||
});
|
});
|
||||||
|
|
||||||
masterPasswordService.masterKeySubject.next(undefined);
|
cryptoService.setMasterKey.mockResolvedValueOnce(undefined);
|
||||||
masterPasswordService.masterKeyHashSubject.next(undefined);
|
cryptoService.setMasterKeyHash.mockResolvedValueOnce(undefined);
|
||||||
cryptoService.decryptUserKeyWithMasterKey.mockResolvedValueOnce(mockDecryptedUserKey);
|
cryptoService.decryptUserKeyWithMasterKey.mockResolvedValueOnce(mockDecryptedUserKey);
|
||||||
cryptoService.setUserKey.mockResolvedValueOnce(undefined);
|
cryptoService.setUserKey.mockResolvedValueOnce(undefined);
|
||||||
|
|
||||||
@@ -156,18 +144,10 @@ describe("AuthRequestService", () => {
|
|||||||
mockAuthReqResponse.masterPasswordHash,
|
mockAuthReqResponse.masterPasswordHash,
|
||||||
mockPrivateKey,
|
mockPrivateKey,
|
||||||
);
|
);
|
||||||
expect(masterPasswordService.mock.setMasterKey).toHaveBeenCalledWith(
|
expect(cryptoService.setMasterKey).toBeCalledWith(mockDecryptedMasterKey);
|
||||||
mockDecryptedMasterKey,
|
expect(cryptoService.setMasterKeyHash).toBeCalledWith(mockDecryptedMasterKeyHash);
|
||||||
mockUserId,
|
expect(cryptoService.decryptUserKeyWithMasterKey).toBeCalledWith(mockDecryptedMasterKey);
|
||||||
);
|
expect(cryptoService.setUserKey).toBeCalledWith(mockDecryptedUserKey);
|
||||||
expect(masterPasswordService.mock.setMasterKeyHash).toHaveBeenCalledWith(
|
|
||||||
mockDecryptedMasterKeyHash,
|
|
||||||
mockUserId,
|
|
||||||
);
|
|
||||||
expect(cryptoService.decryptUserKeyWithMasterKey).toHaveBeenCalledWith(
|
|
||||||
mockDecryptedMasterKey,
|
|
||||||
);
|
|
||||||
expect(cryptoService.setUserKey).toHaveBeenCalledWith(mockDecryptedUserKey);
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -1,13 +1,12 @@
|
|||||||
import { firstValueFrom, Observable, Subject } from "rxjs";
|
import { Observable, Subject } from "rxjs";
|
||||||
|
|
||||||
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
||||||
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
|
||||||
import { InternalMasterPasswordServiceAbstraction } from "@bitwarden/common/auth/abstractions/master-password.service.abstraction";
|
|
||||||
import { PasswordlessAuthRequest } from "@bitwarden/common/auth/models/request/passwordless-auth.request";
|
import { PasswordlessAuthRequest } from "@bitwarden/common/auth/models/request/passwordless-auth.request";
|
||||||
import { AuthRequestResponse } from "@bitwarden/common/auth/models/response/auth-request.response";
|
import { AuthRequestResponse } from "@bitwarden/common/auth/models/response/auth-request.response";
|
||||||
import { AuthRequestPushNotification } from "@bitwarden/common/models/response/notification.response";
|
import { AuthRequestPushNotification } from "@bitwarden/common/models/response/notification.response";
|
||||||
import { AppIdService } from "@bitwarden/common/platform/abstractions/app-id.service";
|
import { AppIdService } from "@bitwarden/common/platform/abstractions/app-id.service";
|
||||||
import { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.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 { Utils } from "@bitwarden/common/platform/misc/utils";
|
||||||
import { SymmetricCryptoKey } from "@bitwarden/common/platform/models/domain/symmetric-crypto-key";
|
import { SymmetricCryptoKey } from "@bitwarden/common/platform/models/domain/symmetric-crypto-key";
|
||||||
import { MasterKey, UserKey } from "@bitwarden/common/types/key";
|
import { MasterKey, UserKey } from "@bitwarden/common/types/key";
|
||||||
@@ -20,10 +19,9 @@ export class AuthRequestService implements AuthRequestServiceAbstraction {
|
|||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private appIdService: AppIdService,
|
private appIdService: AppIdService,
|
||||||
private accountService: AccountService,
|
|
||||||
private masterPasswordService: InternalMasterPasswordServiceAbstraction,
|
|
||||||
private cryptoService: CryptoService,
|
private cryptoService: CryptoService,
|
||||||
private apiService: ApiService,
|
private apiService: ApiService,
|
||||||
|
private stateService: StateService,
|
||||||
) {
|
) {
|
||||||
this.authRequestPushNotification$ = this.authRequestPushNotificationSubject.asObservable();
|
this.authRequestPushNotification$ = this.authRequestPushNotificationSubject.asObservable();
|
||||||
}
|
}
|
||||||
@@ -40,9 +38,8 @@ export class AuthRequestService implements AuthRequestServiceAbstraction {
|
|||||||
}
|
}
|
||||||
const pubKey = Utils.fromB64ToArray(authRequest.publicKey);
|
const pubKey = Utils.fromB64ToArray(authRequest.publicKey);
|
||||||
|
|
||||||
const userId = (await firstValueFrom(this.accountService.activeAccount$)).id;
|
const masterKey = await this.cryptoService.getMasterKey();
|
||||||
const masterKey = await firstValueFrom(this.masterPasswordService.masterKey$(userId));
|
const masterKeyHash = await this.stateService.getKeyHash();
|
||||||
const masterKeyHash = await firstValueFrom(this.masterPasswordService.masterKeyHash$(userId));
|
|
||||||
let encryptedMasterKeyHash;
|
let encryptedMasterKeyHash;
|
||||||
let keyToEncrypt;
|
let keyToEncrypt;
|
||||||
|
|
||||||
@@ -95,9 +92,8 @@ export class AuthRequestService implements AuthRequestServiceAbstraction {
|
|||||||
const userKey = await this.cryptoService.decryptUserKeyWithMasterKey(masterKey);
|
const userKey = await this.cryptoService.decryptUserKeyWithMasterKey(masterKey);
|
||||||
|
|
||||||
// Set masterKey + masterKeyHash in state after decryption (in case decryption fails)
|
// Set masterKey + masterKeyHash in state after decryption (in case decryption fails)
|
||||||
const userId = (await firstValueFrom(this.accountService.activeAccount$)).id;
|
await this.cryptoService.setMasterKey(masterKey);
|
||||||
await this.masterPasswordService.setMasterKey(masterKey, userId);
|
await this.cryptoService.setMasterKeyHash(masterKeyHash);
|
||||||
await this.masterPasswordService.setMasterKeyHash(masterKeyHash, userId);
|
|
||||||
|
|
||||||
await this.cryptoService.setUserKey(userKey);
|
await this.cryptoService.setUserKey(userKey);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,7 +11,6 @@ import { AuthResult } from "@bitwarden/common/auth/models/domain/auth-result";
|
|||||||
import { TokenTwoFactorRequest } from "@bitwarden/common/auth/models/request/identity-token/token-two-factor.request";
|
import { TokenTwoFactorRequest } from "@bitwarden/common/auth/models/request/identity-token/token-two-factor.request";
|
||||||
import { IdentityTokenResponse } from "@bitwarden/common/auth/models/response/identity-token.response";
|
import { IdentityTokenResponse } from "@bitwarden/common/auth/models/response/identity-token.response";
|
||||||
import { IdentityTwoFactorResponse } from "@bitwarden/common/auth/models/response/identity-two-factor.response";
|
import { IdentityTwoFactorResponse } from "@bitwarden/common/auth/models/response/identity-two-factor.response";
|
||||||
import { FakeMasterPasswordService } from "@bitwarden/common/auth/services/master-password/fake-master-password.service";
|
|
||||||
import { BillingAccountProfileStateService } from "@bitwarden/common/billing/abstractions/account/billing-account-profile-state.service";
|
import { BillingAccountProfileStateService } from "@bitwarden/common/billing/abstractions/account/billing-account-profile-state.service";
|
||||||
import { AppIdService } from "@bitwarden/common/platform/abstractions/app-id.service";
|
import { AppIdService } from "@bitwarden/common/platform/abstractions/app-id.service";
|
||||||
import { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.service";
|
import { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.service";
|
||||||
@@ -23,14 +22,8 @@ import { MessagingService } from "@bitwarden/common/platform/abstractions/messag
|
|||||||
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
||||||
import { StateService } from "@bitwarden/common/platform/abstractions/state.service";
|
import { StateService } from "@bitwarden/common/platform/abstractions/state.service";
|
||||||
import { KdfType } from "@bitwarden/common/platform/enums";
|
import { KdfType } from "@bitwarden/common/platform/enums";
|
||||||
import {
|
import { FakeGlobalState, FakeGlobalStateProvider } from "@bitwarden/common/spec";
|
||||||
FakeAccountService,
|
|
||||||
FakeGlobalState,
|
|
||||||
FakeGlobalStateProvider,
|
|
||||||
mockAccountServiceWith,
|
|
||||||
} from "@bitwarden/common/spec";
|
|
||||||
import { PasswordStrengthServiceAbstraction } from "@bitwarden/common/tools/password-strength";
|
import { PasswordStrengthServiceAbstraction } from "@bitwarden/common/tools/password-strength";
|
||||||
import { UserId } from "@bitwarden/common/types/guid";
|
|
||||||
|
|
||||||
import {
|
import {
|
||||||
AuthRequestServiceAbstraction,
|
AuthRequestServiceAbstraction,
|
||||||
@@ -45,8 +38,6 @@ import { CACHE_EXPIRATION_KEY } from "./login-strategy.state";
|
|||||||
describe("LoginStrategyService", () => {
|
describe("LoginStrategyService", () => {
|
||||||
let sut: LoginStrategyService;
|
let sut: LoginStrategyService;
|
||||||
|
|
||||||
let accountService: FakeAccountService;
|
|
||||||
let masterPasswordService: FakeMasterPasswordService;
|
|
||||||
let cryptoService: MockProxy<CryptoService>;
|
let cryptoService: MockProxy<CryptoService>;
|
||||||
let apiService: MockProxy<ApiService>;
|
let apiService: MockProxy<ApiService>;
|
||||||
let tokenService: MockProxy<TokenService>;
|
let tokenService: MockProxy<TokenService>;
|
||||||
@@ -70,11 +61,7 @@ describe("LoginStrategyService", () => {
|
|||||||
let stateProvider: FakeGlobalStateProvider;
|
let stateProvider: FakeGlobalStateProvider;
|
||||||
let loginStrategyCacheExpirationState: FakeGlobalState<Date | null>;
|
let loginStrategyCacheExpirationState: FakeGlobalState<Date | null>;
|
||||||
|
|
||||||
const userId = "USER_ID" as UserId;
|
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
accountService = mockAccountServiceWith(userId);
|
|
||||||
masterPasswordService = new FakeMasterPasswordService();
|
|
||||||
cryptoService = mock<CryptoService>();
|
cryptoService = mock<CryptoService>();
|
||||||
apiService = mock<ApiService>();
|
apiService = mock<ApiService>();
|
||||||
tokenService = mock<TokenService>();
|
tokenService = mock<TokenService>();
|
||||||
@@ -97,8 +84,6 @@ describe("LoginStrategyService", () => {
|
|||||||
stateProvider = new FakeGlobalStateProvider();
|
stateProvider = new FakeGlobalStateProvider();
|
||||||
|
|
||||||
sut = new LoginStrategyService(
|
sut = new LoginStrategyService(
|
||||||
accountService,
|
|
||||||
masterPasswordService,
|
|
||||||
cryptoService,
|
cryptoService,
|
||||||
apiService,
|
apiService,
|
||||||
tokenService,
|
tokenService,
|
||||||
|
|||||||
@@ -9,10 +9,8 @@ import {
|
|||||||
|
|
||||||
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
||||||
import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction";
|
import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction";
|
||||||
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
|
||||||
import { DeviceTrustCryptoServiceAbstraction } from "@bitwarden/common/auth/abstractions/device-trust-crypto.service.abstraction";
|
import { DeviceTrustCryptoServiceAbstraction } from "@bitwarden/common/auth/abstractions/device-trust-crypto.service.abstraction";
|
||||||
import { KeyConnectorService } from "@bitwarden/common/auth/abstractions/key-connector.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 { TokenService } from "@bitwarden/common/auth/abstractions/token.service";
|
||||||
import { TwoFactorService } from "@bitwarden/common/auth/abstractions/two-factor.service";
|
import { TwoFactorService } from "@bitwarden/common/auth/abstractions/two-factor.service";
|
||||||
import { AuthenticationType } from "@bitwarden/common/auth/enums/authentication-type";
|
import { AuthenticationType } from "@bitwarden/common/auth/enums/authentication-type";
|
||||||
@@ -83,8 +81,6 @@ export class LoginStrategyService implements LoginStrategyServiceAbstraction {
|
|||||||
currentAuthType$: Observable<AuthenticationType | null>;
|
currentAuthType$: Observable<AuthenticationType | null>;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
protected accountService: AccountService,
|
|
||||||
protected masterPasswordService: InternalMasterPasswordServiceAbstraction,
|
|
||||||
protected cryptoService: CryptoService,
|
protected cryptoService: CryptoService,
|
||||||
protected apiService: ApiService,
|
protected apiService: ApiService,
|
||||||
protected tokenService: TokenService,
|
protected tokenService: TokenService,
|
||||||
@@ -261,8 +257,7 @@ export class LoginStrategyService implements LoginStrategyServiceAbstraction {
|
|||||||
): Promise<AuthRequestResponse> {
|
): Promise<AuthRequestResponse> {
|
||||||
const pubKey = Utils.fromB64ToArray(key);
|
const pubKey = Utils.fromB64ToArray(key);
|
||||||
|
|
||||||
const userId = (await firstValueFrom(this.accountService.activeAccount$)).id;
|
const masterKey = await this.cryptoService.getMasterKey();
|
||||||
const masterKey = await firstValueFrom(this.masterPasswordService.masterKey$(userId));
|
|
||||||
let keyToEncrypt;
|
let keyToEncrypt;
|
||||||
let encryptedMasterKeyHash = null;
|
let encryptedMasterKeyHash = null;
|
||||||
|
|
||||||
@@ -271,7 +266,7 @@ export class LoginStrategyService implements LoginStrategyServiceAbstraction {
|
|||||||
|
|
||||||
// Only encrypt the master password hash if masterKey exists as
|
// Only encrypt the master password hash if masterKey exists as
|
||||||
// we won't have a masterKeyHash without a masterKey
|
// we won't have a masterKeyHash without a masterKey
|
||||||
const masterKeyHash = await firstValueFrom(this.masterPasswordService.masterKeyHash$(userId));
|
const masterKeyHash = await this.stateService.getKeyHash();
|
||||||
if (masterKeyHash != null) {
|
if (masterKeyHash != null) {
|
||||||
encryptedMasterKeyHash = await this.cryptoService.rsaEncrypt(
|
encryptedMasterKeyHash = await this.cryptoService.rsaEncrypt(
|
||||||
Utils.fromUtf8ToArray(masterKeyHash),
|
Utils.fromUtf8ToArray(masterKeyHash),
|
||||||
@@ -338,8 +333,6 @@ export class LoginStrategyService implements LoginStrategyServiceAbstraction {
|
|||||||
case AuthenticationType.Password:
|
case AuthenticationType.Password:
|
||||||
return new PasswordLoginStrategy(
|
return new PasswordLoginStrategy(
|
||||||
data?.password,
|
data?.password,
|
||||||
this.accountService,
|
|
||||||
this.masterPasswordService,
|
|
||||||
this.cryptoService,
|
this.cryptoService,
|
||||||
this.apiService,
|
this.apiService,
|
||||||
this.tokenService,
|
this.tokenService,
|
||||||
@@ -358,8 +351,6 @@ export class LoginStrategyService implements LoginStrategyServiceAbstraction {
|
|||||||
case AuthenticationType.Sso:
|
case AuthenticationType.Sso:
|
||||||
return new SsoLoginStrategy(
|
return new SsoLoginStrategy(
|
||||||
data?.sso,
|
data?.sso,
|
||||||
this.accountService,
|
|
||||||
this.masterPasswordService,
|
|
||||||
this.cryptoService,
|
this.cryptoService,
|
||||||
this.apiService,
|
this.apiService,
|
||||||
this.tokenService,
|
this.tokenService,
|
||||||
@@ -379,8 +370,6 @@ export class LoginStrategyService implements LoginStrategyServiceAbstraction {
|
|||||||
case AuthenticationType.UserApiKey:
|
case AuthenticationType.UserApiKey:
|
||||||
return new UserApiLoginStrategy(
|
return new UserApiLoginStrategy(
|
||||||
data?.userApiKey,
|
data?.userApiKey,
|
||||||
this.accountService,
|
|
||||||
this.masterPasswordService,
|
|
||||||
this.cryptoService,
|
this.cryptoService,
|
||||||
this.apiService,
|
this.apiService,
|
||||||
this.tokenService,
|
this.tokenService,
|
||||||
@@ -398,8 +387,6 @@ export class LoginStrategyService implements LoginStrategyServiceAbstraction {
|
|||||||
case AuthenticationType.AuthRequest:
|
case AuthenticationType.AuthRequest:
|
||||||
return new AuthRequestLoginStrategy(
|
return new AuthRequestLoginStrategy(
|
||||||
data?.authRequest,
|
data?.authRequest,
|
||||||
this.accountService,
|
|
||||||
this.masterPasswordService,
|
|
||||||
this.cryptoService,
|
this.cryptoService,
|
||||||
this.apiService,
|
this.apiService,
|
||||||
this.tokenService,
|
this.tokenService,
|
||||||
@@ -416,8 +403,6 @@ export class LoginStrategyService implements LoginStrategyServiceAbstraction {
|
|||||||
case AuthenticationType.WebAuthn:
|
case AuthenticationType.WebAuthn:
|
||||||
return new WebAuthnLoginStrategy(
|
return new WebAuthnLoginStrategy(
|
||||||
data?.webAuthn,
|
data?.webAuthn,
|
||||||
this.accountService,
|
|
||||||
this.masterPasswordService,
|
|
||||||
this.cryptoService,
|
this.cryptoService,
|
||||||
this.apiService,
|
this.apiService,
|
||||||
this.tokenService,
|
this.tokenService,
|
||||||
|
|||||||
@@ -1,67 +0,0 @@
|
|||||||
import { Observable } from "rxjs";
|
|
||||||
|
|
||||||
import { EncString } from "../../platform/models/domain/enc-string";
|
|
||||||
import { UserId } from "../../types/guid";
|
|
||||||
import { MasterKey } from "../../types/key";
|
|
||||||
import { ForceSetPasswordReason } from "../models/domain/force-set-password-reason";
|
|
||||||
|
|
||||||
export abstract class MasterPasswordServiceAbstraction {
|
|
||||||
/**
|
|
||||||
* An observable that emits if the user is being forced to set a password on login and why.
|
|
||||||
* @param userId The user ID.
|
|
||||||
* @throws If the user ID is missing.
|
|
||||||
*/
|
|
||||||
abstract forceSetPasswordReason$: (userId: UserId) => Observable<ForceSetPasswordReason>;
|
|
||||||
/**
|
|
||||||
* An observable that emits the master key for the user.
|
|
||||||
* @param userId The user ID.
|
|
||||||
* @throws If the user ID is missing.
|
|
||||||
*/
|
|
||||||
abstract masterKey$: (userId: UserId) => Observable<MasterKey>;
|
|
||||||
/**
|
|
||||||
* An observable that emits the master key hash for the user.
|
|
||||||
* @param userId The user ID.
|
|
||||||
* @throws If the user ID is missing.
|
|
||||||
*/
|
|
||||||
abstract masterKeyHash$: (userId: UserId) => Observable<string>;
|
|
||||||
/**
|
|
||||||
* Returns the master key encrypted user key for the user.
|
|
||||||
* @param userId The user ID.
|
|
||||||
* @throws If the user ID is missing.
|
|
||||||
*/
|
|
||||||
abstract getMasterKeyEncryptedUserKey: (userId: UserId) => Promise<EncString>;
|
|
||||||
}
|
|
||||||
|
|
||||||
export abstract class InternalMasterPasswordServiceAbstraction extends MasterPasswordServiceAbstraction {
|
|
||||||
/**
|
|
||||||
* Set the master key for the user.
|
|
||||||
* @param masterKey The master key.
|
|
||||||
* @param userId The user ID.
|
|
||||||
* @throws If the user ID or master key is missing.
|
|
||||||
*/
|
|
||||||
abstract setMasterKey: (masterKey: MasterKey, userId: UserId) => Promise<void>;
|
|
||||||
/**
|
|
||||||
* Set the master key hash for the user.
|
|
||||||
* @param masterKeyHash The master key hash.
|
|
||||||
* @param userId The user ID.
|
|
||||||
* @throws If the user ID or master key hash is missing.
|
|
||||||
*/
|
|
||||||
abstract setMasterKeyHash: (masterKeyHash: string, userId: UserId) => Promise<void>;
|
|
||||||
/**
|
|
||||||
* Set the master key encrypted user key for the user.
|
|
||||||
* @param encryptedKey The master key encrypted user key.
|
|
||||||
* @param userId The user ID.
|
|
||||||
* @throws If the user ID or encrypted key is missing.
|
|
||||||
*/
|
|
||||||
abstract setMasterKeyEncryptedUserKey: (encryptedKey: EncString, userId: UserId) => Promise<void>;
|
|
||||||
/**
|
|
||||||
* Set the force set password reason for the user.
|
|
||||||
* @param reason The reason the user is being forced to set a password.
|
|
||||||
* @param userId The user ID.
|
|
||||||
* @throws If the user ID or reason is missing.
|
|
||||||
*/
|
|
||||||
abstract setForceSetPasswordReason: (
|
|
||||||
reason: ForceSetPasswordReason,
|
|
||||||
userId: UserId,
|
|
||||||
) => Promise<void>;
|
|
||||||
}
|
|
||||||
@@ -21,7 +21,6 @@ import {
|
|||||||
CONVERT_ACCOUNT_TO_KEY_CONNECTOR,
|
CONVERT_ACCOUNT_TO_KEY_CONNECTOR,
|
||||||
KeyConnectorService,
|
KeyConnectorService,
|
||||||
} from "./key-connector.service";
|
} from "./key-connector.service";
|
||||||
import { FakeMasterPasswordService } from "./master-password/fake-master-password.service";
|
|
||||||
import { TokenService } from "./token.service";
|
import { TokenService } from "./token.service";
|
||||||
|
|
||||||
describe("KeyConnectorService", () => {
|
describe("KeyConnectorService", () => {
|
||||||
@@ -37,7 +36,6 @@ describe("KeyConnectorService", () => {
|
|||||||
let stateProvider: FakeStateProvider;
|
let stateProvider: FakeStateProvider;
|
||||||
|
|
||||||
let accountService: FakeAccountService;
|
let accountService: FakeAccountService;
|
||||||
let masterPasswordService: FakeMasterPasswordService;
|
|
||||||
|
|
||||||
const mockUserId = Utils.newGuid() as UserId;
|
const mockUserId = Utils.newGuid() as UserId;
|
||||||
const mockOrgId = Utils.newGuid() as OrganizationId;
|
const mockOrgId = Utils.newGuid() as OrganizationId;
|
||||||
@@ -49,13 +47,10 @@ describe("KeyConnectorService", () => {
|
|||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
jest.clearAllMocks();
|
jest.clearAllMocks();
|
||||||
|
|
||||||
masterPasswordService = new FakeMasterPasswordService();
|
|
||||||
accountService = mockAccountServiceWith(mockUserId);
|
accountService = mockAccountServiceWith(mockUserId);
|
||||||
stateProvider = new FakeStateProvider(accountService);
|
stateProvider = new FakeStateProvider(accountService);
|
||||||
|
|
||||||
keyConnectorService = new KeyConnectorService(
|
keyConnectorService = new KeyConnectorService(
|
||||||
accountService,
|
|
||||||
masterPasswordService,
|
|
||||||
cryptoService,
|
cryptoService,
|
||||||
apiService,
|
apiService,
|
||||||
tokenService,
|
tokenService,
|
||||||
@@ -219,10 +214,7 @@ describe("KeyConnectorService", () => {
|
|||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
expect(apiService.getMasterKeyFromKeyConnector).toHaveBeenCalledWith(url);
|
expect(apiService.getMasterKeyFromKeyConnector).toHaveBeenCalledWith(url);
|
||||||
expect(masterPasswordService.mock.setMasterKey).toHaveBeenCalledWith(
|
expect(cryptoService.setMasterKey).toHaveBeenCalledWith(masterKey);
|
||||||
masterKey,
|
|
||||||
expect.any(String),
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should handle errors thrown during the process", async () => {
|
it("should handle errors thrown during the process", async () => {
|
||||||
@@ -249,10 +241,10 @@ describe("KeyConnectorService", () => {
|
|||||||
// Arrange
|
// Arrange
|
||||||
const organization = organizationData(true, true, "https://key-connector-url.com", 2, false);
|
const organization = organizationData(true, true, "https://key-connector-url.com", 2, false);
|
||||||
const masterKey = getMockMasterKey();
|
const masterKey = getMockMasterKey();
|
||||||
masterPasswordService.masterKeySubject.next(masterKey);
|
|
||||||
const keyConnectorRequest = new KeyConnectorUserKeyRequest(masterKey.encKeyB64);
|
const keyConnectorRequest = new KeyConnectorUserKeyRequest(masterKey.encKeyB64);
|
||||||
|
|
||||||
jest.spyOn(keyConnectorService, "getManagingOrganization").mockResolvedValue(organization);
|
jest.spyOn(keyConnectorService, "getManagingOrganization").mockResolvedValue(organization);
|
||||||
|
jest.spyOn(cryptoService, "getMasterKey").mockResolvedValue(masterKey);
|
||||||
jest.spyOn(apiService, "postUserKeyToKeyConnector").mockResolvedValue();
|
jest.spyOn(apiService, "postUserKeyToKeyConnector").mockResolvedValue();
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
@@ -260,6 +252,7 @@ describe("KeyConnectorService", () => {
|
|||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
expect(keyConnectorService.getManagingOrganization).toHaveBeenCalled();
|
expect(keyConnectorService.getManagingOrganization).toHaveBeenCalled();
|
||||||
|
expect(cryptoService.getMasterKey).toHaveBeenCalled();
|
||||||
expect(apiService.postUserKeyToKeyConnector).toHaveBeenCalledWith(
|
expect(apiService.postUserKeyToKeyConnector).toHaveBeenCalledWith(
|
||||||
organization.keyConnectorUrl,
|
organization.keyConnectorUrl,
|
||||||
keyConnectorRequest,
|
keyConnectorRequest,
|
||||||
@@ -275,8 +268,8 @@ describe("KeyConnectorService", () => {
|
|||||||
const error = new Error("Failed to post user key to key connector");
|
const error = new Error("Failed to post user key to key connector");
|
||||||
organizationService.getAll.mockResolvedValue([organization]);
|
organizationService.getAll.mockResolvedValue([organization]);
|
||||||
|
|
||||||
masterPasswordService.masterKeySubject.next(masterKey);
|
|
||||||
jest.spyOn(keyConnectorService, "getManagingOrganization").mockResolvedValue(organization);
|
jest.spyOn(keyConnectorService, "getManagingOrganization").mockResolvedValue(organization);
|
||||||
|
jest.spyOn(cryptoService, "getMasterKey").mockResolvedValue(masterKey);
|
||||||
jest.spyOn(apiService, "postUserKeyToKeyConnector").mockRejectedValue(error);
|
jest.spyOn(apiService, "postUserKeyToKeyConnector").mockRejectedValue(error);
|
||||||
jest.spyOn(logService, "error");
|
jest.spyOn(logService, "error");
|
||||||
|
|
||||||
@@ -287,6 +280,7 @@ describe("KeyConnectorService", () => {
|
|||||||
// Assert
|
// Assert
|
||||||
expect(logService.error).toHaveBeenCalledWith(error);
|
expect(logService.error).toHaveBeenCalledWith(error);
|
||||||
expect(keyConnectorService.getManagingOrganization).toHaveBeenCalled();
|
expect(keyConnectorService.getManagingOrganization).toHaveBeenCalled();
|
||||||
|
expect(cryptoService.getMasterKey).toHaveBeenCalled();
|
||||||
expect(apiService.postUserKeyToKeyConnector).toHaveBeenCalledWith(
|
expect(apiService.postUserKeyToKeyConnector).toHaveBeenCalledWith(
|
||||||
organization.keyConnectorUrl,
|
organization.keyConnectorUrl,
|
||||||
keyConnectorRequest,
|
keyConnectorRequest,
|
||||||
|
|||||||
@@ -16,9 +16,7 @@ import {
|
|||||||
UserKeyDefinition,
|
UserKeyDefinition,
|
||||||
} from "../../platform/state";
|
} from "../../platform/state";
|
||||||
import { MasterKey } from "../../types/key";
|
import { MasterKey } from "../../types/key";
|
||||||
import { AccountService } from "../abstractions/account.service";
|
|
||||||
import { KeyConnectorService as KeyConnectorServiceAbstraction } from "../abstractions/key-connector.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 { TokenService } from "../abstractions/token.service";
|
||||||
import { KdfConfig } from "../models/domain/kdf-config";
|
import { KdfConfig } from "../models/domain/kdf-config";
|
||||||
import { KeyConnectorUserKeyRequest } from "../models/request/key-connector-user-key.request";
|
import { KeyConnectorUserKeyRequest } from "../models/request/key-connector-user-key.request";
|
||||||
@@ -47,8 +45,6 @@ export class KeyConnectorService implements KeyConnectorServiceAbstraction {
|
|||||||
private usesKeyConnectorState: ActiveUserState<boolean>;
|
private usesKeyConnectorState: ActiveUserState<boolean>;
|
||||||
private convertAccountToKeyConnectorState: ActiveUserState<boolean>;
|
private convertAccountToKeyConnectorState: ActiveUserState<boolean>;
|
||||||
constructor(
|
constructor(
|
||||||
private accountService: AccountService,
|
|
||||||
private masterPasswordService: InternalMasterPasswordServiceAbstraction,
|
|
||||||
private cryptoService: CryptoService,
|
private cryptoService: CryptoService,
|
||||||
private apiService: ApiService,
|
private apiService: ApiService,
|
||||||
private tokenService: TokenService,
|
private tokenService: TokenService,
|
||||||
@@ -82,8 +78,7 @@ export class KeyConnectorService implements KeyConnectorServiceAbstraction {
|
|||||||
|
|
||||||
async migrateUser() {
|
async migrateUser() {
|
||||||
const organization = await this.getManagingOrganization();
|
const organization = await this.getManagingOrganization();
|
||||||
const userId = (await firstValueFrom(this.accountService.activeAccount$))?.id;
|
const masterKey = await this.cryptoService.getMasterKey();
|
||||||
const masterKey = await firstValueFrom(this.masterPasswordService.masterKey$(userId));
|
|
||||||
const keyConnectorRequest = new KeyConnectorUserKeyRequest(masterKey.encKeyB64);
|
const keyConnectorRequest = new KeyConnectorUserKeyRequest(masterKey.encKeyB64);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -104,8 +99,7 @@ export class KeyConnectorService implements KeyConnectorServiceAbstraction {
|
|||||||
const masterKeyResponse = await this.apiService.getMasterKeyFromKeyConnector(url);
|
const masterKeyResponse = await this.apiService.getMasterKeyFromKeyConnector(url);
|
||||||
const keyArr = Utils.fromB64ToArray(masterKeyResponse.key);
|
const keyArr = Utils.fromB64ToArray(masterKeyResponse.key);
|
||||||
const masterKey = new SymmetricCryptoKey(keyArr) as MasterKey;
|
const masterKey = new SymmetricCryptoKey(keyArr) as MasterKey;
|
||||||
const userId = (await firstValueFrom(this.accountService.activeAccount$))?.id;
|
await this.cryptoService.setMasterKey(masterKey);
|
||||||
await this.masterPasswordService.setMasterKey(masterKey, userId);
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
this.handleKeyConnectorError(e);
|
this.handleKeyConnectorError(e);
|
||||||
}
|
}
|
||||||
@@ -142,8 +136,7 @@ export class KeyConnectorService implements KeyConnectorServiceAbstraction {
|
|||||||
kdfConfig,
|
kdfConfig,
|
||||||
);
|
);
|
||||||
const keyConnectorRequest = new KeyConnectorUserKeyRequest(masterKey.encKeyB64);
|
const keyConnectorRequest = new KeyConnectorUserKeyRequest(masterKey.encKeyB64);
|
||||||
const userId = (await firstValueFrom(this.accountService.activeAccount$))?.id;
|
await this.cryptoService.setMasterKey(masterKey);
|
||||||
await this.masterPasswordService.setMasterKey(masterKey, userId);
|
|
||||||
|
|
||||||
const userKey = await this.cryptoService.makeUserKey(masterKey);
|
const userKey = await this.cryptoService.makeUserKey(masterKey);
|
||||||
await this.cryptoService.setUserKey(userKey[0]);
|
await this.cryptoService.setUserKey(userKey[0]);
|
||||||
|
|||||||
@@ -1,56 +0,0 @@
|
|||||||
import { mock } from "jest-mock-extended";
|
|
||||||
import { ReplaySubject, Observable } from "rxjs";
|
|
||||||
|
|
||||||
import { EncString } from "../../../platform/models/domain/enc-string";
|
|
||||||
import { UserId } from "../../../types/guid";
|
|
||||||
import { MasterKey } from "../../../types/key";
|
|
||||||
import { InternalMasterPasswordServiceAbstraction } from "../../abstractions/master-password.service.abstraction";
|
|
||||||
import { ForceSetPasswordReason } from "../../models/domain/force-set-password-reason";
|
|
||||||
|
|
||||||
export class FakeMasterPasswordService implements InternalMasterPasswordServiceAbstraction {
|
|
||||||
mock = mock<InternalMasterPasswordServiceAbstraction>();
|
|
||||||
|
|
||||||
// eslint-disable-next-line rxjs/no-exposed-subjects -- test class
|
|
||||||
masterKeySubject = new ReplaySubject<MasterKey>(1);
|
|
||||||
// eslint-disable-next-line rxjs/no-exposed-subjects -- test class
|
|
||||||
masterKeyHashSubject = new ReplaySubject<string>(1);
|
|
||||||
// eslint-disable-next-line rxjs/no-exposed-subjects -- test class
|
|
||||||
forceSetPasswordReasonSubject = new ReplaySubject<ForceSetPasswordReason>(1);
|
|
||||||
|
|
||||||
constructor(initialMasterKey?: MasterKey, initialMasterKeyHash?: string) {
|
|
||||||
this.masterKeySubject.next(initialMasterKey);
|
|
||||||
this.masterKeyHashSubject.next(initialMasterKeyHash);
|
|
||||||
}
|
|
||||||
|
|
||||||
masterKey$(userId: UserId): Observable<MasterKey> {
|
|
||||||
return this.masterKeySubject.asObservable();
|
|
||||||
}
|
|
||||||
|
|
||||||
setMasterKey(masterKey: MasterKey, userId: UserId): Promise<void> {
|
|
||||||
return this.mock.setMasterKey(masterKey, userId);
|
|
||||||
}
|
|
||||||
|
|
||||||
masterKeyHash$(userId: UserId): Observable<string> {
|
|
||||||
return this.masterKeyHashSubject.asObservable();
|
|
||||||
}
|
|
||||||
|
|
||||||
getMasterKeyEncryptedUserKey(userId: UserId): Promise<EncString> {
|
|
||||||
return this.mock.getMasterKeyEncryptedUserKey(userId);
|
|
||||||
}
|
|
||||||
|
|
||||||
setMasterKeyEncryptedUserKey(encryptedKey: EncString, userId: UserId): Promise<void> {
|
|
||||||
return this.mock.setMasterKeyEncryptedUserKey(encryptedKey, userId);
|
|
||||||
}
|
|
||||||
|
|
||||||
setMasterKeyHash(masterKeyHash: string, userId: UserId): Promise<void> {
|
|
||||||
return this.mock.setMasterKeyHash(masterKeyHash, userId);
|
|
||||||
}
|
|
||||||
|
|
||||||
forceSetPasswordReason$(userId: UserId): Observable<ForceSetPasswordReason> {
|
|
||||||
return this.forceSetPasswordReasonSubject.asObservable();
|
|
||||||
}
|
|
||||||
|
|
||||||
setForceSetPasswordReason(reason: ForceSetPasswordReason, userId: UserId): Promise<void> {
|
|
||||||
return this.mock.setForceSetPasswordReason(reason, userId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,125 +0,0 @@
|
|||||||
import { firstValueFrom, map, Observable } from "rxjs";
|
|
||||||
|
|
||||||
import { EncString } from "../../../platform/models/domain/enc-string";
|
|
||||||
import { SymmetricCryptoKey } from "../../../platform/models/domain/symmetric-crypto-key";
|
|
||||||
import {
|
|
||||||
MASTER_PASSWORD_DISK,
|
|
||||||
MASTER_PASSWORD_MEMORY,
|
|
||||||
StateProvider,
|
|
||||||
UserKeyDefinition,
|
|
||||||
} from "../../../platform/state";
|
|
||||||
import { UserId } from "../../../types/guid";
|
|
||||||
import { MasterKey } from "../../../types/key";
|
|
||||||
import { InternalMasterPasswordServiceAbstraction } from "../../abstractions/master-password.service.abstraction";
|
|
||||||
import { ForceSetPasswordReason } from "../../models/domain/force-set-password-reason";
|
|
||||||
|
|
||||||
/** Memory since master key shouldn't be available on lock */
|
|
||||||
const MASTER_KEY = new UserKeyDefinition<MasterKey>(MASTER_PASSWORD_MEMORY, "masterKey", {
|
|
||||||
deserializer: (masterKey) => SymmetricCryptoKey.fromJSON(masterKey) as MasterKey,
|
|
||||||
clearOn: ["lock", "logout"],
|
|
||||||
});
|
|
||||||
|
|
||||||
/** Disk since master key hash is used for unlock */
|
|
||||||
const MASTER_KEY_HASH = new UserKeyDefinition<string>(MASTER_PASSWORD_DISK, "masterKeyHash", {
|
|
||||||
deserializer: (masterKeyHash) => masterKeyHash,
|
|
||||||
clearOn: ["logout"],
|
|
||||||
});
|
|
||||||
|
|
||||||
const MASTER_KEY_ENCRYPTED_USER_KEY = new UserKeyDefinition<EncString>(
|
|
||||||
MASTER_PASSWORD_DISK,
|
|
||||||
"masterKeyEncryptedUserKey",
|
|
||||||
{
|
|
||||||
deserializer: (key) => EncString.fromJSON(key),
|
|
||||||
clearOn: ["logout"],
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
/** Disk to persist through lock and account switches */
|
|
||||||
const FORCE_SET_PASSWORD_REASON = new UserKeyDefinition<ForceSetPasswordReason>(
|
|
||||||
MASTER_PASSWORD_DISK,
|
|
||||||
"forceSetPasswordReason",
|
|
||||||
{
|
|
||||||
deserializer: (reason) => reason,
|
|
||||||
clearOn: ["logout"],
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
export class MasterPasswordService implements InternalMasterPasswordServiceAbstraction {
|
|
||||||
constructor(private stateProvider: StateProvider) {}
|
|
||||||
|
|
||||||
masterKey$(userId: UserId): Observable<MasterKey> {
|
|
||||||
if (userId == null) {
|
|
||||||
throw new Error("User ID is required.");
|
|
||||||
}
|
|
||||||
return this.stateProvider.getUser(userId, MASTER_KEY).state$;
|
|
||||||
}
|
|
||||||
|
|
||||||
masterKeyHash$(userId: UserId): Observable<string> {
|
|
||||||
if (userId == null) {
|
|
||||||
throw new Error("User ID is required.");
|
|
||||||
}
|
|
||||||
return this.stateProvider.getUser(userId, MASTER_KEY_HASH).state$;
|
|
||||||
}
|
|
||||||
|
|
||||||
forceSetPasswordReason$(userId: UserId): Observable<ForceSetPasswordReason> {
|
|
||||||
if (userId == null) {
|
|
||||||
throw new Error("User ID is required.");
|
|
||||||
}
|
|
||||||
return this.stateProvider
|
|
||||||
.getUser(userId, FORCE_SET_PASSWORD_REASON)
|
|
||||||
.state$.pipe(map((reason) => reason ?? ForceSetPasswordReason.None));
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: Remove this method and decrypt directly in the service instead
|
|
||||||
async getMasterKeyEncryptedUserKey(userId: UserId): Promise<EncString> {
|
|
||||||
if (userId == null) {
|
|
||||||
throw new Error("User ID is required.");
|
|
||||||
}
|
|
||||||
const key = await firstValueFrom(
|
|
||||||
this.stateProvider.getUser(userId, MASTER_KEY_ENCRYPTED_USER_KEY).state$,
|
|
||||||
);
|
|
||||||
return key;
|
|
||||||
}
|
|
||||||
|
|
||||||
async setMasterKey(masterKey: MasterKey, userId: UserId): Promise<void> {
|
|
||||||
if (masterKey == null) {
|
|
||||||
throw new Error("Master key is required.");
|
|
||||||
}
|
|
||||||
if (userId == null) {
|
|
||||||
throw new Error("User ID is required.");
|
|
||||||
}
|
|
||||||
await this.stateProvider.getUser(userId, MASTER_KEY).update((_) => masterKey);
|
|
||||||
}
|
|
||||||
|
|
||||||
async setMasterKeyHash(masterKeyHash: string, userId: UserId): Promise<void> {
|
|
||||||
if (masterKeyHash == null) {
|
|
||||||
throw new Error("Master key hash is required.");
|
|
||||||
}
|
|
||||||
if (userId == null) {
|
|
||||||
throw new Error("User ID is required.");
|
|
||||||
}
|
|
||||||
await this.stateProvider.getUser(userId, MASTER_KEY_HASH).update((_) => masterKeyHash);
|
|
||||||
}
|
|
||||||
|
|
||||||
async setMasterKeyEncryptedUserKey(encryptedKey: EncString, userId: UserId): Promise<void> {
|
|
||||||
if (encryptedKey == null) {
|
|
||||||
throw new Error("Encrypted Key is required.");
|
|
||||||
}
|
|
||||||
if (userId == null) {
|
|
||||||
throw new Error("User ID is required.");
|
|
||||||
}
|
|
||||||
await this.stateProvider
|
|
||||||
.getUser(userId, MASTER_KEY_ENCRYPTED_USER_KEY)
|
|
||||||
.update((_) => encryptedKey);
|
|
||||||
}
|
|
||||||
|
|
||||||
async setForceSetPasswordReason(reason: ForceSetPasswordReason, userId: UserId): Promise<void> {
|
|
||||||
if (reason == null) {
|
|
||||||
throw new Error("Reason is required.");
|
|
||||||
}
|
|
||||||
if (userId == null) {
|
|
||||||
throw new Error("User ID is required.");
|
|
||||||
}
|
|
||||||
await this.stateProvider.getUser(userId, FORCE_SET_PASSWORD_REASON).update((_) => reason);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -10,10 +10,7 @@ import { LogService } from "../../../platform/abstractions/log.service";
|
|||||||
import { PlatformUtilsService } from "../../../platform/abstractions/platform-utils.service";
|
import { PlatformUtilsService } from "../../../platform/abstractions/platform-utils.service";
|
||||||
import { StateService } from "../../../platform/abstractions/state.service";
|
import { StateService } from "../../../platform/abstractions/state.service";
|
||||||
import { KeySuffixOptions } from "../../../platform/enums/key-suffix-options.enum";
|
import { KeySuffixOptions } from "../../../platform/enums/key-suffix-options.enum";
|
||||||
import { UserId } from "../../../types/guid";
|
|
||||||
import { UserKey } from "../../../types/key";
|
import { UserKey } from "../../../types/key";
|
||||||
import { AccountService } from "../../abstractions/account.service";
|
|
||||||
import { InternalMasterPasswordServiceAbstraction } from "../../abstractions/master-password.service.abstraction";
|
|
||||||
import { UserVerificationApiServiceAbstraction } from "../../abstractions/user-verification/user-verification-api.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";
|
import { UserVerificationService as UserVerificationServiceAbstraction } from "../../abstractions/user-verification/user-verification.service.abstraction";
|
||||||
import { VerificationType } from "../../enums/verification-type";
|
import { VerificationType } from "../../enums/verification-type";
|
||||||
@@ -38,8 +35,6 @@ export class UserVerificationService implements UserVerificationServiceAbstracti
|
|||||||
constructor(
|
constructor(
|
||||||
private stateService: StateService,
|
private stateService: StateService,
|
||||||
private cryptoService: CryptoService,
|
private cryptoService: CryptoService,
|
||||||
private accountService: AccountService,
|
|
||||||
private masterPasswordService: InternalMasterPasswordServiceAbstraction,
|
|
||||||
private i18nService: I18nService,
|
private i18nService: I18nService,
|
||||||
private userVerificationApiService: UserVerificationApiServiceAbstraction,
|
private userVerificationApiService: UserVerificationApiServiceAbstraction,
|
||||||
private userDecryptionOptionsService: UserDecryptionOptionsServiceAbstraction,
|
private userDecryptionOptionsService: UserDecryptionOptionsServiceAbstraction,
|
||||||
@@ -112,8 +107,7 @@ export class UserVerificationService implements UserVerificationServiceAbstracti
|
|||||||
if (verification.type === VerificationType.OTP) {
|
if (verification.type === VerificationType.OTP) {
|
||||||
request.otp = verification.secret;
|
request.otp = verification.secret;
|
||||||
} else {
|
} else {
|
||||||
const userId = (await firstValueFrom(this.accountService.activeAccount$))?.id;
|
let masterKey = await this.cryptoService.getMasterKey();
|
||||||
let masterKey = await firstValueFrom(this.masterPasswordService.masterKey$(userId));
|
|
||||||
if (!masterKey && !alreadyHashed) {
|
if (!masterKey && !alreadyHashed) {
|
||||||
masterKey = await this.cryptoService.makeMasterKey(
|
masterKey = await this.cryptoService.makeMasterKey(
|
||||||
verification.secret,
|
verification.secret,
|
||||||
@@ -170,8 +164,7 @@ export class UserVerificationService implements UserVerificationServiceAbstracti
|
|||||||
private async verifyUserByMasterPassword(
|
private async verifyUserByMasterPassword(
|
||||||
verification: MasterPasswordVerification,
|
verification: MasterPasswordVerification,
|
||||||
): Promise<boolean> {
|
): Promise<boolean> {
|
||||||
const userId = (await firstValueFrom(this.accountService.activeAccount$))?.id;
|
let masterKey = await this.cryptoService.getMasterKey();
|
||||||
let masterKey = await firstValueFrom(this.masterPasswordService.masterKey$(userId));
|
|
||||||
if (!masterKey) {
|
if (!masterKey) {
|
||||||
masterKey = await this.cryptoService.makeMasterKey(
|
masterKey = await this.cryptoService.makeMasterKey(
|
||||||
verification.secret,
|
verification.secret,
|
||||||
@@ -188,7 +181,7 @@ export class UserVerificationService implements UserVerificationServiceAbstracti
|
|||||||
throw new Error(this.i18nService.t("invalidMasterPassword"));
|
throw new Error(this.i18nService.t("invalidMasterPassword"));
|
||||||
}
|
}
|
||||||
// TODO: we should re-evaluate later on if user verification should have the side effect of modifying state. Probably not.
|
// TODO: we should re-evaluate later on if user verification should have the side effect of modifying state. Probably not.
|
||||||
await this.masterPasswordService.setMasterKey(masterKey, userId);
|
await this.cryptoService.setMasterKey(masterKey);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -237,10 +230,9 @@ export class UserVerificationService implements UserVerificationServiceAbstracti
|
|||||||
}
|
}
|
||||||
|
|
||||||
async hasMasterPasswordAndMasterKeyHash(userId?: string): Promise<boolean> {
|
async hasMasterPasswordAndMasterKeyHash(userId?: string): Promise<boolean> {
|
||||||
userId ??= (await firstValueFrom(this.accountService.activeAccount$))?.id;
|
|
||||||
return (
|
return (
|
||||||
(await this.hasMasterPassword(userId)) &&
|
(await this.hasMasterPassword(userId)) &&
|
||||||
(await firstValueFrom(this.masterPasswordService.masterKeyHash$(userId as UserId))) != null
|
(await this.cryptoService.getMasterKeyHash()) != null
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -112,6 +112,18 @@ export abstract class CryptoService {
|
|||||||
* @param userId The desired user
|
* @param userId The desired user
|
||||||
*/
|
*/
|
||||||
abstract setMasterKeyEncryptedUserKey(UserKeyMasterKey: string, userId?: string): Promise<void>;
|
abstract setMasterKeyEncryptedUserKey(UserKeyMasterKey: string, userId?: string): Promise<void>;
|
||||||
|
/**
|
||||||
|
* Sets the user's master key
|
||||||
|
* @param key The user's master key to set
|
||||||
|
* @param userId The desired user
|
||||||
|
*/
|
||||||
|
abstract setMasterKey(key: MasterKey, userId?: string): Promise<void>;
|
||||||
|
/**
|
||||||
|
* @param userId The desired user
|
||||||
|
* @returns The user's master key
|
||||||
|
*/
|
||||||
|
abstract getMasterKey(userId?: string): Promise<MasterKey>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param password The user's master password that will be used to derive a master key if one isn't found
|
* @param password The user's master password that will be used to derive a master key if one isn't found
|
||||||
* @param userId The desired user
|
* @param userId The desired user
|
||||||
@@ -131,6 +143,11 @@ export abstract class CryptoService {
|
|||||||
kdf: KdfType,
|
kdf: KdfType,
|
||||||
KdfConfig: KdfConfig,
|
KdfConfig: KdfConfig,
|
||||||
): Promise<MasterKey>;
|
): Promise<MasterKey>;
|
||||||
|
/**
|
||||||
|
* Clears the user's master key
|
||||||
|
* @param userId The desired user
|
||||||
|
*/
|
||||||
|
abstract clearMasterKey(userId?: string): Promise<void>;
|
||||||
/**
|
/**
|
||||||
* Encrypts the existing (or provided) user key with the
|
* Encrypts the existing (or provided) user key with the
|
||||||
* provided master key
|
* provided master key
|
||||||
@@ -168,6 +185,20 @@ export abstract class CryptoService {
|
|||||||
key: MasterKey,
|
key: MasterKey,
|
||||||
hashPurpose?: HashPurpose,
|
hashPurpose?: HashPurpose,
|
||||||
): Promise<string>;
|
): Promise<string>;
|
||||||
|
/**
|
||||||
|
* Sets the user's master password hash
|
||||||
|
* @param keyHash The user's master password hash to set
|
||||||
|
*/
|
||||||
|
abstract setMasterKeyHash(keyHash: string): Promise<void>;
|
||||||
|
/**
|
||||||
|
* @returns The user's master password hash
|
||||||
|
*/
|
||||||
|
abstract getMasterKeyHash(): Promise<string>;
|
||||||
|
/**
|
||||||
|
* Clears the user's stored master password hash
|
||||||
|
* @param userId The desired user
|
||||||
|
*/
|
||||||
|
abstract clearMasterKeyHash(userId?: string): Promise<void>;
|
||||||
/**
|
/**
|
||||||
* Compares the provided master password to the stored password hash and server password hash.
|
* Compares the provided master password to the stored password hash and server password hash.
|
||||||
* Updates the stored hash if outdated.
|
* Updates the stored hash if outdated.
|
||||||
|
|||||||
@@ -1,12 +1,14 @@
|
|||||||
import { Observable } from "rxjs";
|
import { Observable } from "rxjs";
|
||||||
|
|
||||||
import { AdminAuthRequestStorable } from "../../auth/models/domain/admin-auth-req-storable";
|
import { AdminAuthRequestStorable } from "../../auth/models/domain/admin-auth-req-storable";
|
||||||
|
import { ForceSetPasswordReason } from "../../auth/models/domain/force-set-password-reason";
|
||||||
import { KdfConfig } from "../../auth/models/domain/kdf-config";
|
import { KdfConfig } from "../../auth/models/domain/kdf-config";
|
||||||
import { BiometricKey } from "../../auth/types/biometric-key";
|
import { BiometricKey } from "../../auth/types/biometric-key";
|
||||||
import { GeneratorOptions } from "../../tools/generator/generator-options";
|
import { GeneratorOptions } from "../../tools/generator/generator-options";
|
||||||
import { GeneratedPasswordHistory, PasswordGeneratorOptions } from "../../tools/generator/password";
|
import { GeneratedPasswordHistory, PasswordGeneratorOptions } from "../../tools/generator/password";
|
||||||
import { UsernameGeneratorOptions } from "../../tools/generator/username";
|
import { UsernameGeneratorOptions } from "../../tools/generator/username";
|
||||||
import { UserId } from "../../types/guid";
|
import { UserId } from "../../types/guid";
|
||||||
|
import { MasterKey } from "../../types/key";
|
||||||
import { CipherData } from "../../vault/models/data/cipher.data";
|
import { CipherData } from "../../vault/models/data/cipher.data";
|
||||||
import { LocalData } from "../../vault/models/data/local.data";
|
import { LocalData } from "../../vault/models/data/local.data";
|
||||||
import { CipherView } from "../../vault/models/view/cipher.view";
|
import { CipherView } from "../../vault/models/view/cipher.view";
|
||||||
@@ -15,6 +17,7 @@ import { KdfType } from "../enums";
|
|||||||
import { Account } from "../models/domain/account";
|
import { Account } from "../models/domain/account";
|
||||||
import { EncString } from "../models/domain/enc-string";
|
import { EncString } from "../models/domain/enc-string";
|
||||||
import { StorageOptions } from "../models/domain/storage-options";
|
import { StorageOptions } from "../models/domain/storage-options";
|
||||||
|
import { SymmetricCryptoKey } from "../models/domain/symmetric-crypto-key";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Options for customizing the initiation behavior.
|
* Options for customizing the initiation behavior.
|
||||||
@@ -45,6 +48,22 @@ export abstract class StateService<T extends Account = Account> {
|
|||||||
|
|
||||||
getAddEditCipherInfo: (options?: StorageOptions) => Promise<AddEditCipherInfo>;
|
getAddEditCipherInfo: (options?: StorageOptions) => Promise<AddEditCipherInfo>;
|
||||||
setAddEditCipherInfo: (value: AddEditCipherInfo, options?: StorageOptions) => Promise<void>;
|
setAddEditCipherInfo: (value: AddEditCipherInfo, options?: StorageOptions) => Promise<void>;
|
||||||
|
/**
|
||||||
|
* Gets the user's master key
|
||||||
|
*/
|
||||||
|
getMasterKey: (options?: StorageOptions) => Promise<MasterKey>;
|
||||||
|
/**
|
||||||
|
* Sets the user's master key
|
||||||
|
*/
|
||||||
|
setMasterKey: (value: MasterKey, options?: StorageOptions) => Promise<void>;
|
||||||
|
/**
|
||||||
|
* Gets the user key encrypted by the master key
|
||||||
|
*/
|
||||||
|
getMasterKeyEncryptedUserKey: (options?: StorageOptions) => Promise<string>;
|
||||||
|
/**
|
||||||
|
* Sets the user key encrypted by the master key
|
||||||
|
*/
|
||||||
|
setMasterKeyEncryptedUserKey: (value: string, options?: StorageOptions) => Promise<void>;
|
||||||
/**
|
/**
|
||||||
* Gets the user's auto key
|
* Gets the user's auto key
|
||||||
*/
|
*/
|
||||||
@@ -89,6 +108,10 @@ export abstract class StateService<T extends Account = Account> {
|
|||||||
* @deprecated For migration purposes only, use getUserKeyMasterKey instead
|
* @deprecated For migration purposes only, use getUserKeyMasterKey instead
|
||||||
*/
|
*/
|
||||||
getEncryptedCryptoSymmetricKey: (options?: StorageOptions) => Promise<string>;
|
getEncryptedCryptoSymmetricKey: (options?: StorageOptions) => Promise<string>;
|
||||||
|
/**
|
||||||
|
* @deprecated For legacy purposes only, use getMasterKey instead
|
||||||
|
*/
|
||||||
|
getCryptoMasterKey: (options?: StorageOptions) => Promise<SymmetricCryptoKey>;
|
||||||
/**
|
/**
|
||||||
* @deprecated For migration purposes only, use getUserKeyAuto instead
|
* @deprecated For migration purposes only, use getUserKeyAuto instead
|
||||||
*/
|
*/
|
||||||
@@ -166,11 +189,18 @@ export abstract class StateService<T extends Account = Account> {
|
|||||||
setEncryptedPinProtected: (value: string, options?: StorageOptions) => Promise<void>;
|
setEncryptedPinProtected: (value: string, options?: StorageOptions) => Promise<void>;
|
||||||
getEverBeenUnlocked: (options?: StorageOptions) => Promise<boolean>;
|
getEverBeenUnlocked: (options?: StorageOptions) => Promise<boolean>;
|
||||||
setEverBeenUnlocked: (value: boolean, options?: StorageOptions) => Promise<void>;
|
setEverBeenUnlocked: (value: boolean, options?: StorageOptions) => Promise<void>;
|
||||||
|
getForceSetPasswordReason: (options?: StorageOptions) => Promise<ForceSetPasswordReason>;
|
||||||
|
setForceSetPasswordReason: (
|
||||||
|
value: ForceSetPasswordReason,
|
||||||
|
options?: StorageOptions,
|
||||||
|
) => Promise<void>;
|
||||||
getIsAuthenticated: (options?: StorageOptions) => Promise<boolean>;
|
getIsAuthenticated: (options?: StorageOptions) => Promise<boolean>;
|
||||||
getKdfConfig: (options?: StorageOptions) => Promise<KdfConfig>;
|
getKdfConfig: (options?: StorageOptions) => Promise<KdfConfig>;
|
||||||
setKdfConfig: (kdfConfig: KdfConfig, options?: StorageOptions) => Promise<void>;
|
setKdfConfig: (kdfConfig: KdfConfig, options?: StorageOptions) => Promise<void>;
|
||||||
getKdfType: (options?: StorageOptions) => Promise<KdfType>;
|
getKdfType: (options?: StorageOptions) => Promise<KdfType>;
|
||||||
setKdfType: (value: KdfType, options?: StorageOptions) => Promise<void>;
|
setKdfType: (value: KdfType, options?: StorageOptions) => Promise<void>;
|
||||||
|
getKeyHash: (options?: StorageOptions) => Promise<string>;
|
||||||
|
setKeyHash: (value: string, options?: StorageOptions) => Promise<void>;
|
||||||
getLastActive: (options?: StorageOptions) => Promise<number>;
|
getLastActive: (options?: StorageOptions) => Promise<number>;
|
||||||
setLastActive: (value: number, options?: StorageOptions) => Promise<void>;
|
setLastActive: (value: number, options?: StorageOptions) => Promise<void>;
|
||||||
getLastSync: (options?: StorageOptions) => Promise<string>;
|
getLastSync: (options?: StorageOptions) => Promise<string>;
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import { makeStaticByteArray } from "../../../../spec";
|
|||||||
import { Utils } from "../../misc/utils";
|
import { Utils } from "../../misc/utils";
|
||||||
|
|
||||||
import { AccountKeys, EncryptionPair } from "./account";
|
import { AccountKeys, EncryptionPair } from "./account";
|
||||||
|
import { SymmetricCryptoKey } from "./symmetric-crypto-key";
|
||||||
|
|
||||||
describe("AccountKeys", () => {
|
describe("AccountKeys", () => {
|
||||||
describe("toJSON", () => {
|
describe("toJSON", () => {
|
||||||
@@ -31,6 +32,12 @@ describe("AccountKeys", () => {
|
|||||||
expect(keys.publicKey).toEqual(Utils.fromByteStringToArray("hello"));
|
expect(keys.publicKey).toEqual(Utils.fromByteStringToArray("hello"));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("should deserialize cryptoMasterKey", () => {
|
||||||
|
const spy = jest.spyOn(SymmetricCryptoKey, "fromJSON");
|
||||||
|
AccountKeys.fromJSON({} as any);
|
||||||
|
expect(spy).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
it("should deserialize privateKey", () => {
|
it("should deserialize privateKey", () => {
|
||||||
const spy = jest.spyOn(EncryptionPair, "fromJSON");
|
const spy = jest.spyOn(EncryptionPair, "fromJSON");
|
||||||
AccountKeys.fromJSON({
|
AccountKeys.fromJSON({
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { Jsonify } from "type-fest";
|
import { Jsonify } from "type-fest";
|
||||||
|
|
||||||
import { AdminAuthRequestStorable } from "../../../auth/models/domain/admin-auth-req-storable";
|
import { AdminAuthRequestStorable } from "../../../auth/models/domain/admin-auth-req-storable";
|
||||||
|
import { ForceSetPasswordReason } from "../../../auth/models/domain/force-set-password-reason";
|
||||||
import { UriMatchStrategySetting } from "../../../models/domain/domain-service";
|
import { UriMatchStrategySetting } from "../../../models/domain/domain-service";
|
||||||
import { GeneratorOptions } from "../../../tools/generator/generator-options";
|
import { GeneratorOptions } from "../../../tools/generator/generator-options";
|
||||||
import {
|
import {
|
||||||
@@ -9,6 +10,7 @@ import {
|
|||||||
} from "../../../tools/generator/password";
|
} from "../../../tools/generator/password";
|
||||||
import { UsernameGeneratorOptions } from "../../../tools/generator/username/username-generation-options";
|
import { UsernameGeneratorOptions } from "../../../tools/generator/username/username-generation-options";
|
||||||
import { DeepJsonify } from "../../../types/deep-jsonify";
|
import { DeepJsonify } from "../../../types/deep-jsonify";
|
||||||
|
import { MasterKey } from "../../../types/key";
|
||||||
import { CipherData } from "../../../vault/models/data/cipher.data";
|
import { CipherData } from "../../../vault/models/data/cipher.data";
|
||||||
import { CipherView } from "../../../vault/models/view/cipher.view";
|
import { CipherView } from "../../../vault/models/view/cipher.view";
|
||||||
import { AddEditCipherInfo } from "../../../vault/types/add-edit-cipher-info";
|
import { AddEditCipherInfo } from "../../../vault/types/add-edit-cipher-info";
|
||||||
@@ -88,8 +90,12 @@ export class AccountData {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export class AccountKeys {
|
export class AccountKeys {
|
||||||
|
masterKey?: MasterKey;
|
||||||
|
masterKeyEncryptedUserKey?: string;
|
||||||
publicKey?: Uint8Array;
|
publicKey?: Uint8Array;
|
||||||
|
|
||||||
|
/** @deprecated July 2023, left for migration purposes*/
|
||||||
|
cryptoMasterKey?: SymmetricCryptoKey;
|
||||||
/** @deprecated July 2023, left for migration purposes*/
|
/** @deprecated July 2023, left for migration purposes*/
|
||||||
cryptoMasterKeyAuto?: string;
|
cryptoMasterKeyAuto?: string;
|
||||||
/** @deprecated July 2023, left for migration purposes*/
|
/** @deprecated July 2023, left for migration purposes*/
|
||||||
@@ -114,6 +120,8 @@ export class AccountKeys {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return Object.assign(new AccountKeys(), obj, {
|
return Object.assign(new AccountKeys(), obj, {
|
||||||
|
masterKey: SymmetricCryptoKey.fromJSON(obj?.masterKey),
|
||||||
|
cryptoMasterKey: SymmetricCryptoKey.fromJSON(obj?.cryptoMasterKey),
|
||||||
cryptoSymmetricKey: EncryptionPair.fromJSON(
|
cryptoSymmetricKey: EncryptionPair.fromJSON(
|
||||||
obj?.cryptoSymmetricKey,
|
obj?.cryptoSymmetricKey,
|
||||||
SymmetricCryptoKey.fromJSON,
|
SymmetricCryptoKey.fromJSON,
|
||||||
@@ -142,8 +150,10 @@ export class AccountProfile {
|
|||||||
email?: string;
|
email?: string;
|
||||||
emailVerified?: boolean;
|
emailVerified?: boolean;
|
||||||
everBeenUnlocked?: boolean;
|
everBeenUnlocked?: boolean;
|
||||||
|
forceSetPasswordReason?: ForceSetPasswordReason;
|
||||||
lastSync?: string;
|
lastSync?: string;
|
||||||
userId?: string;
|
userId?: string;
|
||||||
|
keyHash?: string;
|
||||||
kdfIterations?: number;
|
kdfIterations?: number;
|
||||||
kdfMemory?: number;
|
kdfMemory?: number;
|
||||||
kdfParallelism?: number;
|
kdfParallelism?: number;
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ import { FakeAccountService, mockAccountServiceWith } from "../../../spec/fake-a
|
|||||||
import { FakeActiveUserState, FakeSingleUserState } from "../../../spec/fake-state";
|
import { FakeActiveUserState, FakeSingleUserState } from "../../../spec/fake-state";
|
||||||
import { FakeStateProvider } from "../../../spec/fake-state-provider";
|
import { FakeStateProvider } from "../../../spec/fake-state-provider";
|
||||||
import { AuthenticationStatus } from "../../auth/enums/authentication-status";
|
import { AuthenticationStatus } from "../../auth/enums/authentication-status";
|
||||||
import { FakeMasterPasswordService } from "../../auth/services/master-password/fake-master-password.service";
|
|
||||||
import { CsprngArray } from "../../types/csprng";
|
import { CsprngArray } from "../../types/csprng";
|
||||||
import { UserId } from "../../types/guid";
|
import { UserId } from "../../types/guid";
|
||||||
import { UserKey, MasterKey, PinKey } from "../../types/key";
|
import { UserKey, MasterKey, PinKey } from "../../types/key";
|
||||||
@@ -41,15 +40,12 @@ describe("cryptoService", () => {
|
|||||||
|
|
||||||
const mockUserId = Utils.newGuid() as UserId;
|
const mockUserId = Utils.newGuid() as UserId;
|
||||||
let accountService: FakeAccountService;
|
let accountService: FakeAccountService;
|
||||||
let masterPasswordService: FakeMasterPasswordService;
|
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
accountService = mockAccountServiceWith(mockUserId);
|
accountService = mockAccountServiceWith(mockUserId);
|
||||||
masterPasswordService = new FakeMasterPasswordService();
|
|
||||||
stateProvider = new FakeStateProvider(accountService);
|
stateProvider = new FakeStateProvider(accountService);
|
||||||
|
|
||||||
cryptoService = new CryptoService(
|
cryptoService = new CryptoService(
|
||||||
masterPasswordService,
|
|
||||||
keyGenerationService,
|
keyGenerationService,
|
||||||
cryptoFunctionService,
|
cryptoFunctionService,
|
||||||
encryptService,
|
encryptService,
|
||||||
@@ -161,14 +157,14 @@ describe("cryptoService", () => {
|
|||||||
describe("getUserKeyWithLegacySupport", () => {
|
describe("getUserKeyWithLegacySupport", () => {
|
||||||
let mockUserKey: UserKey;
|
let mockUserKey: UserKey;
|
||||||
let mockMasterKey: MasterKey;
|
let mockMasterKey: MasterKey;
|
||||||
let getMasterKey: jest.SpyInstance;
|
let stateSvcGetMasterKey: jest.SpyInstance;
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
const mockRandomBytes = new Uint8Array(64) as CsprngArray;
|
const mockRandomBytes = new Uint8Array(64) as CsprngArray;
|
||||||
mockUserKey = new SymmetricCryptoKey(mockRandomBytes) as UserKey;
|
mockUserKey = new SymmetricCryptoKey(mockRandomBytes) as UserKey;
|
||||||
mockMasterKey = new SymmetricCryptoKey(new Uint8Array(64) as CsprngArray) as MasterKey;
|
mockMasterKey = new SymmetricCryptoKey(new Uint8Array(64) as CsprngArray) as MasterKey;
|
||||||
|
|
||||||
getMasterKey = jest.spyOn(masterPasswordService, "masterKey$");
|
stateSvcGetMasterKey = jest.spyOn(stateService, "getMasterKey");
|
||||||
});
|
});
|
||||||
|
|
||||||
it("returns the User Key if available", async () => {
|
it("returns the User Key if available", async () => {
|
||||||
@@ -178,17 +174,17 @@ describe("cryptoService", () => {
|
|||||||
const userKey = await cryptoService.getUserKeyWithLegacySupport(mockUserId);
|
const userKey = await cryptoService.getUserKeyWithLegacySupport(mockUserId);
|
||||||
|
|
||||||
expect(getKeySpy).toHaveBeenCalledWith(mockUserId);
|
expect(getKeySpy).toHaveBeenCalledWith(mockUserId);
|
||||||
expect(getMasterKey).not.toHaveBeenCalled();
|
expect(stateSvcGetMasterKey).not.toHaveBeenCalled();
|
||||||
|
|
||||||
expect(userKey).toEqual(mockUserKey);
|
expect(userKey).toEqual(mockUserKey);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("returns the user's master key when User Key is not available", async () => {
|
it("returns the user's master key when User Key is not available", async () => {
|
||||||
masterPasswordService.masterKeySubject.next(mockMasterKey);
|
stateSvcGetMasterKey.mockResolvedValue(mockMasterKey);
|
||||||
|
|
||||||
const userKey = await cryptoService.getUserKeyWithLegacySupport(mockUserId);
|
const userKey = await cryptoService.getUserKeyWithLegacySupport(mockUserId);
|
||||||
|
|
||||||
expect(getMasterKey).toHaveBeenCalledWith(mockUserId);
|
expect(stateSvcGetMasterKey).toHaveBeenCalledWith({ userId: mockUserId });
|
||||||
expect(userKey).toEqual(mockMasterKey);
|
expect(userKey).toEqual(mockMasterKey);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ import { ProfileOrganizationResponse } from "../../admin-console/models/response
|
|||||||
import { ProfileProviderOrganizationResponse } from "../../admin-console/models/response/profile-provider-organization.response";
|
import { ProfileProviderOrganizationResponse } from "../../admin-console/models/response/profile-provider-organization.response";
|
||||||
import { ProfileProviderResponse } from "../../admin-console/models/response/profile-provider.response";
|
import { ProfileProviderResponse } from "../../admin-console/models/response/profile-provider.response";
|
||||||
import { AccountService } from "../../auth/abstractions/account.service";
|
import { AccountService } from "../../auth/abstractions/account.service";
|
||||||
import { InternalMasterPasswordServiceAbstraction } from "../../auth/abstractions/master-password.service.abstraction";
|
|
||||||
import { AuthenticationStatus } from "../../auth/enums/authentication-status";
|
import { AuthenticationStatus } from "../../auth/enums/authentication-status";
|
||||||
import { KdfConfig } from "../../auth/models/domain/kdf-config";
|
import { KdfConfig } from "../../auth/models/domain/kdf-config";
|
||||||
import { Utils } from "../../platform/misc/utils";
|
import { Utils } from "../../platform/misc/utils";
|
||||||
@@ -83,7 +82,6 @@ export class CryptoService implements CryptoServiceAbstraction {
|
|||||||
readonly everHadUserKey$: Observable<boolean>;
|
readonly everHadUserKey$: Observable<boolean>;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
protected masterPasswordService: InternalMasterPasswordServiceAbstraction,
|
|
||||||
protected keyGenerationService: KeyGenerationService,
|
protected keyGenerationService: KeyGenerationService,
|
||||||
protected cryptoFunctionService: CryptoFunctionService,
|
protected cryptoFunctionService: CryptoFunctionService,
|
||||||
protected encryptService: EncryptService,
|
protected encryptService: EncryptService,
|
||||||
@@ -183,16 +181,12 @@ export class CryptoService implements CryptoServiceAbstraction {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async isLegacyUser(masterKey?: MasterKey, userId?: UserId): Promise<boolean> {
|
async isLegacyUser(masterKey?: MasterKey, userId?: UserId): Promise<boolean> {
|
||||||
userId ??= await firstValueFrom(this.stateProvider.activeUserId$);
|
return await this.validateUserKey(
|
||||||
masterKey ??= await firstValueFrom(this.masterPasswordService.masterKey$(userId));
|
(masterKey ?? (await this.getMasterKey(userId))) as unknown as UserKey,
|
||||||
|
);
|
||||||
return await this.validateUserKey(masterKey as unknown as UserKey);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: legacy support for user key is no longer needed since we require users to migrate on login
|
|
||||||
async getUserKeyWithLegacySupport(userId?: UserId): Promise<UserKey> {
|
async getUserKeyWithLegacySupport(userId?: UserId): Promise<UserKey> {
|
||||||
userId ??= await firstValueFrom(this.stateProvider.activeUserId$);
|
|
||||||
|
|
||||||
const userKey = await this.getUserKey(userId);
|
const userKey = await this.getUserKey(userId);
|
||||||
if (userKey) {
|
if (userKey) {
|
||||||
return userKey;
|
return userKey;
|
||||||
@@ -200,8 +194,7 @@ export class CryptoService implements CryptoServiceAbstraction {
|
|||||||
|
|
||||||
// Legacy support: encryption used to be done with the master key (derived from master password).
|
// Legacy support: encryption used to be done with the master key (derived from master password).
|
||||||
// Users who have not migrated will have a null user key and must use the master key instead.
|
// Users who have not migrated will have a null user key and must use the master key instead.
|
||||||
const masterKey = await firstValueFrom(this.masterPasswordService.masterKey$(userId));
|
return (await this.getMasterKey(userId)) as unknown as UserKey;
|
||||||
return masterKey as unknown as UserKey;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async getUserKeyFromStorage(keySuffix: KeySuffixOptions, userId?: UserId): Promise<UserKey> {
|
async getUserKeyFromStorage(keySuffix: KeySuffixOptions, userId?: UserId): Promise<UserKey> {
|
||||||
@@ -240,10 +233,7 @@ export class CryptoService implements CryptoServiceAbstraction {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async makeUserKey(masterKey: MasterKey): Promise<[UserKey, EncString]> {
|
async makeUserKey(masterKey: MasterKey): Promise<[UserKey, EncString]> {
|
||||||
if (!masterKey) {
|
masterKey ||= await this.getMasterKey();
|
||||||
const userId = await firstValueFrom(this.stateProvider.activeUserId$);
|
|
||||||
masterKey = await firstValueFrom(this.masterPasswordService.masterKey$(userId));
|
|
||||||
}
|
|
||||||
if (masterKey == null) {
|
if (masterKey == null) {
|
||||||
throw new Error("No Master Key found.");
|
throw new Error("No Master Key found.");
|
||||||
}
|
}
|
||||||
@@ -281,16 +271,28 @@ export class CryptoService implements CryptoServiceAbstraction {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async setMasterKeyEncryptedUserKey(userKeyMasterKey: string, userId?: UserId): Promise<void> {
|
async setMasterKeyEncryptedUserKey(userKeyMasterKey: string, userId?: UserId): Promise<void> {
|
||||||
await this.masterPasswordService.setMasterKeyEncryptedUserKey(
|
await this.stateService.setMasterKeyEncryptedUserKey(userKeyMasterKey, { userId: userId });
|
||||||
new EncString(userKeyMasterKey),
|
}
|
||||||
userId,
|
|
||||||
);
|
async setMasterKey(key: MasterKey, userId?: UserId): Promise<void> {
|
||||||
|
await this.stateService.setMasterKey(key, { userId: userId });
|
||||||
|
}
|
||||||
|
|
||||||
|
async getMasterKey(userId?: UserId): Promise<MasterKey> {
|
||||||
|
let masterKey = await this.stateService.getMasterKey({ userId: userId });
|
||||||
|
if (!masterKey) {
|
||||||
|
masterKey = (await this.stateService.getCryptoMasterKey({ userId: userId })) as MasterKey;
|
||||||
|
// if master key was null/undefined and getCryptoMasterKey also returned null/undefined,
|
||||||
|
// don't set master key as it is unnecessary
|
||||||
|
if (masterKey) {
|
||||||
|
await this.setMasterKey(masterKey, userId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return masterKey;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Move to MasterPasswordService
|
|
||||||
async getOrDeriveMasterKey(password: string, userId?: UserId) {
|
async getOrDeriveMasterKey(password: string, userId?: UserId) {
|
||||||
userId ??= await firstValueFrom(this.stateProvider.activeUserId$);
|
let masterKey = await this.getMasterKey(userId);
|
||||||
let masterKey = await firstValueFrom(this.masterPasswordService.masterKey$(userId));
|
|
||||||
return (masterKey ||= await this.makeMasterKey(
|
return (masterKey ||= await this.makeMasterKey(
|
||||||
password,
|
password,
|
||||||
await this.stateService.getEmail({ userId: userId }),
|
await this.stateService.getEmail({ userId: userId }),
|
||||||
@@ -304,7 +306,6 @@ export class CryptoService implements CryptoServiceAbstraction {
|
|||||||
*
|
*
|
||||||
* @remarks
|
* @remarks
|
||||||
* Does not validate the kdf config to ensure it satisfies the minimum requirements for the given kdf type.
|
* Does not validate the kdf config to ensure it satisfies the minimum requirements for the given kdf type.
|
||||||
* TODO: Move to MasterPasswordService
|
|
||||||
*/
|
*/
|
||||||
async makeMasterKey(
|
async makeMasterKey(
|
||||||
password: string,
|
password: string,
|
||||||
@@ -320,6 +321,10 @@ export class CryptoService implements CryptoServiceAbstraction {
|
|||||||
)) as MasterKey;
|
)) as MasterKey;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async clearMasterKey(userId?: UserId): Promise<void> {
|
||||||
|
await this.stateService.setMasterKey(null, { userId: userId });
|
||||||
|
}
|
||||||
|
|
||||||
async encryptUserKeyWithMasterKey(
|
async encryptUserKeyWithMasterKey(
|
||||||
masterKey: MasterKey,
|
masterKey: MasterKey,
|
||||||
userKey?: UserKey,
|
userKey?: UserKey,
|
||||||
@@ -328,31 +333,32 @@ export class CryptoService implements CryptoServiceAbstraction {
|
|||||||
return await this.buildProtectedSymmetricKey(masterKey, userKey.key);
|
return await this.buildProtectedSymmetricKey(masterKey, userKey.key);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: move to master password service
|
|
||||||
async decryptUserKeyWithMasterKey(
|
async decryptUserKeyWithMasterKey(
|
||||||
masterKey: MasterKey,
|
masterKey: MasterKey,
|
||||||
userKey?: EncString,
|
userKey?: EncString,
|
||||||
userId?: UserId,
|
userId?: UserId,
|
||||||
): Promise<UserKey> {
|
): Promise<UserKey> {
|
||||||
userId ??= await firstValueFrom(this.stateProvider.activeUserId$);
|
masterKey ||= await this.getMasterKey(userId);
|
||||||
masterKey ??= await firstValueFrom(this.masterPasswordService.masterKey$(userId));
|
|
||||||
if (masterKey == null) {
|
if (masterKey == null) {
|
||||||
throw new Error("No master key found.");
|
throw new Error("No master key found.");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (userKey == null) {
|
if (!userKey) {
|
||||||
let userKey = await this.masterPasswordService.getMasterKeyEncryptedUserKey(userId);
|
let masterKeyEncryptedUserKey = await this.stateService.getMasterKeyEncryptedUserKey({
|
||||||
|
userId: userId,
|
||||||
|
});
|
||||||
|
|
||||||
// Try one more way to get the user key if it still wasn't found.
|
// Try one more way to get the user key if it still wasn't found.
|
||||||
if (userKey == null) {
|
if (masterKeyEncryptedUserKey == null) {
|
||||||
const deprecatedKey = await this.stateService.getEncryptedCryptoSymmetricKey({
|
masterKeyEncryptedUserKey = await this.stateService.getEncryptedCryptoSymmetricKey({
|
||||||
userId: userId,
|
userId: userId,
|
||||||
});
|
});
|
||||||
if (deprecatedKey == null) {
|
|
||||||
throw new Error("No encrypted user key found.");
|
|
||||||
}
|
|
||||||
userKey = new EncString(deprecatedKey);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (masterKeyEncryptedUserKey == null) {
|
||||||
|
throw new Error("No encrypted user key found.");
|
||||||
|
}
|
||||||
|
userKey = new EncString(masterKeyEncryptedUserKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
let decUserKey: Uint8Array;
|
let decUserKey: Uint8Array;
|
||||||
@@ -371,16 +377,12 @@ export class CryptoService implements CryptoServiceAbstraction {
|
|||||||
return new SymmetricCryptoKey(decUserKey) as UserKey;
|
return new SymmetricCryptoKey(decUserKey) as UserKey;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: move to MasterPasswordService
|
|
||||||
async hashMasterKey(
|
async hashMasterKey(
|
||||||
password: string,
|
password: string,
|
||||||
key: MasterKey,
|
key: MasterKey,
|
||||||
hashPurpose?: HashPurpose,
|
hashPurpose?: HashPurpose,
|
||||||
): Promise<string> {
|
): Promise<string> {
|
||||||
if (!key) {
|
key ||= await this.getMasterKey();
|
||||||
const userId = await firstValueFrom(this.stateProvider.activeUserId$);
|
|
||||||
key = await firstValueFrom(this.masterPasswordService.masterKey$(userId));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (password == null || key == null) {
|
if (password == null || key == null) {
|
||||||
throw new Error("Invalid parameters.");
|
throw new Error("Invalid parameters.");
|
||||||
@@ -391,12 +393,20 @@ export class CryptoService implements CryptoServiceAbstraction {
|
|||||||
return Utils.fromBufferToB64(hash);
|
return Utils.fromBufferToB64(hash);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: move to MasterPasswordService
|
async setMasterKeyHash(keyHash: string): Promise<void> {
|
||||||
|
await this.stateService.setKeyHash(keyHash);
|
||||||
|
}
|
||||||
|
|
||||||
|
async getMasterKeyHash(): Promise<string> {
|
||||||
|
return await this.stateService.getKeyHash();
|
||||||
|
}
|
||||||
|
|
||||||
|
async clearMasterKeyHash(userId?: UserId): Promise<void> {
|
||||||
|
return await this.stateService.setKeyHash(null, { userId: userId });
|
||||||
|
}
|
||||||
|
|
||||||
async compareAndUpdateKeyHash(masterPassword: string, masterKey: MasterKey): Promise<boolean> {
|
async compareAndUpdateKeyHash(masterPassword: string, masterKey: MasterKey): Promise<boolean> {
|
||||||
const userId = await firstValueFrom(this.stateProvider.activeUserId$);
|
const storedPasswordHash = await this.getMasterKeyHash();
|
||||||
const storedPasswordHash = await firstValueFrom(
|
|
||||||
this.masterPasswordService.masterKeyHash$(userId),
|
|
||||||
);
|
|
||||||
if (masterPassword != null && storedPasswordHash != null) {
|
if (masterPassword != null && storedPasswordHash != null) {
|
||||||
const localKeyHash = await this.hashMasterKey(
|
const localKeyHash = await this.hashMasterKey(
|
||||||
masterPassword,
|
masterPassword,
|
||||||
@@ -414,7 +424,7 @@ export class CryptoService implements CryptoServiceAbstraction {
|
|||||||
HashPurpose.ServerAuthorization,
|
HashPurpose.ServerAuthorization,
|
||||||
);
|
);
|
||||||
if (serverKeyHash != null && storedPasswordHash === serverKeyHash) {
|
if (serverKeyHash != null && storedPasswordHash === serverKeyHash) {
|
||||||
await this.masterPasswordService.setMasterKeyHash(localKeyHash, userId);
|
await this.setMasterKeyHash(localKeyHash);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -471,7 +481,7 @@ export class CryptoService implements CryptoServiceAbstraction {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async clearOrgKeys(memoryOnly?: boolean, userId?: UserId): Promise<void> {
|
async clearOrgKeys(memoryOnly?: boolean, userId?: UserId): Promise<void> {
|
||||||
const activeUserId = await firstValueFrom(this.stateProvider.activeUserId$);
|
const activeUserId = (await firstValueFrom(this.accountService.activeAccount$))?.id;
|
||||||
const userIdIsActive = userId == null || userId === activeUserId;
|
const userIdIsActive = userId == null || userId === activeUserId;
|
||||||
|
|
||||||
if (!memoryOnly) {
|
if (!memoryOnly) {
|
||||||
@@ -517,7 +527,7 @@ export class CryptoService implements CryptoServiceAbstraction {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async clearProviderKeys(memoryOnly?: boolean, userId?: UserId): Promise<void> {
|
async clearProviderKeys(memoryOnly?: boolean, userId?: UserId): Promise<void> {
|
||||||
const activeUserId = await firstValueFrom(this.stateProvider.activeUserId$);
|
const activeUserId = (await firstValueFrom(this.accountService.activeAccount$))?.id;
|
||||||
const userIdIsActive = userId == null || userId === activeUserId;
|
const userIdIsActive = userId == null || userId === activeUserId;
|
||||||
|
|
||||||
if (!memoryOnly) {
|
if (!memoryOnly) {
|
||||||
@@ -588,7 +598,7 @@ export class CryptoService implements CryptoServiceAbstraction {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async clearKeyPair(memoryOnly?: boolean, userId?: UserId): Promise<void[]> {
|
async clearKeyPair(memoryOnly?: boolean, userId?: UserId): Promise<void[]> {
|
||||||
const activeUserId = await firstValueFrom(this.stateProvider.activeUserId$);
|
const activeUserId = (await firstValueFrom(this.accountService.activeAccount$))?.id;
|
||||||
const userIdIsActive = userId == null || userId === activeUserId;
|
const userIdIsActive = userId == null || userId === activeUserId;
|
||||||
|
|
||||||
if (!memoryOnly) {
|
if (!memoryOnly) {
|
||||||
@@ -671,10 +681,8 @@ export class CryptoService implements CryptoServiceAbstraction {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async clearKeys(userId?: UserId): Promise<any> {
|
async clearKeys(userId?: UserId): Promise<any> {
|
||||||
userId ??= await firstValueFrom(this.stateProvider.activeUserId$);
|
|
||||||
await this.masterPasswordService.setMasterKeyHash(null, userId);
|
|
||||||
|
|
||||||
await this.clearUserKey(true, userId);
|
await this.clearUserKey(true, userId);
|
||||||
|
await this.clearMasterKeyHash(userId);
|
||||||
await this.clearOrgKeys(false, userId);
|
await this.clearOrgKeys(false, userId);
|
||||||
await this.clearProviderKeys(false, userId);
|
await this.clearProviderKeys(false, userId);
|
||||||
await this.clearKeyPair(false, userId);
|
await this.clearKeyPair(false, userId);
|
||||||
@@ -1029,8 +1037,7 @@ export class CryptoService implements CryptoServiceAbstraction {
|
|||||||
if (await this.isLegacyUser(masterKey, userId)) {
|
if (await this.isLegacyUser(masterKey, userId)) {
|
||||||
// Legacy users don't have a user key, so no need to migrate.
|
// Legacy users don't have a user key, so no need to migrate.
|
||||||
// Instead, set the master key for additional isLegacyUser checks that will log the user out.
|
// Instead, set the master key for additional isLegacyUser checks that will log the user out.
|
||||||
userId ??= await firstValueFrom(this.stateProvider.activeUserId$);
|
await this.setMasterKey(masterKey, userId);
|
||||||
await this.masterPasswordService.setMasterKey(masterKey, userId);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const encryptedUserKey = await this.stateService.getEncryptedCryptoSymmetricKey({
|
const encryptedUserKey = await this.stateService.getEncryptedCryptoSymmetricKey({
|
||||||
|
|||||||
@@ -5,12 +5,14 @@ import { AccountService } from "../../auth/abstractions/account.service";
|
|||||||
import { TokenService } from "../../auth/abstractions/token.service";
|
import { TokenService } from "../../auth/abstractions/token.service";
|
||||||
import { AuthenticationStatus } from "../../auth/enums/authentication-status";
|
import { AuthenticationStatus } from "../../auth/enums/authentication-status";
|
||||||
import { AdminAuthRequestStorable } from "../../auth/models/domain/admin-auth-req-storable";
|
import { AdminAuthRequestStorable } from "../../auth/models/domain/admin-auth-req-storable";
|
||||||
|
import { ForceSetPasswordReason } from "../../auth/models/domain/force-set-password-reason";
|
||||||
import { KdfConfig } from "../../auth/models/domain/kdf-config";
|
import { KdfConfig } from "../../auth/models/domain/kdf-config";
|
||||||
import { BiometricKey } from "../../auth/types/biometric-key";
|
import { BiometricKey } from "../../auth/types/biometric-key";
|
||||||
import { GeneratorOptions } from "../../tools/generator/generator-options";
|
import { GeneratorOptions } from "../../tools/generator/generator-options";
|
||||||
import { GeneratedPasswordHistory, PasswordGeneratorOptions } from "../../tools/generator/password";
|
import { GeneratedPasswordHistory, PasswordGeneratorOptions } from "../../tools/generator/password";
|
||||||
import { UsernameGeneratorOptions } from "../../tools/generator/username";
|
import { UsernameGeneratorOptions } from "../../tools/generator/username";
|
||||||
import { UserId } from "../../types/guid";
|
import { UserId } from "../../types/guid";
|
||||||
|
import { MasterKey } from "../../types/key";
|
||||||
import { CipherData } from "../../vault/models/data/cipher.data";
|
import { CipherData } from "../../vault/models/data/cipher.data";
|
||||||
import { LocalData } from "../../vault/models/data/local.data";
|
import { LocalData } from "../../vault/models/data/local.data";
|
||||||
import { CipherView } from "../../vault/models/view/cipher.view";
|
import { CipherView } from "../../vault/models/view/cipher.view";
|
||||||
@@ -33,6 +35,7 @@ import { EncString } from "../models/domain/enc-string";
|
|||||||
import { GlobalState } from "../models/domain/global-state";
|
import { GlobalState } from "../models/domain/global-state";
|
||||||
import { State } from "../models/domain/state";
|
import { State } from "../models/domain/state";
|
||||||
import { StorageOptions } from "../models/domain/storage-options";
|
import { StorageOptions } from "../models/domain/storage-options";
|
||||||
|
import { SymmetricCryptoKey } from "../models/domain/symmetric-crypto-key";
|
||||||
|
|
||||||
import { MigrationRunner } from "./migration-runner";
|
import { MigrationRunner } from "./migration-runner";
|
||||||
|
|
||||||
@@ -270,6 +273,65 @@ export class StateService<
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated Do not save the Master Key. Use the User Symmetric Key instead
|
||||||
|
*/
|
||||||
|
async getCryptoMasterKey(options?: StorageOptions): Promise<SymmetricCryptoKey> {
|
||||||
|
const account = await this.getAccount(
|
||||||
|
this.reconcileOptions(options, await this.defaultInMemoryOptions()),
|
||||||
|
);
|
||||||
|
return account?.keys?.cryptoMasterKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* User's master key derived from MP, saved only if we decrypted with MP
|
||||||
|
*/
|
||||||
|
async getMasterKey(options?: StorageOptions): Promise<MasterKey> {
|
||||||
|
const account = await this.getAccount(
|
||||||
|
this.reconcileOptions(options, await this.defaultInMemoryOptions()),
|
||||||
|
);
|
||||||
|
return account?.keys?.masterKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* User's master key derived from MP, saved only if we decrypted with MP
|
||||||
|
*/
|
||||||
|
async setMasterKey(value: MasterKey, options?: StorageOptions): Promise<void> {
|
||||||
|
const account = await this.getAccount(
|
||||||
|
this.reconcileOptions(options, await this.defaultInMemoryOptions()),
|
||||||
|
);
|
||||||
|
account.keys.masterKey = value;
|
||||||
|
await this.saveAccount(
|
||||||
|
account,
|
||||||
|
this.reconcileOptions(options, await this.defaultInMemoryOptions()),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The master key encrypted User symmetric key, saved on every auth
|
||||||
|
* so we can unlock with MP offline
|
||||||
|
*/
|
||||||
|
async getMasterKeyEncryptedUserKey(options?: StorageOptions): Promise<string> {
|
||||||
|
return (
|
||||||
|
await this.getAccount(this.reconcileOptions(options, await this.defaultOnDiskOptions()))
|
||||||
|
)?.keys.masterKeyEncryptedUserKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The master key encrypted User symmetric key, saved on every auth
|
||||||
|
* so we can unlock with MP offline
|
||||||
|
*/
|
||||||
|
async setMasterKeyEncryptedUserKey(value: string, options?: StorageOptions): Promise<void> {
|
||||||
|
const account = await this.getAccount(
|
||||||
|
this.reconcileOptions(options, await this.defaultOnDiskOptions()),
|
||||||
|
);
|
||||||
|
account.keys.masterKeyEncryptedUserKey = value;
|
||||||
|
await this.saveAccount(
|
||||||
|
account,
|
||||||
|
this.reconcileOptions(options, await this.defaultOnDiskOptions()),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* user key when using the "never" option of vault timeout
|
* user key when using the "never" option of vault timeout
|
||||||
*/
|
*/
|
||||||
@@ -761,6 +823,30 @@ export class StateService<
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async getForceSetPasswordReason(options?: StorageOptions): Promise<ForceSetPasswordReason> {
|
||||||
|
return (
|
||||||
|
(
|
||||||
|
await this.getAccount(
|
||||||
|
this.reconcileOptions(options, await this.defaultOnDiskMemoryOptions()),
|
||||||
|
)
|
||||||
|
)?.profile?.forceSetPasswordReason ?? ForceSetPasswordReason.None
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
async setForceSetPasswordReason(
|
||||||
|
value: ForceSetPasswordReason,
|
||||||
|
options?: StorageOptions,
|
||||||
|
): Promise<void> {
|
||||||
|
const account = await this.getAccount(
|
||||||
|
this.reconcileOptions(options, await this.defaultOnDiskMemoryOptions()),
|
||||||
|
);
|
||||||
|
account.profile.forceSetPasswordReason = value;
|
||||||
|
await this.saveAccount(
|
||||||
|
account,
|
||||||
|
this.reconcileOptions(options, await this.defaultOnDiskMemoryOptions()),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
async getIsAuthenticated(options?: StorageOptions): Promise<boolean> {
|
async getIsAuthenticated(options?: StorageOptions): Promise<boolean> {
|
||||||
return (
|
return (
|
||||||
(await this.tokenService.getAccessToken(options?.userId as UserId)) != null &&
|
(await this.tokenService.getAccessToken(options?.userId as UserId)) != null &&
|
||||||
@@ -811,6 +897,23 @@ export class StateService<
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async getKeyHash(options?: StorageOptions): Promise<string> {
|
||||||
|
return (
|
||||||
|
await this.getAccount(this.reconcileOptions(options, await this.defaultOnDiskOptions()))
|
||||||
|
)?.profile?.keyHash;
|
||||||
|
}
|
||||||
|
|
||||||
|
async setKeyHash(value: string, options?: StorageOptions): Promise<void> {
|
||||||
|
const account = await this.getAccount(
|
||||||
|
this.reconcileOptions(options, await this.defaultOnDiskOptions()),
|
||||||
|
);
|
||||||
|
account.profile.keyHash = value;
|
||||||
|
await this.saveAccount(
|
||||||
|
account,
|
||||||
|
this.reconcileOptions(options, await this.defaultOnDiskOptions()),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
async getLastActive(options?: StorageOptions): Promise<number> {
|
async getLastActive(options?: StorageOptions): Promise<number> {
|
||||||
options = this.reconcileOptions(options, await this.defaultOnDiskOptions());
|
options = this.reconcileOptions(options, await this.defaultOnDiskOptions());
|
||||||
|
|
||||||
|
|||||||
@@ -37,8 +37,6 @@ export const BILLING_DISK = new StateDefinition("billing", "disk");
|
|||||||
|
|
||||||
export const KEY_CONNECTOR_DISK = new StateDefinition("keyConnector", "disk");
|
export const KEY_CONNECTOR_DISK = new StateDefinition("keyConnector", "disk");
|
||||||
export const ACCOUNT_MEMORY = new StateDefinition("account", "memory");
|
export const ACCOUNT_MEMORY = new StateDefinition("account", "memory");
|
||||||
export const MASTER_PASSWORD_MEMORY = new StateDefinition("masterPassword", "memory");
|
|
||||||
export const MASTER_PASSWORD_DISK = new StateDefinition("masterPassword", "disk");
|
|
||||||
export const AVATAR_DISK = new StateDefinition("avatar", "disk", { web: "disk-local" });
|
export const AVATAR_DISK = new StateDefinition("avatar", "disk", { web: "disk-local" });
|
||||||
export const ROUTER_DISK = new StateDefinition("router", "disk");
|
export const ROUTER_DISK = new StateDefinition("router", "disk");
|
||||||
export const LOGIN_EMAIL_DISK = new StateDefinition("loginEmail", "disk", {
|
export const LOGIN_EMAIL_DISK = new StateDefinition("loginEmail", "disk", {
|
||||||
|
|||||||
@@ -1,21 +1,17 @@
|
|||||||
import { MockProxy, any, mock } from "jest-mock-extended";
|
import { MockProxy, any, mock } from "jest-mock-extended";
|
||||||
import { BehaviorSubject } from "rxjs";
|
import { BehaviorSubject } from "rxjs";
|
||||||
|
|
||||||
import { FakeAccountService, mockAccountServiceWith } from "../../../spec/fake-account-service";
|
|
||||||
import { SearchService } from "../../abstractions/search.service";
|
import { SearchService } from "../../abstractions/search.service";
|
||||||
import { VaultTimeoutSettingsService } from "../../abstractions/vault-timeout/vault-timeout-settings.service";
|
import { VaultTimeoutSettingsService } from "../../abstractions/vault-timeout/vault-timeout-settings.service";
|
||||||
import { AuthService } from "../../auth/abstractions/auth.service";
|
import { AuthService } from "../../auth/abstractions/auth.service";
|
||||||
import { AuthenticationStatus } from "../../auth/enums/authentication-status";
|
import { AuthenticationStatus } from "../../auth/enums/authentication-status";
|
||||||
import { FakeMasterPasswordService } from "../../auth/services/master-password/fake-master-password.service";
|
|
||||||
import { VaultTimeoutAction } from "../../enums/vault-timeout-action.enum";
|
import { VaultTimeoutAction } from "../../enums/vault-timeout-action.enum";
|
||||||
import { CryptoService } from "../../platform/abstractions/crypto.service";
|
import { CryptoService } from "../../platform/abstractions/crypto.service";
|
||||||
import { MessagingService } from "../../platform/abstractions/messaging.service";
|
import { MessagingService } from "../../platform/abstractions/messaging.service";
|
||||||
import { PlatformUtilsService } from "../../platform/abstractions/platform-utils.service";
|
import { PlatformUtilsService } from "../../platform/abstractions/platform-utils.service";
|
||||||
import { StateService } from "../../platform/abstractions/state.service";
|
import { StateService } from "../../platform/abstractions/state.service";
|
||||||
import { Utils } from "../../platform/misc/utils";
|
|
||||||
import { Account } from "../../platform/models/domain/account";
|
import { Account } from "../../platform/models/domain/account";
|
||||||
import { StateEventRunnerService } from "../../platform/state";
|
import { StateEventRunnerService } from "../../platform/state";
|
||||||
import { UserId } from "../../types/guid";
|
|
||||||
import { CipherService } from "../../vault/abstractions/cipher.service";
|
import { CipherService } from "../../vault/abstractions/cipher.service";
|
||||||
import { CollectionService } from "../../vault/abstractions/collection.service";
|
import { CollectionService } from "../../vault/abstractions/collection.service";
|
||||||
import { FolderService } from "../../vault/abstractions/folder/folder.service.abstraction";
|
import { FolderService } from "../../vault/abstractions/folder/folder.service.abstraction";
|
||||||
@@ -23,8 +19,6 @@ import { FolderService } from "../../vault/abstractions/folder/folder.service.ab
|
|||||||
import { VaultTimeoutService } from "./vault-timeout.service";
|
import { VaultTimeoutService } from "./vault-timeout.service";
|
||||||
|
|
||||||
describe("VaultTimeoutService", () => {
|
describe("VaultTimeoutService", () => {
|
||||||
let accountService: FakeAccountService;
|
|
||||||
let masterPasswordService: FakeMasterPasswordService;
|
|
||||||
let cipherService: MockProxy<CipherService>;
|
let cipherService: MockProxy<CipherService>;
|
||||||
let folderService: MockProxy<FolderService>;
|
let folderService: MockProxy<FolderService>;
|
||||||
let collectionService: MockProxy<CollectionService>;
|
let collectionService: MockProxy<CollectionService>;
|
||||||
@@ -45,11 +39,7 @@ describe("VaultTimeoutService", () => {
|
|||||||
|
|
||||||
let vaultTimeoutService: VaultTimeoutService;
|
let vaultTimeoutService: VaultTimeoutService;
|
||||||
|
|
||||||
const userId = Utils.newGuid() as UserId;
|
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
accountService = mockAccountServiceWith(userId);
|
|
||||||
masterPasswordService = new FakeMasterPasswordService();
|
|
||||||
cipherService = mock();
|
cipherService = mock();
|
||||||
folderService = mock();
|
folderService = mock();
|
||||||
collectionService = mock();
|
collectionService = mock();
|
||||||
@@ -76,8 +66,6 @@ describe("VaultTimeoutService", () => {
|
|||||||
availableVaultTimeoutActionsSubject = new BehaviorSubject<VaultTimeoutAction[]>([]);
|
availableVaultTimeoutActionsSubject = new BehaviorSubject<VaultTimeoutAction[]>([]);
|
||||||
|
|
||||||
vaultTimeoutService = new VaultTimeoutService(
|
vaultTimeoutService = new VaultTimeoutService(
|
||||||
accountService,
|
|
||||||
masterPasswordService,
|
|
||||||
cipherService,
|
cipherService,
|
||||||
folderService,
|
folderService,
|
||||||
collectionService,
|
collectionService,
|
||||||
@@ -135,15 +123,6 @@ describe("VaultTimeoutService", () => {
|
|||||||
|
|
||||||
stateService.activeAccount$ = new BehaviorSubject<string>(globalSetups?.userId);
|
stateService.activeAccount$ = new BehaviorSubject<string>(globalSetups?.userId);
|
||||||
|
|
||||||
if (globalSetups?.userId) {
|
|
||||||
accountService.activeAccountSubject.next({
|
|
||||||
id: globalSetups.userId as UserId,
|
|
||||||
status: accounts[globalSetups.userId]?.authStatus,
|
|
||||||
email: null,
|
|
||||||
name: null,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
platformUtilsService.isViewOpen.mockResolvedValue(globalSetups?.isViewOpen ?? false);
|
platformUtilsService.isViewOpen.mockResolvedValue(globalSetups?.isViewOpen ?? false);
|
||||||
|
|
||||||
vaultTimeoutSettingsService.vaultTimeoutAction$.mockImplementation((userId) => {
|
vaultTimeoutSettingsService.vaultTimeoutAction$.mockImplementation((userId) => {
|
||||||
@@ -177,8 +156,8 @@ describe("VaultTimeoutService", () => {
|
|||||||
expect(vaultTimeoutSettingsService.availableVaultTimeoutActions$).toHaveBeenCalledWith(userId);
|
expect(vaultTimeoutSettingsService.availableVaultTimeoutActions$).toHaveBeenCalledWith(userId);
|
||||||
expect(stateService.setEverBeenUnlocked).toHaveBeenCalledWith(true, { userId: userId });
|
expect(stateService.setEverBeenUnlocked).toHaveBeenCalledWith(true, { userId: userId });
|
||||||
expect(stateService.setUserKeyAutoUnlock).toHaveBeenCalledWith(null, { userId: userId });
|
expect(stateService.setUserKeyAutoUnlock).toHaveBeenCalledWith(null, { userId: userId });
|
||||||
expect(masterPasswordService.mock.setMasterKey).toHaveBeenCalledWith(null, userId);
|
|
||||||
expect(cryptoService.clearUserKey).toHaveBeenCalledWith(false, userId);
|
expect(cryptoService.clearUserKey).toHaveBeenCalledWith(false, userId);
|
||||||
|
expect(cryptoService.clearMasterKey).toHaveBeenCalledWith(userId);
|
||||||
expect(cipherService.clearCache).toHaveBeenCalledWith(userId);
|
expect(cipherService.clearCache).toHaveBeenCalledWith(userId);
|
||||||
expect(lockedCallback).toHaveBeenCalledWith(userId);
|
expect(lockedCallback).toHaveBeenCalledWith(userId);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -3,9 +3,7 @@ import { firstValueFrom, timeout } from "rxjs";
|
|||||||
import { SearchService } from "../../abstractions/search.service";
|
import { SearchService } from "../../abstractions/search.service";
|
||||||
import { VaultTimeoutSettingsService } from "../../abstractions/vault-timeout/vault-timeout-settings.service";
|
import { VaultTimeoutSettingsService } from "../../abstractions/vault-timeout/vault-timeout-settings.service";
|
||||||
import { VaultTimeoutService as VaultTimeoutServiceAbstraction } from "../../abstractions/vault-timeout/vault-timeout.service";
|
import { VaultTimeoutService as VaultTimeoutServiceAbstraction } from "../../abstractions/vault-timeout/vault-timeout.service";
|
||||||
import { AccountService } from "../../auth/abstractions/account.service";
|
|
||||||
import { AuthService } from "../../auth/abstractions/auth.service";
|
import { AuthService } from "../../auth/abstractions/auth.service";
|
||||||
import { InternalMasterPasswordServiceAbstraction } from "../../auth/abstractions/master-password.service.abstraction";
|
|
||||||
import { AuthenticationStatus } from "../../auth/enums/authentication-status";
|
import { AuthenticationStatus } from "../../auth/enums/authentication-status";
|
||||||
import { ClientType } from "../../enums";
|
import { ClientType } from "../../enums";
|
||||||
import { VaultTimeoutAction } from "../../enums/vault-timeout-action.enum";
|
import { VaultTimeoutAction } from "../../enums/vault-timeout-action.enum";
|
||||||
@@ -23,8 +21,6 @@ export class VaultTimeoutService implements VaultTimeoutServiceAbstraction {
|
|||||||
private inited = false;
|
private inited = false;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private accountService: AccountService,
|
|
||||||
private masterPasswordService: InternalMasterPasswordServiceAbstraction,
|
|
||||||
private cipherService: CipherService,
|
private cipherService: CipherService,
|
||||||
private folderService: FolderService,
|
private folderService: FolderService,
|
||||||
private collectionService: CollectionService,
|
private collectionService: CollectionService,
|
||||||
@@ -88,7 +84,7 @@ export class VaultTimeoutService implements VaultTimeoutServiceAbstraction {
|
|||||||
await this.logOut(userId);
|
await this.logOut(userId);
|
||||||
}
|
}
|
||||||
|
|
||||||
const currentUserId = (await firstValueFrom(this.accountService.activeAccount$)).id;
|
const currentUserId = await this.stateService.getUserId();
|
||||||
|
|
||||||
if (userId == null || userId === currentUserId) {
|
if (userId == null || userId === currentUserId) {
|
||||||
this.searchService.clearIndex();
|
this.searchService.clearIndex();
|
||||||
@@ -96,13 +92,12 @@ export class VaultTimeoutService implements VaultTimeoutServiceAbstraction {
|
|||||||
await this.collectionService.clearActiveUserCache();
|
await this.collectionService.clearActiveUserCache();
|
||||||
}
|
}
|
||||||
|
|
||||||
await this.masterPasswordService.setMasterKey(null, (userId ?? currentUserId) as UserId);
|
|
||||||
|
|
||||||
await this.stateService.setEverBeenUnlocked(true, { userId: userId });
|
await this.stateService.setEverBeenUnlocked(true, { userId: userId });
|
||||||
await this.stateService.setUserKeyAutoUnlock(null, { userId: userId });
|
await this.stateService.setUserKeyAutoUnlock(null, { userId: userId });
|
||||||
await this.stateService.setCryptoMasterKeyAuto(null, { userId: userId });
|
await this.stateService.setCryptoMasterKeyAuto(null, { userId: userId });
|
||||||
|
|
||||||
await this.cryptoService.clearUserKey(false, userId);
|
await this.cryptoService.clearUserKey(false, userId);
|
||||||
|
await this.cryptoService.clearMasterKey(userId);
|
||||||
await this.cryptoService.clearOrgKeys(true, userId);
|
await this.cryptoService.clearOrgKeys(true, userId);
|
||||||
await this.cryptoService.clearKeyPair(true, userId);
|
await this.cryptoService.clearKeyPair(true, userId);
|
||||||
|
|
||||||
|
|||||||
@@ -51,7 +51,6 @@ import { RememberedEmailMigrator } from "./migrations/51-move-remembered-email-t
|
|||||||
import { DeleteInstalledVersion } from "./migrations/52-delete-installed-version";
|
import { DeleteInstalledVersion } from "./migrations/52-delete-installed-version";
|
||||||
import { DeviceTrustCryptoServiceStateProviderMigrator } from "./migrations/53-migrate-device-trust-crypto-svc-to-state-providers";
|
import { DeviceTrustCryptoServiceStateProviderMigrator } from "./migrations/53-migrate-device-trust-crypto-svc-to-state-providers";
|
||||||
import { SendMigrator } from "./migrations/54-move-encrypted-sends";
|
import { SendMigrator } from "./migrations/54-move-encrypted-sends";
|
||||||
import { MoveMasterKeyStateToProviderMigrator } from "./migrations/55-move-master-key-state-to-provider";
|
|
||||||
import { RemoveLegacyEtmKeyMigrator } from "./migrations/6-remove-legacy-etm-key";
|
import { RemoveLegacyEtmKeyMigrator } from "./migrations/6-remove-legacy-etm-key";
|
||||||
import { MoveBiometricAutoPromptToAccount } from "./migrations/7-move-biometric-auto-prompt-to-account";
|
import { MoveBiometricAutoPromptToAccount } from "./migrations/7-move-biometric-auto-prompt-to-account";
|
||||||
import { MoveStateVersionMigrator } from "./migrations/8-move-state-version";
|
import { MoveStateVersionMigrator } from "./migrations/8-move-state-version";
|
||||||
@@ -59,7 +58,7 @@ import { MoveBrowserSettingsToGlobal } from "./migrations/9-move-browser-setting
|
|||||||
import { MinVersionMigrator } from "./migrations/min-version";
|
import { MinVersionMigrator } from "./migrations/min-version";
|
||||||
|
|
||||||
export const MIN_VERSION = 3;
|
export const MIN_VERSION = 3;
|
||||||
export const CURRENT_VERSION = 55;
|
export const CURRENT_VERSION = 54;
|
||||||
|
|
||||||
export type MinVersion = typeof MIN_VERSION;
|
export type MinVersion = typeof MIN_VERSION;
|
||||||
|
|
||||||
@@ -116,8 +115,7 @@ export function createMigrationBuilder() {
|
|||||||
.with(RememberedEmailMigrator, 50, 51)
|
.with(RememberedEmailMigrator, 50, 51)
|
||||||
.with(DeleteInstalledVersion, 51, 52)
|
.with(DeleteInstalledVersion, 51, 52)
|
||||||
.with(DeviceTrustCryptoServiceStateProviderMigrator, 52, 53)
|
.with(DeviceTrustCryptoServiceStateProviderMigrator, 52, 53)
|
||||||
.with(SendMigrator, 53, 54)
|
.with(SendMigrator, 53, 54);
|
||||||
.with(MoveMasterKeyStateToProviderMigrator, 54, CURRENT_VERSION);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function currentVersion(
|
export async function currentVersion(
|
||||||
|
|||||||
@@ -1,210 +0,0 @@
|
|||||||
import { any, MockProxy } from "jest-mock-extended";
|
|
||||||
|
|
||||||
import { MigrationHelper } from "../migration-helper";
|
|
||||||
import { mockMigrationHelper } from "../migration-helper.spec";
|
|
||||||
|
|
||||||
import {
|
|
||||||
FORCE_SET_PASSWORD_REASON_DEFINITION,
|
|
||||||
MASTER_KEY_ENCRYPTED_USER_KEY_DEFINITION,
|
|
||||||
MASTER_KEY_HASH_DEFINITION,
|
|
||||||
MoveMasterKeyStateToProviderMigrator,
|
|
||||||
} from "./55-move-master-key-state-to-provider";
|
|
||||||
|
|
||||||
function preMigrationState() {
|
|
||||||
return {
|
|
||||||
global: {
|
|
||||||
otherStuff: "otherStuff1",
|
|
||||||
},
|
|
||||||
authenticatedAccounts: ["FirstAccount", "SecondAccount", "ThirdAccount"],
|
|
||||||
// prettier-ignore
|
|
||||||
"FirstAccount": {
|
|
||||||
profile: {
|
|
||||||
forceSetPasswordReason: "FirstAccount_forceSetPasswordReason",
|
|
||||||
keyHash: "FirstAccount_keyHash",
|
|
||||||
otherStuff: "overStuff2",
|
|
||||||
},
|
|
||||||
keys: {
|
|
||||||
masterKeyEncryptedUserKey: "FirstAccount_masterKeyEncryptedUserKey",
|
|
||||||
},
|
|
||||||
otherStuff: "otherStuff3",
|
|
||||||
},
|
|
||||||
// prettier-ignore
|
|
||||||
"SecondAccount": {
|
|
||||||
profile: {
|
|
||||||
forceSetPasswordReason: "SecondAccount_forceSetPasswordReason",
|
|
||||||
keyHash: "SecondAccount_keyHash",
|
|
||||||
otherStuff: "otherStuff4",
|
|
||||||
},
|
|
||||||
keys: {
|
|
||||||
masterKeyEncryptedUserKey: "SecondAccount_masterKeyEncryptedUserKey",
|
|
||||||
},
|
|
||||||
otherStuff: "otherStuff5",
|
|
||||||
},
|
|
||||||
// prettier-ignore
|
|
||||||
"ThirdAccount": {
|
|
||||||
profile: {
|
|
||||||
otherStuff: "otherStuff6",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function postMigrationState() {
|
|
||||||
return {
|
|
||||||
user_FirstAccount_masterPassword_forceSetPasswordReason: "FirstAccount_forceSetPasswordReason",
|
|
||||||
user_FirstAccount_masterPassword_masterKeyHash: "FirstAccount_keyHash",
|
|
||||||
user_FirstAccount_masterPassword_masterKeyEncryptedUserKey:
|
|
||||||
"FirstAccount_masterKeyEncryptedUserKey",
|
|
||||||
user_SecondAccount_masterPassword_forceSetPasswordReason:
|
|
||||||
"SecondAccount_forceSetPasswordReason",
|
|
||||||
user_SecondAccount_masterPassword_masterKeyHash: "SecondAccount_keyHash",
|
|
||||||
user_SecondAccount_masterPassword_masterKeyEncryptedUserKey:
|
|
||||||
"SecondAccount_masterKeyEncryptedUserKey",
|
|
||||||
global: {
|
|
||||||
otherStuff: "otherStuff1",
|
|
||||||
},
|
|
||||||
authenticatedAccounts: ["FirstAccount", "SecondAccount"],
|
|
||||||
// prettier-ignore
|
|
||||||
"FirstAccount": {
|
|
||||||
profile: {
|
|
||||||
otherStuff: "overStuff2",
|
|
||||||
},
|
|
||||||
otherStuff: "otherStuff3",
|
|
||||||
},
|
|
||||||
// prettier-ignore
|
|
||||||
"SecondAccount": {
|
|
||||||
profile: {
|
|
||||||
otherStuff: "otherStuff4",
|
|
||||||
},
|
|
||||||
otherStuff: "otherStuff5",
|
|
||||||
},
|
|
||||||
// prettier-ignore
|
|
||||||
"ThirdAccount": {
|
|
||||||
profile: {
|
|
||||||
otherStuff: "otherStuff6",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
describe("MoveForceSetPasswordReasonToStateProviderMigrator", () => {
|
|
||||||
let helper: MockProxy<MigrationHelper>;
|
|
||||||
let sut: MoveMasterKeyStateToProviderMigrator;
|
|
||||||
|
|
||||||
describe("migrate", () => {
|
|
||||||
beforeEach(() => {
|
|
||||||
helper = mockMigrationHelper(preMigrationState(), 54);
|
|
||||||
sut = new MoveMasterKeyStateToProviderMigrator(54, 55);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should remove properties from existing accounts", async () => {
|
|
||||||
await sut.migrate(helper);
|
|
||||||
expect(helper.set).toHaveBeenCalledWith("FirstAccount", {
|
|
||||||
profile: {
|
|
||||||
otherStuff: "overStuff2",
|
|
||||||
},
|
|
||||||
keys: {},
|
|
||||||
otherStuff: "otherStuff3",
|
|
||||||
});
|
|
||||||
expect(helper.set).toHaveBeenCalledWith("SecondAccount", {
|
|
||||||
profile: {
|
|
||||||
otherStuff: "otherStuff4",
|
|
||||||
},
|
|
||||||
keys: {},
|
|
||||||
otherStuff: "otherStuff5",
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should set properties for each account", async () => {
|
|
||||||
await sut.migrate(helper);
|
|
||||||
|
|
||||||
expect(helper.setToUser).toHaveBeenCalledWith(
|
|
||||||
"FirstAccount",
|
|
||||||
FORCE_SET_PASSWORD_REASON_DEFINITION,
|
|
||||||
"FirstAccount_forceSetPasswordReason",
|
|
||||||
);
|
|
||||||
|
|
||||||
expect(helper.setToUser).toHaveBeenCalledWith(
|
|
||||||
"FirstAccount",
|
|
||||||
MASTER_KEY_HASH_DEFINITION,
|
|
||||||
"FirstAccount_keyHash",
|
|
||||||
);
|
|
||||||
|
|
||||||
expect(helper.setToUser).toHaveBeenCalledWith(
|
|
||||||
"FirstAccount",
|
|
||||||
MASTER_KEY_ENCRYPTED_USER_KEY_DEFINITION,
|
|
||||||
"FirstAccount_masterKeyEncryptedUserKey",
|
|
||||||
);
|
|
||||||
|
|
||||||
expect(helper.setToUser).toHaveBeenCalledWith(
|
|
||||||
"SecondAccount",
|
|
||||||
FORCE_SET_PASSWORD_REASON_DEFINITION,
|
|
||||||
"SecondAccount_forceSetPasswordReason",
|
|
||||||
);
|
|
||||||
|
|
||||||
expect(helper.setToUser).toHaveBeenCalledWith(
|
|
||||||
"SecondAccount",
|
|
||||||
MASTER_KEY_HASH_DEFINITION,
|
|
||||||
"SecondAccount_keyHash",
|
|
||||||
);
|
|
||||||
|
|
||||||
expect(helper.setToUser).toHaveBeenCalledWith(
|
|
||||||
"SecondAccount",
|
|
||||||
MASTER_KEY_ENCRYPTED_USER_KEY_DEFINITION,
|
|
||||||
"SecondAccount_masterKeyEncryptedUserKey",
|
|
||||||
);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe("rollback", () => {
|
|
||||||
beforeEach(() => {
|
|
||||||
helper = mockMigrationHelper(postMigrationState(), 55);
|
|
||||||
sut = new MoveMasterKeyStateToProviderMigrator(54, 55);
|
|
||||||
});
|
|
||||||
|
|
||||||
it.each(["FirstAccount", "SecondAccount"])("should null out new values", async (userId) => {
|
|
||||||
await sut.rollback(helper);
|
|
||||||
|
|
||||||
expect(helper.setToUser).toHaveBeenCalledWith(
|
|
||||||
userId,
|
|
||||||
FORCE_SET_PASSWORD_REASON_DEFINITION,
|
|
||||||
null,
|
|
||||||
);
|
|
||||||
|
|
||||||
expect(helper.setToUser).toHaveBeenCalledWith(userId, MASTER_KEY_HASH_DEFINITION, null);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should add explicit value back to accounts", async () => {
|
|
||||||
await sut.rollback(helper);
|
|
||||||
|
|
||||||
expect(helper.set).toHaveBeenCalledWith("FirstAccount", {
|
|
||||||
profile: {
|
|
||||||
forceSetPasswordReason: "FirstAccount_forceSetPasswordReason",
|
|
||||||
keyHash: "FirstAccount_keyHash",
|
|
||||||
otherStuff: "overStuff2",
|
|
||||||
},
|
|
||||||
keys: {
|
|
||||||
masterKeyEncryptedUserKey: "FirstAccount_masterKeyEncryptedUserKey",
|
|
||||||
},
|
|
||||||
otherStuff: "otherStuff3",
|
|
||||||
});
|
|
||||||
expect(helper.set).toHaveBeenCalledWith("SecondAccount", {
|
|
||||||
profile: {
|
|
||||||
forceSetPasswordReason: "SecondAccount_forceSetPasswordReason",
|
|
||||||
keyHash: "SecondAccount_keyHash",
|
|
||||||
otherStuff: "otherStuff4",
|
|
||||||
},
|
|
||||||
keys: {
|
|
||||||
masterKeyEncryptedUserKey: "SecondAccount_masterKeyEncryptedUserKey",
|
|
||||||
},
|
|
||||||
otherStuff: "otherStuff5",
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should not try to restore values to missing accounts", async () => {
|
|
||||||
await sut.rollback(helper);
|
|
||||||
|
|
||||||
expect(helper.set).not.toHaveBeenCalledWith("ThirdAccount", any());
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -1,111 +0,0 @@
|
|||||||
import { KeyDefinitionLike, MigrationHelper } from "../migration-helper";
|
|
||||||
import { Migrator } from "../migrator";
|
|
||||||
|
|
||||||
type ExpectedAccountType = {
|
|
||||||
keys?: {
|
|
||||||
masterKeyEncryptedUserKey?: string;
|
|
||||||
};
|
|
||||||
profile?: {
|
|
||||||
forceSetPasswordReason?: number;
|
|
||||||
keyHash?: string;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
export const FORCE_SET_PASSWORD_REASON_DEFINITION: KeyDefinitionLike = {
|
|
||||||
key: "forceSetPasswordReason",
|
|
||||||
stateDefinition: {
|
|
||||||
name: "masterPassword",
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
export const MASTER_KEY_HASH_DEFINITION: KeyDefinitionLike = {
|
|
||||||
key: "masterKeyHash",
|
|
||||||
stateDefinition: {
|
|
||||||
name: "masterPassword",
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
export const MASTER_KEY_ENCRYPTED_USER_KEY_DEFINITION: KeyDefinitionLike = {
|
|
||||||
key: "masterKeyEncryptedUserKey",
|
|
||||||
stateDefinition: {
|
|
||||||
name: "masterPassword",
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
export class MoveMasterKeyStateToProviderMigrator extends Migrator<54, 55> {
|
|
||||||
async migrate(helper: MigrationHelper): Promise<void> {
|
|
||||||
const accounts = await helper.getAccounts<ExpectedAccountType>();
|
|
||||||
async function migrateAccount(userId: string, account: ExpectedAccountType): Promise<void> {
|
|
||||||
const forceSetPasswordReason = account?.profile?.forceSetPasswordReason;
|
|
||||||
if (forceSetPasswordReason != null) {
|
|
||||||
await helper.setToUser(
|
|
||||||
userId,
|
|
||||||
FORCE_SET_PASSWORD_REASON_DEFINITION,
|
|
||||||
forceSetPasswordReason,
|
|
||||||
);
|
|
||||||
|
|
||||||
delete account.profile.forceSetPasswordReason;
|
|
||||||
await helper.set(userId, account);
|
|
||||||
}
|
|
||||||
|
|
||||||
const masterKeyHash = account?.profile?.keyHash;
|
|
||||||
if (masterKeyHash != null) {
|
|
||||||
await helper.setToUser(userId, MASTER_KEY_HASH_DEFINITION, masterKeyHash);
|
|
||||||
|
|
||||||
delete account.profile.keyHash;
|
|
||||||
await helper.set(userId, account);
|
|
||||||
}
|
|
||||||
|
|
||||||
const masterKeyEncryptedUserKey = account?.keys?.masterKeyEncryptedUserKey;
|
|
||||||
if (masterKeyEncryptedUserKey != null) {
|
|
||||||
await helper.setToUser(
|
|
||||||
userId,
|
|
||||||
MASTER_KEY_ENCRYPTED_USER_KEY_DEFINITION,
|
|
||||||
masterKeyEncryptedUserKey,
|
|
||||||
);
|
|
||||||
|
|
||||||
delete account.keys.masterKeyEncryptedUserKey;
|
|
||||||
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 forceSetPasswordReason = await helper.getFromUser(
|
|
||||||
userId,
|
|
||||||
FORCE_SET_PASSWORD_REASON_DEFINITION,
|
|
||||||
);
|
|
||||||
const masterKeyHash = await helper.getFromUser(userId, MASTER_KEY_HASH_DEFINITION);
|
|
||||||
const masterKeyEncryptedUserKey = await helper.getFromUser(
|
|
||||||
userId,
|
|
||||||
MASTER_KEY_ENCRYPTED_USER_KEY_DEFINITION,
|
|
||||||
);
|
|
||||||
if (account != null) {
|
|
||||||
if (forceSetPasswordReason != null) {
|
|
||||||
account.profile = Object.assign(account.profile ?? {}, {
|
|
||||||
forceSetPasswordReason,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
if (masterKeyHash != null) {
|
|
||||||
account.profile = Object.assign(account.profile ?? {}, {
|
|
||||||
keyHash: masterKeyHash,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
if (masterKeyEncryptedUserKey != null) {
|
|
||||||
account.keys = Object.assign(account.keys ?? {}, {
|
|
||||||
masterKeyEncryptedUserKey,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
await helper.set(userId, account);
|
|
||||||
}
|
|
||||||
|
|
||||||
await helper.setToUser(userId, FORCE_SET_PASSWORD_REASON_DEFINITION, null);
|
|
||||||
await helper.setToUser(userId, MASTER_KEY_HASH_DEFINITION, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
await Promise.all([...accounts.map(({ userId, account }) => rollbackAccount(userId, account))]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -11,10 +11,8 @@ import { OrganizationData } from "../../../admin-console/models/data/organizatio
|
|||||||
import { PolicyData } from "../../../admin-console/models/data/policy.data";
|
import { PolicyData } from "../../../admin-console/models/data/policy.data";
|
||||||
import { ProviderData } from "../../../admin-console/models/data/provider.data";
|
import { ProviderData } from "../../../admin-console/models/data/provider.data";
|
||||||
import { PolicyResponse } from "../../../admin-console/models/response/policy.response";
|
import { PolicyResponse } from "../../../admin-console/models/response/policy.response";
|
||||||
import { AccountService } from "../../../auth/abstractions/account.service";
|
|
||||||
import { AvatarService } from "../../../auth/abstractions/avatar.service";
|
import { AvatarService } from "../../../auth/abstractions/avatar.service";
|
||||||
import { KeyConnectorService } from "../../../auth/abstractions/key-connector.service";
|
import { KeyConnectorService } from "../../../auth/abstractions/key-connector.service";
|
||||||
import { InternalMasterPasswordServiceAbstraction } from "../../../auth/abstractions/master-password.service.abstraction";
|
|
||||||
import { ForceSetPasswordReason } from "../../../auth/models/domain/force-set-password-reason";
|
import { ForceSetPasswordReason } from "../../../auth/models/domain/force-set-password-reason";
|
||||||
import { DomainSettingsService } from "../../../autofill/services/domain-settings.service";
|
import { DomainSettingsService } from "../../../autofill/services/domain-settings.service";
|
||||||
import { BillingAccountProfileStateService } from "../../../billing/abstractions/account/billing-account-profile-state.service";
|
import { BillingAccountProfileStateService } from "../../../billing/abstractions/account/billing-account-profile-state.service";
|
||||||
@@ -51,8 +49,6 @@ export class SyncService implements SyncServiceAbstraction {
|
|||||||
syncInProgress = false;
|
syncInProgress = false;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private masterPasswordService: InternalMasterPasswordServiceAbstraction,
|
|
||||||
private accountService: AccountService,
|
|
||||||
private apiService: ApiService,
|
private apiService: ApiService,
|
||||||
private domainSettingsService: DomainSettingsService,
|
private domainSettingsService: DomainSettingsService,
|
||||||
private folderService: InternalFolderService,
|
private folderService: InternalFolderService,
|
||||||
@@ -356,10 +352,8 @@ export class SyncService implements SyncServiceAbstraction {
|
|||||||
private async setForceSetPasswordReasonIfNeeded(profileResponse: ProfileResponse) {
|
private async setForceSetPasswordReasonIfNeeded(profileResponse: ProfileResponse) {
|
||||||
// The `forcePasswordReset` flag indicates an admin has reset the user's password and must be updated
|
// The `forcePasswordReset` flag indicates an admin has reset the user's password and must be updated
|
||||||
if (profileResponse.forcePasswordReset) {
|
if (profileResponse.forcePasswordReset) {
|
||||||
const userId = (await firstValueFrom(this.accountService.activeAccount$))?.id;
|
await this.stateService.setForceSetPasswordReason(
|
||||||
await this.masterPasswordService.setForceSetPasswordReason(
|
|
||||||
ForceSetPasswordReason.AdminForcePasswordReset,
|
ForceSetPasswordReason.AdminForcePasswordReset,
|
||||||
userId,
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -393,10 +387,8 @@ export class SyncService implements SyncServiceAbstraction {
|
|||||||
) {
|
) {
|
||||||
// TDE user w/out MP went from having no password reset permission to having it.
|
// TDE user w/out MP went from having no password reset permission to having it.
|
||||||
// Must set the force password reset reason so the auth guard will redirect to the set password page.
|
// Must set the force password reset reason so the auth guard will redirect to the set password page.
|
||||||
const userId = (await firstValueFrom(this.accountService.activeAccount$))?.id;
|
await this.stateService.setForceSetPasswordReason(
|
||||||
await this.masterPasswordService.setForceSetPasswordReason(
|
|
||||||
ForceSetPasswordReason.TdeUserWithoutPasswordHasPasswordResetPermission,
|
ForceSetPasswordReason.TdeUserWithoutPasswordHasPasswordResetPermission,
|
||||||
userId,
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user