1
0
mirror of https://github.com/bitwarden/browser synced 2026-01-31 00:33:33 +00:00

[PM-27086 TDE Offboarding] Use new KM APIs; create new methods

This commit is contained in:
rr-bw
2026-01-04 21:12:45 -08:00
parent 4593017377
commit 0929b1b276
4 changed files with 133 additions and 2 deletions

View File

@@ -19,7 +19,11 @@ import { AccountCryptographicStateService } from "@bitwarden/common/key-manageme
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 { MasterPasswordSalt } from "@bitwarden/common/key-management/master-password/types/master-password.types";
import {
MasterPasswordAuthenticationData,
MasterPasswordSalt,
MasterPasswordUnlockData,
} 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 { Utils } from "@bitwarden/common/platform/misc/utils";
@@ -32,6 +36,7 @@ import {
SetInitialPasswordCredentials,
SetInitialPasswordUserType,
SetInitialPasswordTdeOffboardingCredentialsOld,
SetInitialPasswordTdeOffboardingCredentials,
} from "./set-initial-password.service.abstraction";
export class DefaultSetInitialPasswordService implements SetInitialPasswordService {
@@ -362,4 +367,52 @@ export class DefaultSetInitialPasswordService implements SetInitialPasswordServi
// Clear force set password reason to allow navigation back to vault.
await this.masterPasswordService.setForceSetPasswordReason(ForceSetPasswordReason.None, userId);
}
async setInitialPasswordTdeOffboarding(
credentials: SetInitialPasswordTdeOffboardingCredentials,
userId: UserId,
) {
const { newPassword, kdfConfig, salt, newPasswordHint } = credentials;
for (const [key, value] of Object.entries(credentials)) {
if (value == null) {
throw new Error(`${key} not found. Could not set password.`);
}
}
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 authenticationData: MasterPasswordAuthenticationData =
await this.masterPasswordService.makeMasterPasswordAuthenticationData(
newPassword,
kdfConfig,
salt,
);
const unlockData: MasterPasswordUnlockData =
await this.masterPasswordService.makeMasterPasswordUnlockData(
newPassword,
kdfConfig,
salt,
userKey,
);
const request = UpdateTdeOffboardingPasswordRequest.newConstructorWithHint(
authenticationData,
unlockData,
newPasswordHint,
);
await this.masterPasswordApiService.putUpdateTdeOffboardingPassword(request);
// Clear force set password reason to allow navigation back to vault.
await this.masterPasswordService.setForceSetPasswordReason(ForceSetPasswordReason.None, userId);
}
}

View File

@@ -43,6 +43,7 @@ import { I18nPipe } from "@bitwarden/ui-common";
import {
SetInitialPasswordCredentials,
SetInitialPasswordService,
SetInitialPasswordTdeOffboardingCredentials,
SetInitialPasswordTdeOffboardingCredentialsOld,
SetInitialPasswordUserType,
} from "./set-initial-password.service.abstraction";
@@ -276,7 +277,7 @@ export class SetInitialPasswordComponent implements OnInit {
case SetInitialPasswordUserType.OFFBOARDED_TDE_ORG_USER:
// Remove wrapping "if" check and early return in PM-28143
if (passwordInputResult.newApisFlagEnabled) {
// ...
await this.setInitialPasswordTdeOffboarding(passwordInputResult);
return;
}
@@ -340,6 +341,42 @@ export class SetInitialPasswordComponent implements OnInit {
}
}
private async setInitialPasswordTdeOffboarding(passwordInputResult: PasswordInputResult) {
const ctx = "Could not set initial password.";
assertTruthy(passwordInputResult.newPassword, "newPassword", ctx);
assertTruthy(passwordInputResult.kdfConfig, "kdfConfig", ctx);
assertTruthy(passwordInputResult.salt, "salt", ctx);
assertNonNullish(passwordInputResult.newPasswordHint, "newPasswordHint", ctx); // can have an empty string as a valid value, so check non-nullish
assertTruthy(this.userId, "userId", ctx);
try {
const credentials: SetInitialPasswordTdeOffboardingCredentials = {
newPassword: passwordInputResult.newPassword,
kdfConfig: passwordInputResult.kdfConfig,
salt: passwordInputResult.salt,
newPasswordHint: passwordInputResult.newPasswordHint,
};
await this.setInitialPasswordService.setInitialPasswordTdeOffboarding(
credentials,
this.userId,
);
this.showSuccessToastByUserType();
await this.logoutService.logout(this.userId);
// navigate to root so redirect guard can properly route next active user or null user to correct page
await this.router.navigate(["/"]);
} catch (e) {
this.logService.error("Error setting initial password during TDE offboarding", e);
this.validationService.showError(e);
} finally {
this.submitting = false;
}
}
/**
* @deprecated To be removed in PM-28143
*/

View File

@@ -64,6 +64,13 @@ export interface SetInitialPasswordTdeOffboardingCredentialsOld {
newPasswordHint: string;
}
export interface SetInitialPasswordTdeOffboardingCredentials {
newPassword: string;
kdfConfig: KdfConfig;
salt: MasterPasswordSalt;
newPasswordHint: string;
}
/**
* Handles setting an initial password for an existing authed user.
*
@@ -102,4 +109,17 @@ export abstract class SetInitialPasswordService {
credentials: SetInitialPasswordTdeOffboardingCredentialsOld,
userId: UserId,
) => Promise<void>;
/**
* Sets an initial password for a user who logs in after their org offboarded from
* trusted device encryption and is now a master-password-encryption org:
* - {@link SetInitialPasswordUserType.OFFBOARDED_TDE_ORG_USER}
*
* @param passwordInputResult credentials object received from the `InputPasswordComponent`
* @param userId the account `userId`
*/
abstract setInitialPasswordTdeOffboarding: (
credentials: SetInitialPasswordTdeOffboardingCredentials,
userId: UserId,
) => Promise<void>;
}

View File

@@ -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 UpdateTdeOffboardingPasswordRequest 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,
): UpdateTdeOffboardingPasswordRequest {
const request = OrganizationUserResetPasswordRequest.newConstructor(
authenticationData,
unlockData,
) as UpdateTdeOffboardingPasswordRequest;
request.masterPasswordHint = masterPasswordHint;
return request;
}
}