mirror of
https://github.com/bitwarden/browser
synced 2026-02-22 20:34:04 +00:00
[PM-27086 Change Password] Refactor ChangePasswordService methods and add new constructor to request model
This commit is contained in:
@@ -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";
|
||||
@@ -7,6 +9,10 @@ import { PasswordRequest } from "@bitwarden/common/auth/models/request/password.
|
||||
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 {
|
||||
MasterPasswordAuthenticationData,
|
||||
MasterPasswordUnlockData,
|
||||
} from "@bitwarden/common/key-management/master-password/types/master-password.types";
|
||||
import { UserId } from "@bitwarden/common/types/guid";
|
||||
import { UserKey } from "@bitwarden/common/types/key";
|
||||
import { KeyService } from "@bitwarden/key-management";
|
||||
@@ -74,6 +80,15 @@ export class DefaultChangePasswordService implements ChangePasswordService {
|
||||
}
|
||||
|
||||
async changePassword(passwordInputResult: PasswordInputResult, userId: UserId | null) {
|
||||
if (passwordInputResult.newApisWithInputPasswordFlagEnabled) {
|
||||
const { newAuthenticationData, newUnlockData } =
|
||||
await this.confirmCurrentPasswordAndMakeNewAuthAndUnlockData(passwordInputResult, userId);
|
||||
|
||||
const request = PasswordRequest.newConstructor(newAuthenticationData, newUnlockData);
|
||||
await this.masterPasswordApiService.postPassword(request);
|
||||
return; // EARLY RETURN for flagged logic
|
||||
}
|
||||
|
||||
const request = new PasswordRequest();
|
||||
|
||||
const newMasterKeyEncryptedUserKey = await this.preparePasswordChange(
|
||||
@@ -92,6 +107,19 @@ export class DefaultChangePasswordService implements ChangePasswordService {
|
||||
}
|
||||
|
||||
async changePasswordForAccountRecovery(passwordInputResult: PasswordInputResult, userId: UserId) {
|
||||
if (passwordInputResult.newApisWithInputPasswordFlagEnabled) {
|
||||
const { newAuthenticationData, newUnlockData } =
|
||||
await this.confirmCurrentPasswordAndMakeNewAuthAndUnlockData(passwordInputResult, userId);
|
||||
|
||||
const request = UpdateTempPasswordRequest.newConstructorWithHint(
|
||||
newAuthenticationData,
|
||||
newUnlockData,
|
||||
passwordInputResult.newPasswordHint,
|
||||
);
|
||||
await this.masterPasswordApiService.putUpdateTempPassword(request);
|
||||
return; // EARLY RETURN for flagged logic
|
||||
}
|
||||
|
||||
const request = new UpdateTempPasswordRequest();
|
||||
|
||||
const newMasterKeyEncryptedUserKey = await this.preparePasswordChange(
|
||||
@@ -109,4 +137,52 @@ export class DefaultChangePasswordService implements ChangePasswordService {
|
||||
throw new Error("Could not change password");
|
||||
}
|
||||
}
|
||||
|
||||
private async confirmCurrentPasswordAndMakeNewAuthAndUnlockData(
|
||||
passwordInputResult: PasswordInputResult,
|
||||
userId: UserId | null,
|
||||
): Promise<{
|
||||
newAuthenticationData: MasterPasswordAuthenticationData;
|
||||
newUnlockData: MasterPasswordUnlockData;
|
||||
}> {
|
||||
if (
|
||||
!passwordInputResult.currentPassword ||
|
||||
!passwordInputResult.newPassword ||
|
||||
!passwordInputResult.salt ||
|
||||
passwordInputResult.kdfConfig == null ||
|
||||
passwordInputResult.newPasswordHint == null
|
||||
) {
|
||||
throw new Error("invalid PasswordInputResult credentials, could not change password");
|
||||
}
|
||||
|
||||
// Confirm that the current password + unlock data can decrypt the user key (i.e the current password is valid)
|
||||
const currentUnlockData = await firstValueFrom(
|
||||
this.masterPasswordService.masterPasswordUnlockData$(userId),
|
||||
);
|
||||
const userKey = await this.masterPasswordService.unwrapUserKeyFromMasterPasswordUnlockData(
|
||||
passwordInputResult.currentPassword,
|
||||
currentUnlockData,
|
||||
);
|
||||
if (userKey == null) {
|
||||
throw new Error("Could not decrypt user key");
|
||||
}
|
||||
|
||||
// Create new authentication data with the new password (includes a new masterPasswordAuthenticationHash)
|
||||
const newAuthenticationData =
|
||||
await this.masterPasswordService.makeMasterPasswordAuthenticationData(
|
||||
passwordInputResult.newPassword,
|
||||
passwordInputResult.kdfConfig,
|
||||
passwordInputResult.salt,
|
||||
);
|
||||
|
||||
// Create new unlock data with the new password (includes a new masterKeyWrappedUserKey)
|
||||
const newUnlockData = await this.masterPasswordService.makeMasterPasswordUnlockData(
|
||||
passwordInputResult.newPassword,
|
||||
passwordInputResult.kdfConfig,
|
||||
passwordInputResult.salt,
|
||||
userKey,
|
||||
);
|
||||
|
||||
return { newAuthenticationData, newUnlockData };
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,28 @@
|
||||
// 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 { OrganizationUserResetPasswordRequest } from "@bitwarden/admin-console/common";
|
||||
import {
|
||||
MasterPasswordAuthenticationData,
|
||||
MasterPasswordUnlockData,
|
||||
} from "@bitwarden/common/key-management/master-password/types/master-password.types";
|
||||
|
||||
export class UpdateTempPasswordRequest extends OrganizationUserResetPasswordRequest {
|
||||
masterPasswordHint: string;
|
||||
|
||||
// This will eventually be changed to be an actual constructor, once all callers are updated.
|
||||
// The body of this request will be changed to carry the authentication data and unlock data.
|
||||
// https://bitwarden.atlassian.net/browse/PM-23234
|
||||
static newConstructorWithHint(
|
||||
authenticationData: MasterPasswordAuthenticationData,
|
||||
unlockData: MasterPasswordUnlockData,
|
||||
masterPasswordHint: string,
|
||||
): UpdateTempPasswordRequest {
|
||||
const request = OrganizationUserResetPasswordRequest.newConstructor(
|
||||
authenticationData,
|
||||
unlockData,
|
||||
) as UpdateTempPasswordRequest;
|
||||
|
||||
request.masterPasswordHint = masterPasswordHint;
|
||||
return request;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user