mirror of
https://github.com/bitwarden/browser
synced 2026-02-15 07:54:55 +00:00
tmp
This commit is contained in:
@@ -1,232 +0,0 @@
|
||||
// FIXME: Update this file to be type safe and remove this and next line
|
||||
// @ts-strict-ignore
|
||||
import { Directive, OnDestroy, OnInit } from "@angular/core";
|
||||
import { Subject, firstValueFrom, map, switchMap, takeUntil } from "rxjs";
|
||||
|
||||
import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction";
|
||||
import { MasterPasswordPolicyOptions } from "@bitwarden/common/admin-console/models/domain/master-password-policy-options";
|
||||
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
||||
import { getUserId } from "@bitwarden/common/auth/services/account.service";
|
||||
import { EncString } from "@bitwarden/common/key-management/crypto/models/enc-string";
|
||||
import { InternalMasterPasswordServiceAbstraction } from "@bitwarden/common/key-management/master-password/abstractions/master-password.service.abstraction";
|
||||
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 { Utils } from "@bitwarden/common/platform/misc/utils";
|
||||
import { UserKey, MasterKey } from "@bitwarden/common/types/key";
|
||||
import { DialogService, ToastService } from "@bitwarden/components";
|
||||
import { KdfConfig, KdfConfigService, KeyService } from "@bitwarden/key-management";
|
||||
|
||||
import { PasswordColorText } from "../../tools/password-strength/password-strength.component";
|
||||
|
||||
@Directive()
|
||||
export class ChangePasswordComponent implements OnInit, OnDestroy {
|
||||
masterPassword: string;
|
||||
masterPasswordRetype: string;
|
||||
formPromise: Promise<any>;
|
||||
enforcedPolicyOptions: MasterPasswordPolicyOptions;
|
||||
passwordStrengthResult: any;
|
||||
color: string;
|
||||
text: string;
|
||||
leakedPassword: boolean;
|
||||
minimumLength = Utils.minimumPasswordLength;
|
||||
|
||||
protected email: string;
|
||||
protected kdfConfig: KdfConfig;
|
||||
|
||||
protected destroy$ = new Subject<void>();
|
||||
|
||||
constructor(
|
||||
protected accountService: AccountService,
|
||||
protected dialogService: DialogService,
|
||||
protected i18nService: I18nService,
|
||||
protected kdfConfigService: KdfConfigService,
|
||||
protected keyService: KeyService,
|
||||
protected masterPasswordService: InternalMasterPasswordServiceAbstraction,
|
||||
protected messagingService: MessagingService,
|
||||
protected platformUtilsService: PlatformUtilsService,
|
||||
protected policyService: PolicyService,
|
||||
protected toastService: ToastService,
|
||||
) {}
|
||||
|
||||
async ngOnInit() {
|
||||
this.email = await firstValueFrom(
|
||||
this.accountService.activeAccount$.pipe(map((a) => a?.email)),
|
||||
);
|
||||
this.accountService.activeAccount$
|
||||
.pipe(
|
||||
getUserId,
|
||||
switchMap((userId) => this.policyService.masterPasswordPolicyOptions$(userId)),
|
||||
takeUntil(this.destroy$),
|
||||
)
|
||||
.subscribe(
|
||||
(enforcedPasswordPolicyOptions) =>
|
||||
(this.enforcedPolicyOptions ??= enforcedPasswordPolicyOptions),
|
||||
);
|
||||
|
||||
if (this.enforcedPolicyOptions?.minLength) {
|
||||
this.minimumLength = this.enforcedPolicyOptions.minLength;
|
||||
}
|
||||
}
|
||||
|
||||
ngOnDestroy(): void {
|
||||
this.destroy$.next();
|
||||
this.destroy$.complete();
|
||||
}
|
||||
|
||||
async submit() {
|
||||
if (!(await this.strongPassword())) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!(await this.setupSubmitActions())) {
|
||||
return;
|
||||
}
|
||||
|
||||
const [userId, email] = await firstValueFrom(
|
||||
this.accountService.activeAccount$.pipe(map((a) => [a?.id, a?.email])),
|
||||
);
|
||||
|
||||
if (this.kdfConfig == null) {
|
||||
this.kdfConfig = await this.kdfConfigService.getKdfConfig(userId);
|
||||
}
|
||||
|
||||
// Create new master key
|
||||
const newMasterKey = await this.keyService.makeMasterKey(
|
||||
this.masterPassword,
|
||||
email.trim().toLowerCase(),
|
||||
this.kdfConfig,
|
||||
);
|
||||
const newMasterKeyHash = await this.keyService.hashMasterKey(this.masterPassword, newMasterKey);
|
||||
|
||||
let newProtectedUserKey: [UserKey, EncString] = null;
|
||||
const userKey = await this.keyService.getUserKey();
|
||||
if (userKey == null) {
|
||||
newProtectedUserKey = await this.keyService.makeUserKey(newMasterKey);
|
||||
} else {
|
||||
newProtectedUserKey = await this.keyService.encryptUserKeyWithMasterKey(newMasterKey);
|
||||
}
|
||||
|
||||
await this.performSubmitActions(newMasterKeyHash, newMasterKey, newProtectedUserKey);
|
||||
}
|
||||
|
||||
async setupSubmitActions(): Promise<boolean> {
|
||||
// Override in sub-class
|
||||
// Can be used for additional validation and/or other processes the should occur before changing passwords
|
||||
return true;
|
||||
}
|
||||
|
||||
async performSubmitActions(
|
||||
newMasterKeyHash: string,
|
||||
newMasterKey: MasterKey,
|
||||
newUserKey: [UserKey, EncString],
|
||||
) {
|
||||
// Override in sub-class
|
||||
}
|
||||
|
||||
async strongPassword(): Promise<boolean> {
|
||||
if (this.masterPassword == null || this.masterPassword === "") {
|
||||
this.toastService.showToast({
|
||||
variant: "error",
|
||||
title: this.i18nService.t("errorOccurred"),
|
||||
message: this.i18nService.t("masterPasswordRequired"),
|
||||
});
|
||||
return false;
|
||||
}
|
||||
if (this.masterPassword.length < this.minimumLength) {
|
||||
this.toastService.showToast({
|
||||
variant: "error",
|
||||
title: this.i18nService.t("errorOccurred"),
|
||||
message: this.i18nService.t("masterPasswordMinimumlength", this.minimumLength),
|
||||
});
|
||||
return false;
|
||||
}
|
||||
if (this.masterPassword !== this.masterPasswordRetype) {
|
||||
this.toastService.showToast({
|
||||
variant: "error",
|
||||
title: this.i18nService.t("errorOccurred"),
|
||||
message: this.i18nService.t("masterPassDoesntMatch"),
|
||||
});
|
||||
return false;
|
||||
}
|
||||
|
||||
const strengthResult = this.passwordStrengthResult;
|
||||
|
||||
if (
|
||||
this.enforcedPolicyOptions != null &&
|
||||
!this.policyService.evaluateMasterPassword(
|
||||
strengthResult.score,
|
||||
this.masterPassword,
|
||||
this.enforcedPolicyOptions,
|
||||
)
|
||||
) {
|
||||
this.toastService.showToast({
|
||||
variant: "error",
|
||||
title: this.i18nService.t("errorOccurred"),
|
||||
message: this.i18nService.t("masterPasswordPolicyRequirementsNotMet"),
|
||||
});
|
||||
return false;
|
||||
}
|
||||
|
||||
const weakPassword = strengthResult != null && strengthResult.score < 3;
|
||||
|
||||
if (weakPassword && this.leakedPassword) {
|
||||
const result = await this.dialogService.openSimpleDialog({
|
||||
title: { key: "weakAndExposedMasterPassword" },
|
||||
content: { key: "weakAndBreachedMasterPasswordDesc" },
|
||||
type: "warning",
|
||||
});
|
||||
|
||||
if (!result) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if (weakPassword) {
|
||||
const result = await this.dialogService.openSimpleDialog({
|
||||
title: { key: "weakMasterPassword" },
|
||||
content: { key: "weakMasterPasswordDesc" },
|
||||
type: "warning",
|
||||
});
|
||||
|
||||
if (!result) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (this.leakedPassword) {
|
||||
const result = await this.dialogService.openSimpleDialog({
|
||||
title: { key: "exposedMasterPassword" },
|
||||
content: { key: "exposedMasterPasswordDesc" },
|
||||
type: "warning",
|
||||
});
|
||||
|
||||
if (!result) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
async logOut() {
|
||||
const confirmed = await this.dialogService.openSimpleDialog({
|
||||
title: { key: "logOut" },
|
||||
content: { key: "logOutConfirmation" },
|
||||
acceptButtonText: { key: "logOut" },
|
||||
type: "warning",
|
||||
});
|
||||
|
||||
if (confirmed) {
|
||||
this.messagingService.send("logout");
|
||||
}
|
||||
}
|
||||
|
||||
getStrengthResult(result: any) {
|
||||
this.passwordStrengthResult = result;
|
||||
}
|
||||
|
||||
getPasswordScoreText(event: PasswordColorText) {
|
||||
this.color = event.color;
|
||||
this.text = event.text;
|
||||
}
|
||||
}
|
||||
@@ -1,300 +0,0 @@
|
||||
// FIXME: Update this file to be type safe and remove this and next line
|
||||
// @ts-strict-ignore
|
||||
import { Directive, OnInit } from "@angular/core";
|
||||
import { ActivatedRoute, Router } from "@angular/router";
|
||||
import { firstValueFrom, of } from "rxjs";
|
||||
import { filter, first, switchMap, tap } from "rxjs/operators";
|
||||
|
||||
// This import has been flagged as unallowed for this class. It may be involved in a circular dependency loop.
|
||||
// eslint-disable-next-line no-restricted-imports
|
||||
import {
|
||||
OrganizationUserApiService,
|
||||
OrganizationUserResetPasswordEnrollmentRequest,
|
||||
} from "@bitwarden/admin-console/common";
|
||||
// This import has been flagged as unallowed for this class. It may be involved in a circular dependency loop.
|
||||
// eslint-disable-next-line no-restricted-imports
|
||||
import { InternalUserDecryptionOptionsServiceAbstraction } from "@bitwarden/auth/common";
|
||||
import { OrganizationApiServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/organization/organization-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 { MasterPasswordPolicyOptions } from "@bitwarden/common/admin-console/models/domain/master-password-policy-options";
|
||||
import { OrganizationAutoEnrollStatusResponse } from "@bitwarden/common/admin-console/models/response/organization-auto-enroll-status.response";
|
||||
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
||||
import { MasterPasswordApiService } from "@bitwarden/common/auth/abstractions/master-password-api.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 { SetPasswordRequest } from "@bitwarden/common/auth/models/request/set-password.request";
|
||||
import { EncryptService } from "@bitwarden/common/key-management/crypto/abstractions/encrypt.service";
|
||||
import { EncString } from "@bitwarden/common/key-management/crypto/models/enc-string";
|
||||
import { InternalMasterPasswordServiceAbstraction } from "@bitwarden/common/key-management/master-password/abstractions/master-password.service.abstraction";
|
||||
import { KeysRequest } from "@bitwarden/common/models/request/keys.request";
|
||||
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 { HashPurpose } from "@bitwarden/common/platform/enums";
|
||||
import { Utils } from "@bitwarden/common/platform/misc/utils";
|
||||
import { UserId } from "@bitwarden/common/types/guid";
|
||||
import { MasterKey, UserKey } from "@bitwarden/common/types/key";
|
||||
import { SyncService } from "@bitwarden/common/vault/abstractions/sync/sync.service.abstraction";
|
||||
import { DialogService, ToastService } from "@bitwarden/components";
|
||||
import { DEFAULT_KDF_CONFIG, KdfConfigService, KeyService } from "@bitwarden/key-management";
|
||||
|
||||
import { ChangePasswordComponent as BaseChangePasswordComponent } from "./change-password.component";
|
||||
|
||||
@Directive()
|
||||
export class SetPasswordComponent extends BaseChangePasswordComponent implements OnInit {
|
||||
syncLoading = true;
|
||||
showPassword = false;
|
||||
hint = "";
|
||||
orgSsoIdentifier: string = null;
|
||||
orgId: string;
|
||||
resetPasswordAutoEnroll = false;
|
||||
onSuccessfulChangePassword: () => Promise<void>;
|
||||
successRoute = "vault";
|
||||
activeUserId: UserId;
|
||||
|
||||
forceSetPasswordReason: ForceSetPasswordReason = ForceSetPasswordReason.None;
|
||||
ForceSetPasswordReason = ForceSetPasswordReason;
|
||||
|
||||
constructor(
|
||||
protected accountService: AccountService,
|
||||
protected dialogService: DialogService,
|
||||
protected encryptService: EncryptService,
|
||||
protected i18nService: I18nService,
|
||||
protected kdfConfigService: KdfConfigService,
|
||||
protected keyService: KeyService,
|
||||
protected masterPasswordApiService: MasterPasswordApiService,
|
||||
protected masterPasswordService: InternalMasterPasswordServiceAbstraction,
|
||||
protected messagingService: MessagingService,
|
||||
protected organizationApiService: OrganizationApiServiceAbstraction,
|
||||
protected organizationUserApiService: OrganizationUserApiService,
|
||||
protected platformUtilsService: PlatformUtilsService,
|
||||
protected policyApiService: PolicyApiServiceAbstraction,
|
||||
protected policyService: PolicyService,
|
||||
protected route: ActivatedRoute,
|
||||
protected router: Router,
|
||||
protected ssoLoginService: SsoLoginServiceAbstraction,
|
||||
protected syncService: SyncService,
|
||||
protected toastService: ToastService,
|
||||
protected userDecryptionOptionsService: InternalUserDecryptionOptionsServiceAbstraction,
|
||||
) {
|
||||
super(
|
||||
accountService,
|
||||
dialogService,
|
||||
i18nService,
|
||||
kdfConfigService,
|
||||
keyService,
|
||||
masterPasswordService,
|
||||
messagingService,
|
||||
platformUtilsService,
|
||||
policyService,
|
||||
toastService,
|
||||
);
|
||||
}
|
||||
|
||||
async ngOnInit() {
|
||||
// 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
|
||||
super.ngOnInit();
|
||||
|
||||
await this.syncService.fullSync(true);
|
||||
this.syncLoading = false;
|
||||
|
||||
this.activeUserId = (await firstValueFrom(this.accountService.activeAccount$))?.id;
|
||||
|
||||
this.forceSetPasswordReason = await firstValueFrom(
|
||||
this.masterPasswordService.forceSetPasswordReason$(this.activeUserId),
|
||||
);
|
||||
|
||||
this.route.queryParams
|
||||
.pipe(
|
||||
first(),
|
||||
switchMap((qParams) => {
|
||||
if (qParams.identifier != null) {
|
||||
return of(qParams.identifier);
|
||||
} else {
|
||||
// Try to get orgSsoId from state as fallback
|
||||
// Note: this is primarily for the TDE user w/out MP obtains admin MP reset permission scenario.
|
||||
return this.ssoLoginService.getActiveUserOrganizationSsoIdentifier(this.activeUserId);
|
||||
}
|
||||
}),
|
||||
filter((orgSsoId) => orgSsoId != null),
|
||||
tap((orgSsoId: string) => {
|
||||
this.orgSsoIdentifier = orgSsoId;
|
||||
}),
|
||||
switchMap((orgSsoId: string) => this.organizationApiService.getAutoEnrollStatus(orgSsoId)),
|
||||
tap((orgAutoEnrollStatusResponse: OrganizationAutoEnrollStatusResponse) => {
|
||||
this.orgId = orgAutoEnrollStatusResponse.id;
|
||||
this.resetPasswordAutoEnroll = orgAutoEnrollStatusResponse.resetPasswordEnabled;
|
||||
}),
|
||||
switchMap((orgAutoEnrollStatusResponse: OrganizationAutoEnrollStatusResponse) =>
|
||||
// Must get org id from response to get master password policy options
|
||||
this.policyApiService.getMasterPasswordPolicyOptsForOrgUser(
|
||||
orgAutoEnrollStatusResponse.id,
|
||||
),
|
||||
),
|
||||
tap((masterPasswordPolicyOptions: MasterPasswordPolicyOptions) => {
|
||||
this.enforcedPolicyOptions = masterPasswordPolicyOptions;
|
||||
}),
|
||||
)
|
||||
.subscribe({
|
||||
error: () => {
|
||||
this.toastService.showToast({
|
||||
variant: "error",
|
||||
title: null,
|
||||
message: this.i18nService.t("errorOccurred"),
|
||||
});
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
async setupSubmitActions() {
|
||||
this.kdfConfig = DEFAULT_KDF_CONFIG;
|
||||
return true;
|
||||
}
|
||||
|
||||
async performSubmitActions(
|
||||
masterPasswordHash: string,
|
||||
masterKey: MasterKey,
|
||||
userKey: [UserKey, EncString],
|
||||
) {
|
||||
let keysRequest: KeysRequest | null = null;
|
||||
let newKeyPair: [string, EncString] | null = null;
|
||||
|
||||
if (
|
||||
this.forceSetPasswordReason !=
|
||||
ForceSetPasswordReason.TdeUserWithoutPasswordHasPasswordResetPermission
|
||||
) {
|
||||
// Existing JIT provisioned user in a MP encryption org setting first password
|
||||
// Users in this state will not already have a user asymmetric key pair so must create it for them
|
||||
// We don't want to re-create the user key pair if the user already has one (TDE user case)
|
||||
|
||||
// in case we have a local private key, and are not sure whether it has been posted to the server, we post the local private key instead of generating a new one
|
||||
const existingUserPrivateKey = (await firstValueFrom(
|
||||
this.keyService.userPrivateKey$(this.activeUserId),
|
||||
)) as Uint8Array;
|
||||
const existingUserPublicKey = await firstValueFrom(
|
||||
this.keyService.userPublicKey$(this.activeUserId),
|
||||
);
|
||||
if (existingUserPrivateKey != null && existingUserPublicKey != null) {
|
||||
const existingUserPublicKeyB64 = Utils.fromBufferToB64(existingUserPublicKey);
|
||||
newKeyPair = [
|
||||
existingUserPublicKeyB64,
|
||||
await this.encryptService.wrapDecapsulationKey(existingUserPrivateKey, userKey[0]),
|
||||
];
|
||||
} else {
|
||||
newKeyPair = await this.keyService.makeKeyPair(userKey[0]);
|
||||
}
|
||||
keysRequest = new KeysRequest(newKeyPair[0], newKeyPair[1].encryptedString);
|
||||
}
|
||||
|
||||
const request = new SetPasswordRequest(
|
||||
masterPasswordHash,
|
||||
userKey[1].encryptedString,
|
||||
this.hint,
|
||||
this.orgSsoIdentifier,
|
||||
keysRequest,
|
||||
this.kdfConfig.kdfType, //always PBKDF2 --> see this.setupSubmitActions
|
||||
this.kdfConfig.iterations,
|
||||
);
|
||||
try {
|
||||
if (this.resetPasswordAutoEnroll) {
|
||||
this.formPromise = this.masterPasswordApiService
|
||||
.setPassword(request)
|
||||
.then(async () => {
|
||||
await this.onSetPasswordSuccess(masterKey, userKey, newKeyPair);
|
||||
return this.organizationApiService.getKeys(this.orgId);
|
||||
})
|
||||
.then(async (response) => {
|
||||
if (response == null) {
|
||||
throw new Error(this.i18nService.t("resetPasswordOrgKeysError"));
|
||||
}
|
||||
const publicKey = Utils.fromB64ToArray(response.publicKey);
|
||||
|
||||
// RSA Encrypt user key with organization public key
|
||||
const userKey = await this.keyService.getUserKey();
|
||||
const encryptedUserKey = await this.encryptService.encapsulateKeyUnsigned(
|
||||
userKey,
|
||||
publicKey,
|
||||
);
|
||||
|
||||
const resetRequest = new OrganizationUserResetPasswordEnrollmentRequest();
|
||||
resetRequest.masterPasswordHash = masterPasswordHash;
|
||||
resetRequest.resetPasswordKey = encryptedUserKey.encryptedString;
|
||||
|
||||
return this.organizationUserApiService.putOrganizationUserResetPasswordEnrollment(
|
||||
this.orgId,
|
||||
this.activeUserId,
|
||||
resetRequest,
|
||||
);
|
||||
});
|
||||
} else {
|
||||
this.formPromise = this.masterPasswordApiService.setPassword(request).then(async () => {
|
||||
await this.onSetPasswordSuccess(masterKey, userKey, newKeyPair);
|
||||
});
|
||||
}
|
||||
|
||||
await this.formPromise;
|
||||
|
||||
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.
|
||||
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
||||
this.onSuccessfulChangePassword();
|
||||
} else {
|
||||
// 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
|
||||
this.router.navigate([this.successRoute]);
|
||||
}
|
||||
} catch {
|
||||
this.toastService.showToast({
|
||||
variant: "error",
|
||||
title: null,
|
||||
message: this.i18nService.t("errorOccurred"),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
togglePassword(confirmField: boolean) {
|
||||
this.showPassword = !this.showPassword;
|
||||
document.getElementById(confirmField ? "masterPasswordRetype" : "masterPassword").focus();
|
||||
}
|
||||
|
||||
protected async onSetPasswordSuccess(
|
||||
masterKey: MasterKey,
|
||||
userKey: [UserKey, EncString],
|
||||
keyPair: [string, EncString] | null,
|
||||
) {
|
||||
// Clear force set password reason to allow navigation back to vault.
|
||||
await this.masterPasswordService.setForceSetPasswordReason(
|
||||
ForceSetPasswordReason.None,
|
||||
this.activeUserId,
|
||||
);
|
||||
|
||||
// User now has a password so update account decryption options in state
|
||||
const userDecryptionOpts = await firstValueFrom(
|
||||
this.userDecryptionOptionsService.userDecryptionOptions$,
|
||||
);
|
||||
userDecryptionOpts.hasMasterPassword = true;
|
||||
await this.userDecryptionOptionsService.setUserDecryptionOptions(userDecryptionOpts);
|
||||
await this.kdfConfigService.setKdfConfig(this.activeUserId, this.kdfConfig);
|
||||
await this.masterPasswordService.setMasterKey(masterKey, this.activeUserId);
|
||||
await this.keyService.setUserKey(userKey[0], this.activeUserId);
|
||||
|
||||
// Set private key only for new JIT provisioned users in MP encryption orgs
|
||||
// Existing TDE users will have private key set on sync or on login
|
||||
if (
|
||||
keyPair !== null &&
|
||||
this.forceSetPasswordReason !=
|
||||
ForceSetPasswordReason.TdeUserWithoutPasswordHasPasswordResetPermission
|
||||
) {
|
||||
await this.keyService.setPrivateKey(keyPair[1].encryptedString, this.activeUserId);
|
||||
}
|
||||
|
||||
const localMasterKeyHash = await this.keyService.hashMasterKey(
|
||||
this.masterPassword,
|
||||
masterKey,
|
||||
HashPurpose.LocalAuthorization,
|
||||
);
|
||||
await this.masterPasswordService.setMasterKeyHash(localMasterKeyHash, this.activeUserId);
|
||||
}
|
||||
}
|
||||
@@ -1,141 +0,0 @@
|
||||
// FIXME: Update this file to be type safe and remove this and next line
|
||||
// @ts-strict-ignore
|
||||
import { Directive } from "@angular/core";
|
||||
import { Router } from "@angular/router";
|
||||
import { firstValueFrom } from "rxjs";
|
||||
|
||||
import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction";
|
||||
import { MasterPasswordPolicyOptions } from "@bitwarden/common/admin-console/models/domain/master-password-policy-options";
|
||||
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
||||
import { MasterPasswordApiService } from "@bitwarden/common/auth/abstractions/master-password-api.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 { PasswordRequest } from "@bitwarden/common/auth/models/request/password.request";
|
||||
import { getUserId } from "@bitwarden/common/auth/services/account.service";
|
||||
import { Verification } from "@bitwarden/common/auth/types/verification";
|
||||
import { EncString } from "@bitwarden/common/key-management/crypto/models/enc-string";
|
||||
import { InternalMasterPasswordServiceAbstraction } from "@bitwarden/common/key-management/master-password/abstractions/master-password.service.abstraction";
|
||||
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 { MasterKey, UserKey } from "@bitwarden/common/types/key";
|
||||
import { DialogService, ToastService } from "@bitwarden/components";
|
||||
import { KdfConfigService, KeyService } from "@bitwarden/key-management";
|
||||
|
||||
import { ChangePasswordComponent as BaseChangePasswordComponent } from "./change-password.component";
|
||||
|
||||
@Directive()
|
||||
export class UpdatePasswordComponent extends BaseChangePasswordComponent {
|
||||
hint: string;
|
||||
key: string;
|
||||
enforcedPolicyOptions: MasterPasswordPolicyOptions;
|
||||
showPassword = false;
|
||||
currentMasterPassword: string;
|
||||
|
||||
onSuccessfulChangePassword: () => Promise<void>;
|
||||
|
||||
constructor(
|
||||
protected router: Router,
|
||||
i18nService: I18nService,
|
||||
platformUtilsService: PlatformUtilsService,
|
||||
policyService: PolicyService,
|
||||
keyService: KeyService,
|
||||
messagingService: MessagingService,
|
||||
private masterPasswordApiService: MasterPasswordApiService,
|
||||
private userVerificationService: UserVerificationService,
|
||||
private logService: LogService,
|
||||
dialogService: DialogService,
|
||||
kdfConfigService: KdfConfigService,
|
||||
masterPasswordService: InternalMasterPasswordServiceAbstraction,
|
||||
accountService: AccountService,
|
||||
toastService: ToastService,
|
||||
) {
|
||||
super(
|
||||
accountService,
|
||||
dialogService,
|
||||
i18nService,
|
||||
kdfConfigService,
|
||||
keyService,
|
||||
masterPasswordService,
|
||||
messagingService,
|
||||
platformUtilsService,
|
||||
policyService,
|
||||
toastService,
|
||||
);
|
||||
}
|
||||
|
||||
togglePassword(confirmField: boolean) {
|
||||
this.showPassword = !this.showPassword;
|
||||
document.getElementById(confirmField ? "masterPasswordRetype" : "masterPassword").focus();
|
||||
}
|
||||
|
||||
async cancel() {
|
||||
await this.router.navigate(["/vault"]);
|
||||
}
|
||||
|
||||
async setupSubmitActions(): Promise<boolean> {
|
||||
if (this.currentMasterPassword == null || this.currentMasterPassword === "") {
|
||||
this.toastService.showToast({
|
||||
variant: "error",
|
||||
title: this.i18nService.t("errorOccurred"),
|
||||
message: this.i18nService.t("masterPasswordRequired"),
|
||||
});
|
||||
return false;
|
||||
}
|
||||
|
||||
const secret: Verification = {
|
||||
type: VerificationType.MasterPassword,
|
||||
secret: this.currentMasterPassword,
|
||||
};
|
||||
try {
|
||||
await this.userVerificationService.verifyUser(secret);
|
||||
} catch (e) {
|
||||
this.toastService.showToast({
|
||||
variant: "error",
|
||||
title: this.i18nService.t("errorOccurred"),
|
||||
message: e.message,
|
||||
});
|
||||
return false;
|
||||
}
|
||||
const userId = await firstValueFrom(getUserId(this.accountService.activeAccount$));
|
||||
this.kdfConfig = await this.kdfConfigService.getKdfConfig(userId);
|
||||
return true;
|
||||
}
|
||||
|
||||
async performSubmitActions(
|
||||
newMasterKeyHash: string,
|
||||
newMasterKey: MasterKey,
|
||||
newUserKey: [UserKey, EncString],
|
||||
) {
|
||||
try {
|
||||
// Create Request
|
||||
const request = new PasswordRequest();
|
||||
request.masterPasswordHash = await this.keyService.hashMasterKey(
|
||||
this.currentMasterPassword,
|
||||
await this.keyService.getOrDeriveMasterKey(this.currentMasterPassword),
|
||||
);
|
||||
request.newMasterPasswordHash = newMasterKeyHash;
|
||||
request.key = newUserKey[1].encryptedString;
|
||||
|
||||
// Update user's password
|
||||
await this.masterPasswordApiService.postPassword(request);
|
||||
|
||||
this.toastService.showToast({
|
||||
variant: "success",
|
||||
title: this.i18nService.t("masterPasswordChanged"),
|
||||
message: this.i18nService.t("logBackIn"),
|
||||
});
|
||||
|
||||
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.
|
||||
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
||||
this.onSuccessfulChangePassword();
|
||||
} else {
|
||||
this.messagingService.send("logout");
|
||||
}
|
||||
} catch (e) {
|
||||
this.logService.error(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,232 +0,0 @@
|
||||
// FIXME: Update this file to be type safe and remove this and next line
|
||||
// @ts-strict-ignore
|
||||
import { Directive, OnInit } from "@angular/core";
|
||||
import { Router } from "@angular/router";
|
||||
import { firstValueFrom, map } from "rxjs";
|
||||
|
||||
import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction";
|
||||
import { MasterPasswordPolicyOptions } from "@bitwarden/common/admin-console/models/domain/master-password-policy-options";
|
||||
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
||||
import { MasterPasswordApiService } from "@bitwarden/common/auth/abstractions/master-password-api.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 { ForceSetPasswordReason } from "@bitwarden/common/auth/models/domain/force-set-password-reason";
|
||||
import { PasswordRequest } from "@bitwarden/common/auth/models/request/password.request";
|
||||
import { UpdateTdeOffboardingPasswordRequest } from "@bitwarden/common/auth/models/request/update-tde-offboarding-password.request";
|
||||
import { UpdateTempPasswordRequest } from "@bitwarden/common/auth/models/request/update-temp-password.request";
|
||||
import { MasterPasswordVerification } from "@bitwarden/common/auth/types/verification";
|
||||
import { EncString } from "@bitwarden/common/key-management/crypto/models/enc-string";
|
||||
import { InternalMasterPasswordServiceAbstraction } from "@bitwarden/common/key-management/master-password/abstractions/master-password.service.abstraction";
|
||||
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 { MasterKey, UserKey } from "@bitwarden/common/types/key";
|
||||
import { SyncService } from "@bitwarden/common/vault/abstractions/sync/sync.service.abstraction";
|
||||
import { DialogService, ToastService } from "@bitwarden/components";
|
||||
import { KdfConfigService, KeyService } from "@bitwarden/key-management";
|
||||
|
||||
import { ChangePasswordComponent as BaseChangePasswordComponent } from "./change-password.component";
|
||||
|
||||
@Directive()
|
||||
export class UpdateTempPasswordComponent extends BaseChangePasswordComponent implements OnInit {
|
||||
hint: string;
|
||||
key: string;
|
||||
enforcedPolicyOptions: MasterPasswordPolicyOptions;
|
||||
showPassword = false;
|
||||
reason: ForceSetPasswordReason = ForceSetPasswordReason.None;
|
||||
verification: MasterPasswordVerification = {
|
||||
type: VerificationType.MasterPassword,
|
||||
secret: "",
|
||||
};
|
||||
|
||||
onSuccessfulChangePassword: () => Promise<any>;
|
||||
|
||||
get requireCurrentPassword(): boolean {
|
||||
return this.reason === ForceSetPasswordReason.WeakMasterPassword;
|
||||
}
|
||||
|
||||
constructor(
|
||||
i18nService: I18nService,
|
||||
platformUtilsService: PlatformUtilsService,
|
||||
policyService: PolicyService,
|
||||
keyService: KeyService,
|
||||
messagingService: MessagingService,
|
||||
private masterPasswordApiService: MasterPasswordApiService,
|
||||
private syncService: SyncService,
|
||||
private logService: LogService,
|
||||
private userVerificationService: UserVerificationService,
|
||||
protected router: Router,
|
||||
dialogService: DialogService,
|
||||
kdfConfigService: KdfConfigService,
|
||||
accountService: AccountService,
|
||||
masterPasswordService: InternalMasterPasswordServiceAbstraction,
|
||||
toastService: ToastService,
|
||||
) {
|
||||
super(
|
||||
accountService,
|
||||
dialogService,
|
||||
i18nService,
|
||||
kdfConfigService,
|
||||
keyService,
|
||||
masterPasswordService,
|
||||
messagingService,
|
||||
platformUtilsService,
|
||||
policyService,
|
||||
toastService,
|
||||
);
|
||||
}
|
||||
|
||||
async ngOnInit() {
|
||||
await this.syncService.fullSync(true);
|
||||
|
||||
const userId = (await firstValueFrom(this.accountService.activeAccount$))?.id;
|
||||
this.reason = await firstValueFrom(this.masterPasswordService.forceSetPasswordReason$(userId));
|
||||
|
||||
// If we somehow end up here without a reason, go back to the home page
|
||||
if (this.reason == ForceSetPasswordReason.None) {
|
||||
// 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
|
||||
this.router.navigate(["/"]);
|
||||
return;
|
||||
}
|
||||
|
||||
await super.ngOnInit();
|
||||
}
|
||||
|
||||
get masterPasswordWarningText(): string {
|
||||
if (this.reason == ForceSetPasswordReason.WeakMasterPassword) {
|
||||
return this.i18nService.t("updateWeakMasterPasswordWarning");
|
||||
} else if (this.reason == ForceSetPasswordReason.TdeOffboarding) {
|
||||
return this.i18nService.t("tdeDisabledMasterPasswordRequired");
|
||||
} else {
|
||||
return this.i18nService.t("updateMasterPasswordWarning");
|
||||
}
|
||||
}
|
||||
|
||||
togglePassword(confirmField: boolean) {
|
||||
this.showPassword = !this.showPassword;
|
||||
document.getElementById(confirmField ? "masterPasswordRetype" : "masterPassword").focus();
|
||||
}
|
||||
|
||||
async setupSubmitActions(): Promise<boolean> {
|
||||
const [userId, email] = await firstValueFrom(
|
||||
this.accountService.activeAccount$.pipe(map((a) => [a?.id, a?.email])),
|
||||
);
|
||||
this.email = email;
|
||||
this.kdfConfig = await this.kdfConfigService.getKdfConfig(userId);
|
||||
return true;
|
||||
}
|
||||
|
||||
async submit() {
|
||||
// Validation
|
||||
if (!(await this.strongPassword())) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!(await this.setupSubmitActions())) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
// Create new key and hash new password
|
||||
const newMasterKey = await this.keyService.makeMasterKey(
|
||||
this.masterPassword,
|
||||
this.email.trim().toLowerCase(),
|
||||
this.kdfConfig,
|
||||
);
|
||||
const newPasswordHash = await this.keyService.hashMasterKey(
|
||||
this.masterPassword,
|
||||
newMasterKey,
|
||||
);
|
||||
|
||||
// Grab user key
|
||||
const userKey = await this.keyService.getUserKey();
|
||||
|
||||
// Encrypt user key with new master key
|
||||
const newProtectedUserKey = await this.keyService.encryptUserKeyWithMasterKey(
|
||||
newMasterKey,
|
||||
userKey,
|
||||
);
|
||||
|
||||
await this.performSubmitActions(newPasswordHash, newMasterKey, newProtectedUserKey);
|
||||
} catch (e) {
|
||||
this.logService.error(e);
|
||||
}
|
||||
}
|
||||
|
||||
async performSubmitActions(
|
||||
masterPasswordHash: string,
|
||||
masterKey: MasterKey,
|
||||
userKey: [UserKey, EncString],
|
||||
) {
|
||||
try {
|
||||
switch (this.reason) {
|
||||
case ForceSetPasswordReason.AdminForcePasswordReset:
|
||||
this.formPromise = this.updateTempPassword(masterPasswordHash, userKey);
|
||||
break;
|
||||
case ForceSetPasswordReason.WeakMasterPassword:
|
||||
this.formPromise = this.updatePassword(masterPasswordHash, userKey);
|
||||
break;
|
||||
case ForceSetPasswordReason.TdeOffboarding:
|
||||
this.formPromise = this.updateTdeOffboardingPassword(masterPasswordHash, userKey);
|
||||
break;
|
||||
}
|
||||
|
||||
await this.formPromise;
|
||||
this.toastService.showToast({
|
||||
variant: "success",
|
||||
title: null,
|
||||
message: this.i18nService.t("updatedMasterPassword"),
|
||||
});
|
||||
|
||||
const userId = (await firstValueFrom(this.accountService.activeAccount$))?.id;
|
||||
await this.masterPasswordService.setForceSetPasswordReason(
|
||||
ForceSetPasswordReason.None,
|
||||
userId,
|
||||
);
|
||||
|
||||
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.
|
||||
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
||||
this.onSuccessfulChangePassword();
|
||||
} else {
|
||||
this.messagingService.send("logout");
|
||||
}
|
||||
} catch (e) {
|
||||
this.logService.error(e);
|
||||
}
|
||||
}
|
||||
private async updateTempPassword(masterPasswordHash: string, userKey: [UserKey, EncString]) {
|
||||
const request = new UpdateTempPasswordRequest();
|
||||
request.key = userKey[1].encryptedString;
|
||||
request.newMasterPasswordHash = masterPasswordHash;
|
||||
request.masterPasswordHint = this.hint;
|
||||
|
||||
return this.masterPasswordApiService.putUpdateTempPassword(request);
|
||||
}
|
||||
|
||||
private async updatePassword(newMasterPasswordHash: string, userKey: [UserKey, EncString]) {
|
||||
const request = await this.userVerificationService.buildRequest(
|
||||
this.verification,
|
||||
PasswordRequest,
|
||||
);
|
||||
request.masterPasswordHint = this.hint;
|
||||
request.newMasterPasswordHash = newMasterPasswordHash;
|
||||
request.key = userKey[1].encryptedString;
|
||||
|
||||
return this.masterPasswordApiService.postPassword(request);
|
||||
}
|
||||
|
||||
private async updateTdeOffboardingPassword(
|
||||
masterPasswordHash: string,
|
||||
userKey: [UserKey, EncString],
|
||||
) {
|
||||
const request = new UpdateTdeOffboardingPasswordRequest();
|
||||
request.key = userKey[1].encryptedString;
|
||||
request.newMasterPasswordHash = masterPasswordHash;
|
||||
request.masterPasswordHint = this.hint;
|
||||
|
||||
return this.masterPasswordApiService.putUpdateTdeOffboardingPassword(request);
|
||||
}
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
@if (initializing) {
|
||||
<i
|
||||
class="bwi bwi-spinner bwi-spin bwi-2x tw-text-muted"
|
||||
title="{{ 'loading' | i18n }}"
|
||||
aria-hidden="true"
|
||||
></i>
|
||||
<span class="tw-sr-only">{{ "loading" | i18n }}</span>
|
||||
} @else {
|
||||
<bit-callout
|
||||
*ngIf="this.forceSetPasswordReason !== ForceSetPasswordReason.AdminForcePasswordReset"
|
||||
type="warning"
|
||||
>{{ "changePasswordWarning" | i18n }}</bit-callout
|
||||
>
|
||||
|
||||
<auth-input-password
|
||||
[flow]="inputPasswordFlow"
|
||||
[email]="email"
|
||||
[userId]="userId"
|
||||
[loading]="submitting"
|
||||
[masterPasswordPolicyOptions]="masterPasswordPolicyOptions"
|
||||
[inlineButtons]="true"
|
||||
[primaryButtonText]="{ key: 'changeMasterPassword' }"
|
||||
(onPasswordFormSubmit)="handlePasswordFormSubmit($event)"
|
||||
[secondaryButtonText]="secondaryButtonText()"
|
||||
(onSecondaryButtonClick)="logOut()"
|
||||
>
|
||||
</auth-input-password>
|
||||
}
|
||||
@@ -1,203 +0,0 @@
|
||||
import { CommonModule } from "@angular/common";
|
||||
import { Component, Input, OnInit } from "@angular/core";
|
||||
import { firstValueFrom } from "rxjs";
|
||||
|
||||
// This import has been flagged as unallowed for this class. It may be involved in a circular dependency loop.
|
||||
// eslint-disable-next-line no-restricted-imports
|
||||
import {
|
||||
InputPasswordComponent,
|
||||
InputPasswordFlow,
|
||||
PasswordInputResult,
|
||||
} from "@bitwarden/auth/angular";
|
||||
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 { Account, AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
||||
import { ForceSetPasswordReason } from "@bitwarden/common/auth/models/domain/force-set-password-reason";
|
||||
import { OrganizationInviteService } from "@bitwarden/common/auth/services/organization-invite/organization-invite.service";
|
||||
import { InternalMasterPasswordServiceAbstraction } from "@bitwarden/common/key-management/master-password/abstractions/master-password.service.abstraction";
|
||||
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 { SyncService } from "@bitwarden/common/platform/sync";
|
||||
import { UserId } from "@bitwarden/common/types/guid";
|
||||
import {
|
||||
AnonLayoutWrapperDataService,
|
||||
DialogService,
|
||||
ToastService,
|
||||
Icons,
|
||||
CalloutComponent,
|
||||
} from "@bitwarden/components";
|
||||
import { I18nPipe } from "@bitwarden/ui-common";
|
||||
|
||||
import { ChangePasswordService } from "./change-password.service.abstraction";
|
||||
|
||||
/**
|
||||
* Change Password Component
|
||||
*
|
||||
* NOTE: The change password component uses the input-password component which will show the
|
||||
* current password input form in some flows, although it could be left off. This is intentional
|
||||
* and by design to maintain a strong security posture as some flows could have the user
|
||||
* end up at a change password without having one before.
|
||||
*/
|
||||
@Component({
|
||||
selector: "auth-change-password",
|
||||
templateUrl: "change-password.component.html",
|
||||
imports: [InputPasswordComponent, I18nPipe, CalloutComponent, CommonModule],
|
||||
})
|
||||
export class ChangePasswordComponent implements OnInit {
|
||||
@Input() inputPasswordFlow: InputPasswordFlow = InputPasswordFlow.ChangePassword;
|
||||
|
||||
activeAccount: Account | null = null;
|
||||
email?: string;
|
||||
userId?: UserId;
|
||||
masterPasswordPolicyOptions?: MasterPasswordPolicyOptions;
|
||||
initializing = true;
|
||||
submitting = false;
|
||||
formPromise?: Promise<any>;
|
||||
forceSetPasswordReason: ForceSetPasswordReason = ForceSetPasswordReason.None;
|
||||
|
||||
protected readonly ForceSetPasswordReason = ForceSetPasswordReason;
|
||||
|
||||
constructor(
|
||||
private accountService: AccountService,
|
||||
private changePasswordService: ChangePasswordService,
|
||||
private i18nService: I18nService,
|
||||
private masterPasswordService: InternalMasterPasswordServiceAbstraction,
|
||||
private anonLayoutWrapperDataService: AnonLayoutWrapperDataService,
|
||||
private organizationInviteService: OrganizationInviteService,
|
||||
private messagingService: MessagingService,
|
||||
private policyService: PolicyService,
|
||||
private toastService: ToastService,
|
||||
private syncService: SyncService,
|
||||
private dialogService: DialogService,
|
||||
private logService: LogService,
|
||||
) {}
|
||||
|
||||
async ngOnInit() {
|
||||
this.activeAccount = await firstValueFrom(this.accountService.activeAccount$);
|
||||
|
||||
if (!this.activeAccount) {
|
||||
throw new Error("No active active account found while trying to change passwords.");
|
||||
}
|
||||
|
||||
this.userId = this.activeAccount.id;
|
||||
this.email = this.activeAccount.email;
|
||||
|
||||
if (!this.userId) {
|
||||
throw new Error("userId not found");
|
||||
}
|
||||
|
||||
this.masterPasswordPolicyOptions = await firstValueFrom(
|
||||
this.policyService.masterPasswordPolicyOptions$(this.userId),
|
||||
);
|
||||
|
||||
this.forceSetPasswordReason = await firstValueFrom(
|
||||
this.masterPasswordService.forceSetPasswordReason$(this.userId),
|
||||
);
|
||||
|
||||
if (this.forceSetPasswordReason === ForceSetPasswordReason.AdminForcePasswordReset) {
|
||||
this.anonLayoutWrapperDataService.setAnonLayoutWrapperData({
|
||||
pageIcon: Icons.LockIcon,
|
||||
pageTitle: { key: "updateMasterPassword" },
|
||||
pageSubtitle: { key: "accountRecoveryUpdateMasterPasswordSubtitle" },
|
||||
});
|
||||
} else if (this.forceSetPasswordReason === ForceSetPasswordReason.WeakMasterPassword) {
|
||||
this.anonLayoutWrapperDataService.setAnonLayoutWrapperData({
|
||||
pageIcon: Icons.LockIcon,
|
||||
pageTitle: { key: "updateMasterPassword" },
|
||||
pageSubtitle: { key: "updateMasterPasswordSubtitle" },
|
||||
maxWidth: "lg",
|
||||
});
|
||||
}
|
||||
|
||||
this.initializing = false;
|
||||
}
|
||||
|
||||
async logOut() {
|
||||
const confirmed = await this.dialogService.openSimpleDialog({
|
||||
title: { key: "logOut" },
|
||||
content: { key: "logOutConfirmation" },
|
||||
acceptButtonText: { key: "logOut" },
|
||||
type: "warning",
|
||||
});
|
||||
|
||||
if (confirmed) {
|
||||
await this.organizationInviteService.clearOrganizationInvitation();
|
||||
|
||||
if (this.changePasswordService.clearDeeplinkState) {
|
||||
await this.changePasswordService.clearDeeplinkState();
|
||||
}
|
||||
|
||||
// TODO: PM-23515 eventually use the logout service instead of messaging service once it is available without circular dependencies
|
||||
this.messagingService.send("logout");
|
||||
}
|
||||
}
|
||||
|
||||
async handlePasswordFormSubmit(passwordInputResult: PasswordInputResult) {
|
||||
this.submitting = true;
|
||||
|
||||
try {
|
||||
if (passwordInputResult.rotateUserKey) {
|
||||
if (this.activeAccount == null) {
|
||||
throw new Error("activeAccount not found");
|
||||
}
|
||||
|
||||
if (
|
||||
passwordInputResult.currentPassword == null ||
|
||||
passwordInputResult.newPasswordHint == null
|
||||
) {
|
||||
throw new Error("currentPassword or newPasswordHint not found");
|
||||
}
|
||||
|
||||
await this.syncService.fullSync(true);
|
||||
|
||||
await this.changePasswordService.rotateUserKeyMasterPasswordAndEncryptedData(
|
||||
passwordInputResult.currentPassword,
|
||||
passwordInputResult.newPassword,
|
||||
this.activeAccount,
|
||||
passwordInputResult.newPasswordHint,
|
||||
);
|
||||
} else {
|
||||
if (!this.userId) {
|
||||
throw new Error("userId not found");
|
||||
}
|
||||
|
||||
if (this.forceSetPasswordReason === ForceSetPasswordReason.AdminForcePasswordReset) {
|
||||
await this.changePasswordService.changePasswordForAccountRecovery(
|
||||
passwordInputResult,
|
||||
this.userId,
|
||||
);
|
||||
} else {
|
||||
await this.changePasswordService.changePassword(passwordInputResult, this.userId);
|
||||
}
|
||||
|
||||
this.toastService.showToast({
|
||||
variant: "success",
|
||||
message: this.i18nService.t("masterPasswordChanged"),
|
||||
});
|
||||
|
||||
// TODO: PM-23515 eventually use the logout service instead of messaging service once it is available without circular dependencies
|
||||
this.messagingService.send("logout");
|
||||
}
|
||||
} catch (error) {
|
||||
this.logService.error(error);
|
||||
this.toastService.showToast({
|
||||
variant: "error",
|
||||
title: "",
|
||||
message: this.i18nService.t("errorOccurred"),
|
||||
});
|
||||
} finally {
|
||||
this.submitting = false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows the logout button in the case of admin force reset password or weak password upon login.
|
||||
*/
|
||||
protected secondaryButtonText(): { key: string } | undefined {
|
||||
return this.forceSetPasswordReason === ForceSetPasswordReason.AdminForcePasswordReset ||
|
||||
this.forceSetPasswordReason === ForceSetPasswordReason.WeakMasterPassword
|
||||
? { key: "logOut" }
|
||||
: undefined;
|
||||
}
|
||||
}
|
||||
@@ -41,7 +41,7 @@ describe("DefaultChangePasswordService", () => {
|
||||
newServerMasterKeyHash: "newServerMasterKeyHash",
|
||||
newLocalMasterKeyHash: "newLocalMasterKeyHash",
|
||||
|
||||
kdfConfig: new PBKDF2KdfConfig(),
|
||||
kdf: new PBKDF2KdfConfig(),
|
||||
};
|
||||
|
||||
const decryptedUserKey = new SymmetricCryptoKey(new Uint8Array(64)) as UserKey;
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import { firstValueFrom } from "rxjs";
|
||||
|
||||
// This import has been flagged as unallowed for this class. It may be involved in a circular dependency loop.
|
||||
// eslint-disable-next-line no-restricted-imports
|
||||
import { PasswordInputResult } from "@bitwarden/auth/angular";
|
||||
@@ -5,10 +7,8 @@ import { Account } from "@bitwarden/common/auth/abstractions/account.service";
|
||||
import { MasterPasswordApiService } from "@bitwarden/common/auth/abstractions/master-password-api.service.abstraction";
|
||||
import { PasswordRequest } from "@bitwarden/common/auth/models/request/password.request";
|
||||
import { UpdateTempPasswordRequest } from "@bitwarden/common/auth/models/request/update-temp-password.request";
|
||||
import { EncString } from "@bitwarden/common/key-management/crypto/models/enc-string";
|
||||
import { InternalMasterPasswordServiceAbstraction } from "@bitwarden/common/key-management/master-password/abstractions/master-password.service.abstraction";
|
||||
import { UserId } from "@bitwarden/common/types/guid";
|
||||
import { UserKey } from "@bitwarden/common/types/key";
|
||||
import { KeyService } from "@bitwarden/key-management";
|
||||
|
||||
import { ChangePasswordService } from "./change-password.service.abstraction";
|
||||
@@ -18,7 +18,7 @@ export class DefaultChangePasswordService implements ChangePasswordService {
|
||||
protected keyService: KeyService,
|
||||
protected masterPasswordApiService: MasterPasswordApiService,
|
||||
protected masterPasswordService: InternalMasterPasswordServiceAbstraction,
|
||||
) {}
|
||||
) { }
|
||||
|
||||
async rotateUserKeyMasterPasswordAndEncryptedData(
|
||||
currentPassword: string,
|
||||
@@ -29,60 +29,20 @@ export class DefaultChangePasswordService implements ChangePasswordService {
|
||||
throw new Error("rotateUserKeyMasterPasswordAndEncryptedData() is only implemented in Web");
|
||||
}
|
||||
|
||||
private async preparePasswordChange(
|
||||
passwordInputResult: PasswordInputResult,
|
||||
userId: UserId | null,
|
||||
request: PasswordRequest | UpdateTempPasswordRequest,
|
||||
): Promise<[UserKey, EncString]> {
|
||||
if (!userId) {
|
||||
throw new Error("userId not found");
|
||||
}
|
||||
if (
|
||||
!passwordInputResult.currentMasterKey ||
|
||||
!passwordInputResult.currentServerMasterKeyHash ||
|
||||
!passwordInputResult.newMasterKey ||
|
||||
!passwordInputResult.newServerMasterKeyHash ||
|
||||
passwordInputResult.newPasswordHint == null
|
||||
) {
|
||||
throw new Error("invalid PasswordInputResult credentials, could not change password");
|
||||
}
|
||||
|
||||
const decryptedUserKey = await this.masterPasswordService.decryptUserKeyWithMasterKey(
|
||||
passwordInputResult.currentMasterKey,
|
||||
userId,
|
||||
);
|
||||
|
||||
if (decryptedUserKey == null) {
|
||||
throw new Error("Could not decrypt user key");
|
||||
}
|
||||
|
||||
const newKeyValue = await this.keyService.encryptUserKeyWithMasterKey(
|
||||
passwordInputResult.newMasterKey,
|
||||
decryptedUserKey,
|
||||
);
|
||||
|
||||
if (request instanceof PasswordRequest) {
|
||||
request.masterPasswordHash = passwordInputResult.currentServerMasterKeyHash;
|
||||
request.newMasterPasswordHash = passwordInputResult.newServerMasterKeyHash;
|
||||
request.masterPasswordHint = passwordInputResult.newPasswordHint;
|
||||
} else if (request instanceof UpdateTempPasswordRequest) {
|
||||
request.newMasterPasswordHash = passwordInputResult.newServerMasterKeyHash;
|
||||
request.masterPasswordHint = passwordInputResult.newPasswordHint;
|
||||
}
|
||||
|
||||
return newKeyValue;
|
||||
}
|
||||
|
||||
async changePassword(passwordInputResult: PasswordInputResult, userId: UserId | null) {
|
||||
const request = new PasswordRequest();
|
||||
const userKey = await firstValueFrom(this.keyService.userKey$(userId));
|
||||
if (userKey == null) {
|
||||
throw new Error("Can't find UserKey");
|
||||
}
|
||||
const salt = await firstValueFrom(this.masterPasswordService.saltForAccount$(userId));
|
||||
const authenticationData = await this.masterPasswordService.makeMasterPasswordAuthenticationData(passwordInputResult.newPassword, passwordInputResult.kdf, salt);
|
||||
const unlockData = await this.masterPasswordService.makeMasterPasswordUnlockData(passwordInputResult.newPassword, passwordInputResult.kdf, passwordInputResult.salt, userKey);
|
||||
|
||||
const newMasterKeyEncryptedUserKey = await this.preparePasswordChange(
|
||||
passwordInputResult,
|
||||
userId,
|
||||
request,
|
||||
);
|
||||
const request = new PasswordRequest(authenticationData, unlockData);
|
||||
|
||||
request.key = newMasterKeyEncryptedUserKey[1].encryptedString as string;
|
||||
const oldAuthenticationData = await this.masterPasswordService.makeMasterPasswordAuthenticationData(passwordInputResult.currentPassword, passwordInputResult.kdf, salt);
|
||||
request.masterPasswordHash = oldAuthenticationData.masterPasswordAuthenticationHash;
|
||||
request.masterPasswordHint = passwordInputResult.newPasswordHint;
|
||||
|
||||
try {
|
||||
await this.masterPasswordApiService.postPassword(request);
|
||||
@@ -92,15 +52,16 @@ export class DefaultChangePasswordService implements ChangePasswordService {
|
||||
}
|
||||
|
||||
async changePasswordForAccountRecovery(passwordInputResult: PasswordInputResult, userId: UserId) {
|
||||
const request = new UpdateTempPasswordRequest();
|
||||
const userKey = await firstValueFrom(this.keyService.userKey$(userId));
|
||||
if (userKey == null) {
|
||||
throw new Error("Can't find UserKey");
|
||||
}
|
||||
const salt = await firstValueFrom(this.masterPasswordService.saltForAccount$(userId));
|
||||
const authenticationData = await this.masterPasswordService.makeMasterPasswordAuthenticationData(passwordInputResult.newPassword, passwordInputResult.kdf, salt);
|
||||
const unlockData = await this.masterPasswordService.makeMasterPasswordUnlockData(passwordInputResult.newPassword, passwordInputResult.kdf, passwordInputResult.salt, userKey);
|
||||
|
||||
const newMasterKeyEncryptedUserKey = await this.preparePasswordChange(
|
||||
passwordInputResult,
|
||||
userId,
|
||||
request,
|
||||
);
|
||||
|
||||
request.key = newMasterKeyEncryptedUserKey[1].encryptedString as string;
|
||||
const request = new UpdateTempPasswordRequest(authenticationData, unlockData);
|
||||
request.masterPasswordHint = passwordInputResult.newPasswordHint;
|
||||
|
||||
try {
|
||||
// TODO: PM-23047 will look to consolidate this into the change password endpoint.
|
||||
|
||||
@@ -1,3 +1,2 @@
|
||||
export * from "./change-password.component";
|
||||
export * from "./change-password.service.abstraction";
|
||||
export * from "./default-change-password.service";
|
||||
|
||||
@@ -18,8 +18,10 @@ import { UpdateTdeOffboardingPasswordRequest } from "@bitwarden/common/auth/mode
|
||||
import { EncryptService } from "@bitwarden/common/key-management/crypto/abstractions/encrypt.service";
|
||||
import { EncString } from "@bitwarden/common/key-management/crypto/models/enc-string";
|
||||
import { InternalMasterPasswordServiceAbstraction } from "@bitwarden/common/key-management/master-password/abstractions/master-password.service.abstraction";
|
||||
import { MasterPasswordAuthenticationData } from "@bitwarden/common/key-management/master-password/types/master-password.types";
|
||||
import { KeysRequest } from "@bitwarden/common/models/request/keys.request";
|
||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||
import { HashPurpose } from "@bitwarden/common/platform/enums";
|
||||
import { Utils } from "@bitwarden/common/platform/misc/utils";
|
||||
import { UserId } from "@bitwarden/common/types/guid";
|
||||
import { MasterKey, UserKey } from "@bitwarden/common/types/key";
|
||||
@@ -44,7 +46,7 @@ export class DefaultSetInitialPasswordService implements SetInitialPasswordServi
|
||||
protected organizationApiService: OrganizationApiServiceAbstraction,
|
||||
protected organizationUserApiService: OrganizationUserApiService,
|
||||
protected userDecryptionOptionsService: InternalUserDecryptionOptionsServiceAbstraction,
|
||||
) {}
|
||||
) { }
|
||||
|
||||
async setInitialPassword(
|
||||
credentials: SetInitialPasswordCredentials,
|
||||
@@ -52,11 +54,7 @@ export class DefaultSetInitialPasswordService implements SetInitialPasswordServi
|
||||
userId: UserId,
|
||||
): Promise<void> {
|
||||
const {
|
||||
newMasterKey,
|
||||
newServerMasterKeyHash,
|
||||
newLocalMasterKeyHash,
|
||||
newPasswordHint,
|
||||
kdfConfig,
|
||||
orgSsoIdentifier,
|
||||
orgId,
|
||||
resetPasswordAutoEnroll,
|
||||
@@ -74,13 +72,18 @@ export class DefaultSetInitialPasswordService implements SetInitialPasswordServi
|
||||
throw new Error("userType not found. Could not set password.");
|
||||
}
|
||||
|
||||
const masterKeyEncryptedUserKey = await this.makeMasterKeyEncryptedUserKey(
|
||||
newMasterKey,
|
||||
userId,
|
||||
const userKey = await this.keyService.makeUserKeyV1Raw();
|
||||
const authenticationData = await this.masterPasswordService.makeMasterPasswordAuthenticationData(
|
||||
credentials.initialPassword,
|
||||
credentials.kdf,
|
||||
credentials.salt,
|
||||
);
|
||||
const unlockData = await this.masterPasswordService.makeMasterPasswordUnlockData(
|
||||
credentials.initialPassword,
|
||||
credentials.kdf,
|
||||
credentials.salt,
|
||||
userKey,
|
||||
);
|
||||
if (masterKeyEncryptedUserKey == null || !masterKeyEncryptedUserKey[1].encryptedString) {
|
||||
throw new Error("masterKeyEncryptedUserKey not found. Could not set password.");
|
||||
}
|
||||
|
||||
let keyPair: [string, EncString] | null = null;
|
||||
let keysRequest: KeysRequest | null = null;
|
||||
@@ -113,12 +116,12 @@ export class DefaultSetInitialPasswordService implements SetInitialPasswordServi
|
||||
existingUserPublicKeyB64,
|
||||
await this.encryptService.wrapDecapsulationKey(
|
||||
existingUserPrivateKey,
|
||||
masterKeyEncryptedUserKey[0],
|
||||
userKey,
|
||||
),
|
||||
];
|
||||
} else {
|
||||
// New key pair
|
||||
keyPair = await this.keyService.makeKeyPair(masterKeyEncryptedUserKey[0]);
|
||||
keyPair = await this.keyService.makeKeyPair(userKey);
|
||||
}
|
||||
|
||||
if (keyPair == null) {
|
||||
@@ -132,13 +135,11 @@ export class DefaultSetInitialPasswordService implements SetInitialPasswordServi
|
||||
}
|
||||
|
||||
const request = new SetPasswordRequest(
|
||||
newServerMasterKeyHash,
|
||||
masterKeyEncryptedUserKey[1].encryptedString,
|
||||
authenticationData,
|
||||
unlockData,
|
||||
newPasswordHint,
|
||||
orgSsoIdentifier,
|
||||
keysRequest,
|
||||
kdfConfig.kdfType,
|
||||
kdfConfig.iterations,
|
||||
);
|
||||
|
||||
await this.masterPasswordApiService.setPassword(request);
|
||||
@@ -147,10 +148,18 @@ export class DefaultSetInitialPasswordService implements SetInitialPasswordServi
|
||||
await this.masterPasswordService.setForceSetPasswordReason(ForceSetPasswordReason.None, userId);
|
||||
|
||||
// User now has a password so update account decryption options in state
|
||||
// TODO: REMOVE when masterKey is no longer used
|
||||
const masterKey = await this.keyService.makeMasterKey(credentials.initialPassword, credentials.salt, credentials.kdf);
|
||||
const localMasterKeyHash = await this.keyService.hashMasterKey(
|
||||
credentials.initialPassword,
|
||||
masterKey,
|
||||
HashPurpose.LocalAuthorization
|
||||
) as string;
|
||||
await this.masterPasswordService.setMasterKeyHash(localMasterKeyHash, userId);
|
||||
await this.updateAccountDecryptionProperties(
|
||||
newMasterKey,
|
||||
kdfConfig,
|
||||
masterKeyEncryptedUserKey,
|
||||
masterKey,
|
||||
credentials.kdf,
|
||||
userKey,
|
||||
userId,
|
||||
);
|
||||
|
||||
@@ -165,34 +174,17 @@ export class DefaultSetInitialPasswordService implements SetInitialPasswordServi
|
||||
await this.keyService.setPrivateKey(keyPair[1].encryptedString, userId);
|
||||
}
|
||||
|
||||
await this.masterPasswordService.setMasterKeyHash(newLocalMasterKeyHash, userId);
|
||||
|
||||
if (resetPasswordAutoEnroll) {
|
||||
await this.handleResetPasswordAutoEnroll(newServerMasterKeyHash, orgId, userId);
|
||||
await this.handleResetPasswordAutoEnroll(authenticationData, orgId, userId);
|
||||
}
|
||||
}
|
||||
|
||||
private async makeMasterKeyEncryptedUserKey(
|
||||
masterKey: MasterKey,
|
||||
userId: UserId,
|
||||
): Promise<[UserKey, EncString]> {
|
||||
let masterKeyEncryptedUserKey: [UserKey, EncString] | null = null;
|
||||
|
||||
const userKey = await firstValueFrom(this.keyService.userKey$(userId));
|
||||
|
||||
if (userKey == null) {
|
||||
masterKeyEncryptedUserKey = await this.keyService.makeUserKey(masterKey);
|
||||
} else {
|
||||
masterKeyEncryptedUserKey = await this.keyService.encryptUserKeyWithMasterKey(masterKey);
|
||||
}
|
||||
|
||||
return masterKeyEncryptedUserKey;
|
||||
}
|
||||
|
||||
private async updateAccountDecryptionProperties(
|
||||
/** @deprecated */
|
||||
masterKey: MasterKey,
|
||||
kdfConfig: KdfConfig,
|
||||
masterKeyEncryptedUserKey: [UserKey, EncString],
|
||||
userKey: UserKey,
|
||||
userId: UserId,
|
||||
) {
|
||||
const userDecryptionOpts = await firstValueFrom(
|
||||
@@ -201,12 +193,13 @@ export class DefaultSetInitialPasswordService implements SetInitialPasswordServi
|
||||
userDecryptionOpts.hasMasterPassword = true;
|
||||
await this.userDecryptionOptionsService.setUserDecryptionOptions(userDecryptionOpts);
|
||||
await this.kdfConfigService.setKdfConfig(userId, kdfConfig);
|
||||
// TODO: Remove when masterKey is no longer used
|
||||
await this.masterPasswordService.setMasterKey(masterKey, userId);
|
||||
await this.keyService.setUserKey(masterKeyEncryptedUserKey[0], userId);
|
||||
await this.keyService.setUserKey(userKey, userId);
|
||||
}
|
||||
|
||||
private async handleResetPasswordAutoEnroll(
|
||||
masterKeyHash: string,
|
||||
authenticationData: MasterPasswordAuthenticationData,
|
||||
orgId: string,
|
||||
userId: UserId,
|
||||
) {
|
||||
@@ -238,7 +231,7 @@ export class DefaultSetInitialPasswordService implements SetInitialPasswordServi
|
||||
}
|
||||
|
||||
const enrollmentRequest = new OrganizationUserResetPasswordEnrollmentRequest();
|
||||
enrollmentRequest.masterPasswordHash = masterKeyHash;
|
||||
enrollmentRequest.masterPasswordHash = authenticationData.masterPasswordAuthenticationHash;
|
||||
enrollmentRequest.resetPasswordKey = orgPublicKeyEncryptedUserKey.encryptedString;
|
||||
|
||||
await this.organizationUserApiService.putOrganizationUserResetPasswordEnrollment(
|
||||
@@ -252,7 +245,7 @@ export class DefaultSetInitialPasswordService implements SetInitialPasswordServi
|
||||
credentials: SetInitialPasswordTdeOffboardingCredentials,
|
||||
userId: UserId,
|
||||
) {
|
||||
const { newMasterKey, newServerMasterKeyHash, newPasswordHint } = credentials;
|
||||
const { initialPassword, kdf, salt, newPasswordHint } = credentials;
|
||||
for (const [key, value] of Object.entries(credentials)) {
|
||||
if (value == null) {
|
||||
throw new Error(`${key} not found. Could not set password.`);
|
||||
@@ -262,24 +255,24 @@ export class DefaultSetInitialPasswordService implements SetInitialPasswordServi
|
||||
if (userId == null) {
|
||||
throw new Error("userId not found. Could not set password.");
|
||||
}
|
||||
|
||||
const userKey = await firstValueFrom(this.keyService.userKey$(userId));
|
||||
if (userKey == null) {
|
||||
throw new Error("userKey not found. Could not set password.");
|
||||
}
|
||||
|
||||
const newMasterKeyEncryptedUserKey = await this.keyService.encryptUserKeyWithMasterKey(
|
||||
newMasterKey,
|
||||
const authenticationData = await this.masterPasswordService.makeMasterPasswordAuthenticationData(
|
||||
initialPassword,
|
||||
kdf,
|
||||
salt,
|
||||
);
|
||||
const unlockData = await this.masterPasswordService.makeMasterPasswordUnlockData(
|
||||
initialPassword,
|
||||
kdf,
|
||||
salt,
|
||||
userKey,
|
||||
);
|
||||
|
||||
if (!newMasterKeyEncryptedUserKey[1].encryptedString) {
|
||||
throw new Error("newMasterKeyEncryptedUserKey not found. Could not set password.");
|
||||
}
|
||||
|
||||
const request = new UpdateTdeOffboardingPasswordRequest();
|
||||
request.key = newMasterKeyEncryptedUserKey[1].encryptedString;
|
||||
request.newMasterPasswordHash = newServerMasterKeyHash;
|
||||
const request = new UpdateTdeOffboardingPasswordRequest(authenticationData, unlockData);
|
||||
request.masterPasswordHint = newPasswordHint;
|
||||
|
||||
await this.masterPasswordApiService.putUpdateTdeOffboardingPassword(request);
|
||||
|
||||
@@ -157,8 +157,6 @@ describe("DefaultSetInitialPasswordService", () => {
|
||||
credentials.newPasswordHint,
|
||||
credentials.orgSsoIdentifier,
|
||||
keysRequest,
|
||||
credentials.kdfConfig.kdfType,
|
||||
credentials.kdfConfig.iterations,
|
||||
);
|
||||
|
||||
enrollmentRequest = new OrganizationUserResetPasswordEnrollmentRequest();
|
||||
|
||||
@@ -85,7 +85,7 @@ export class SetInitialPasswordComponent implements OnInit {
|
||||
private syncService: SyncService,
|
||||
private toastService: ToastService,
|
||||
private validationService: ValidationService,
|
||||
) {}
|
||||
) { }
|
||||
|
||||
async ngOnInit() {
|
||||
await this.syncService.fullSync(true);
|
||||
@@ -209,10 +209,9 @@ export class SetInitialPasswordComponent implements OnInit {
|
||||
|
||||
private async setInitialPassword(passwordInputResult: PasswordInputResult) {
|
||||
const ctx = "Could not set initial password.";
|
||||
assertTruthy(passwordInputResult.newMasterKey, "newMasterKey", ctx);
|
||||
assertTruthy(passwordInputResult.newServerMasterKeyHash, "newServerMasterKeyHash", ctx);
|
||||
assertTruthy(passwordInputResult.newLocalMasterKeyHash, "newLocalMasterKeyHash", ctx);
|
||||
assertTruthy(passwordInputResult.kdfConfig, "kdfConfig", ctx);
|
||||
assertTruthy(passwordInputResult.newPassword, "newPassword", ctx);
|
||||
assertTruthy(passwordInputResult.kdf, "kdf", ctx);
|
||||
assertTruthy(passwordInputResult.salt, "salt", ctx);
|
||||
assertTruthy(this.orgSsoIdentifier, "orgSsoIdentifier", ctx);
|
||||
assertTruthy(this.orgId, "orgId", ctx);
|
||||
assertTruthy(this.userType, "userType", ctx);
|
||||
@@ -222,11 +221,10 @@ export class SetInitialPasswordComponent implements OnInit {
|
||||
|
||||
try {
|
||||
const credentials: SetInitialPasswordCredentials = {
|
||||
newMasterKey: passwordInputResult.newMasterKey,
|
||||
newServerMasterKeyHash: passwordInputResult.newServerMasterKeyHash,
|
||||
newLocalMasterKeyHash: passwordInputResult.newLocalMasterKeyHash,
|
||||
initialPassword: passwordInputResult.newPassword,
|
||||
kdf: passwordInputResult.kdf,
|
||||
salt: passwordInputResult.salt,
|
||||
newPasswordHint: passwordInputResult.newPasswordHint,
|
||||
kdfConfig: passwordInputResult.kdfConfig,
|
||||
orgSsoIdentifier: this.orgSsoIdentifier,
|
||||
orgId: this.orgId,
|
||||
resetPasswordAutoEnroll: this.resetPasswordAutoEnroll,
|
||||
@@ -251,15 +249,17 @@ export class SetInitialPasswordComponent implements OnInit {
|
||||
|
||||
private async setInitialPasswordTdeOffboarding(passwordInputResult: PasswordInputResult) {
|
||||
const ctx = "Could not set initial password.";
|
||||
assertTruthy(passwordInputResult.newMasterKey, "newMasterKey", ctx);
|
||||
assertTruthy(passwordInputResult.newServerMasterKeyHash, "newServerMasterKeyHash", ctx);
|
||||
assertTruthy(passwordInputResult.newPassword, "newPassword", ctx);
|
||||
assertTruthy(passwordInputResult.kdf, "kdf", ctx);
|
||||
assertTruthy(passwordInputResult.salt, "salt", ctx);
|
||||
assertTruthy(this.userId, "userId", ctx);
|
||||
assertNonNullish(passwordInputResult.newPasswordHint, "newPasswordHint", ctx); // can have an empty string as a valid value, so check non-nullish
|
||||
|
||||
try {
|
||||
const credentials: SetInitialPasswordTdeOffboardingCredentials = {
|
||||
newMasterKey: passwordInputResult.newMasterKey,
|
||||
newServerMasterKeyHash: passwordInputResult.newServerMasterKeyHash,
|
||||
initialPassword: passwordInputResult.newPassword,
|
||||
kdf: passwordInputResult.kdf,
|
||||
salt: passwordInputResult.salt,
|
||||
newPasswordHint: passwordInputResult.newPasswordHint,
|
||||
};
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { MasterPasswordSalt } from "@bitwarden/common/key-management/master-password/types/master-password.types";
|
||||
import { UserId } from "@bitwarden/common/types/guid";
|
||||
import { MasterKey } from "@bitwarden/common/types/key";
|
||||
import { KdfConfig } from "@bitwarden/key-management";
|
||||
|
||||
export const _SetInitialPasswordUserType = {
|
||||
@@ -42,19 +42,21 @@ export const SetInitialPasswordUserType: Readonly<{
|
||||
}> = Object.freeze(_SetInitialPasswordUserType);
|
||||
|
||||
export interface SetInitialPasswordCredentials {
|
||||
newMasterKey: MasterKey;
|
||||
newServerMasterKeyHash: string;
|
||||
newLocalMasterKeyHash: string;
|
||||
initialPassword: string,
|
||||
kdf: KdfConfig,
|
||||
salt: MasterPasswordSalt,
|
||||
|
||||
newPasswordHint: string;
|
||||
kdfConfig: KdfConfig;
|
||||
orgSsoIdentifier: string;
|
||||
orgId: string;
|
||||
resetPasswordAutoEnroll: boolean;
|
||||
}
|
||||
|
||||
export interface SetInitialPasswordTdeOffboardingCredentials {
|
||||
newMasterKey: MasterKey;
|
||||
newServerMasterKeyHash: string;
|
||||
initialPassword: string;
|
||||
kdf: KdfConfig;
|
||||
salt: MasterPasswordSalt;
|
||||
|
||||
newPasswordHint: string;
|
||||
}
|
||||
|
||||
|
||||
@@ -423,11 +423,11 @@ const safeProviders: SafeProvider[] = [
|
||||
provide: LOGOUT_CALLBACK,
|
||||
useFactory:
|
||||
(messagingService: MessagingServiceAbstraction) =>
|
||||
async (logoutReason: LogoutReason, userId?: string) => {
|
||||
return Promise.resolve(
|
||||
messagingService.send("logout", { logoutReason: logoutReason, userId: userId }),
|
||||
);
|
||||
},
|
||||
async (logoutReason: LogoutReason, userId?: string) => {
|
||||
return Promise.resolve(
|
||||
messagingService.send("logout", { logoutReason: logoutReason, userId: userId }),
|
||||
);
|
||||
},
|
||||
deps: [MessagingServiceAbstraction],
|
||||
}),
|
||||
safeProvider({
|
||||
@@ -1024,6 +1024,7 @@ const safeProviders: SafeProvider[] = [
|
||||
EncryptService,
|
||||
LogService,
|
||||
CryptoFunctionServiceAbstraction,
|
||||
AccountServiceAbstraction
|
||||
],
|
||||
}),
|
||||
safeProvider({
|
||||
@@ -1614,4 +1615,4 @@ const safeProviders: SafeProvider[] = [
|
||||
// Do not register your dependency here! Add it to the typesafeProviders array using the helper function
|
||||
providers: safeProviders,
|
||||
})
|
||||
export class JslibServicesModule {}
|
||||
export class JslibServicesModule { }
|
||||
|
||||
Reference in New Issue
Block a user