1
0
mirror of https://github.com/bitwarden/browser synced 2025-12-11 22:03:36 +00:00

feat(auth-tech-debt): [PM-24103] Remove Get User Key to UserKey$ (#16589)

* fix(auth-tech-debt): [PM-24103] Remove Get User Key to UserKey$ - Fixed and updated tests.

* fix(auth-tech-debt): [PM-24103] Remove Get User Key to UserKey$ - Fixed test variable being made more vague.
This commit is contained in:
Patrick-Pimentel-Bitwarden
2025-10-16 14:30:10 -04:00
committed by GitHub
parent 9b2fbdba1c
commit 94cb1fe07b
15 changed files with 77 additions and 29 deletions

View File

@@ -886,6 +886,7 @@ export default class MainBackground {
this.apiService, this.apiService,
this.stateProvider, this.stateProvider,
this.authRequestApiService, this.authRequestApiService,
this.accountService,
); );
this.billingAccountProfileStateService = new DefaultBillingAccountProfileStateService( this.billingAccountProfileStateService = new DefaultBillingAccountProfileStateService(

View File

@@ -621,7 +621,7 @@ export class LoginCommand {
const newPasswordHash = await this.keyService.hashMasterKey(masterPassword, newMasterKey); const newPasswordHash = await this.keyService.hashMasterKey(masterPassword, newMasterKey);
// Grab user key // Grab user key
const userKey = await this.keyService.getUserKey(); const userKey = await firstValueFrom(this.keyService.userKey$(userId));
if (!userKey) { if (!userKey) {
throw new Error("User key not found."); throw new Error("User key not found.");
} }

View File

@@ -657,6 +657,7 @@ export class ServiceContainer {
this.apiService, this.apiService,
this.stateProvider, this.stateProvider,
this.authRequestApiService, this.authRequestApiService,
this.accountService,
); );
this.billingAccountProfileStateService = new DefaultBillingAccountProfileStateService( this.billingAccountProfileStateService = new DefaultBillingAccountProfileStateService(

View File

@@ -17,6 +17,7 @@ import { CsprngArray } from "@bitwarden/common/types/csprng";
import { UserId } from "@bitwarden/common/types/guid"; import { UserId } from "@bitwarden/common/types/guid";
import { UserKey, MasterKey, UserPrivateKey } from "@bitwarden/common/types/key"; import { UserKey, MasterKey, UserPrivateKey } from "@bitwarden/common/types/key";
import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service"; import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service";
import { newGuid } from "@bitwarden/guid";
import { Argon2KdfConfig, KdfType, KeyService, PBKDF2KdfConfig } from "@bitwarden/key-management"; import { Argon2KdfConfig, KdfType, KeyService, PBKDF2KdfConfig } from "@bitwarden/key-management";
import { EmergencyAccessStatusType } from "../enums/emergency-access-status-type"; import { EmergencyAccessStatusType } from "../enums/emergency-access-status-type";
@@ -44,6 +45,7 @@ describe("EmergencyAccessService", () => {
const mockNewUserKey = new SymmetricCryptoKey(new Uint8Array(64)) as UserKey; const mockNewUserKey = new SymmetricCryptoKey(new Uint8Array(64)) as UserKey;
const mockTrustedPublicKeys = [Utils.fromUtf8ToArray("trustedPublicKey")]; const mockTrustedPublicKeys = [Utils.fromUtf8ToArray("trustedPublicKey")];
const mockUserId = newGuid() as UserId;
beforeAll(() => { beforeAll(() => {
emergencyAccessApiService = mock<EmergencyAccessApiService>(); emergencyAccessApiService = mock<EmergencyAccessApiService>();
@@ -125,7 +127,7 @@ describe("EmergencyAccessService", () => {
"mockUserPublicKeyEncryptedUserKey", "mockUserPublicKeyEncryptedUserKey",
); );
keyService.getUserKey.mockResolvedValueOnce(mockUserKey); keyService.userKey$.mockReturnValue(of(mockUserKey));
encryptService.encapsulateKeyUnsigned.mockResolvedValueOnce( encryptService.encapsulateKeyUnsigned.mockResolvedValueOnce(
mockUserPublicKeyEncryptedUserKey, mockUserPublicKeyEncryptedUserKey,
@@ -134,7 +136,7 @@ describe("EmergencyAccessService", () => {
emergencyAccessApiService.postEmergencyAccessConfirm.mockResolvedValueOnce(); emergencyAccessApiService.postEmergencyAccessConfirm.mockResolvedValueOnce();
// Act // Act
await emergencyAccessService.confirm(id, granteeId, publicKey); await emergencyAccessService.confirm(id, granteeId, publicKey, mockUserId);
// Assert // Assert
expect(emergencyAccessApiService.postEmergencyAccessConfirm).toHaveBeenCalledWith(id, { expect(emergencyAccessApiService.postEmergencyAccessConfirm).toHaveBeenCalledWith(id, {

View File

@@ -175,11 +175,17 @@ export class EmergencyAccessService
* Step 3 of the 3 step setup flow. * Step 3 of the 3 step setup flow.
* Intended for grantor. * Intended for grantor.
* @param id emergency access id * @param id emergency access id
* @param token secret token provided in email * @param granteeId id of the grantee
* @param publicKey public key of grantee * @param publicKey public key of grantee
* @param activeUserId the active user's id
*/ */
async confirm(id: string, granteeId: string, publicKey: Uint8Array): Promise<void> { async confirm(
const userKey = await this.keyService.getUserKey(); id: string,
granteeId: string,
publicKey: Uint8Array,
activeUserId: UserId,
): Promise<void> {
const userKey = await firstValueFrom(this.keyService.userKey$(activeUserId));
if (!userKey) { if (!userKey) {
throw new Error("No user key found"); throw new Error("No user key found");
} }

View File

@@ -1,7 +1,7 @@
// FIXME: Update this file to be type safe and remove this and next line // FIXME: Update this file to be type safe and remove this and next line
// @ts-strict-ignore // @ts-strict-ignore
import { Component, OnInit } from "@angular/core"; import { Component, OnInit } from "@angular/core";
import { lastValueFrom, Observable, firstValueFrom, switchMap } from "rxjs"; import { lastValueFrom, Observable, firstValueFrom, switchMap, map } from "rxjs";
import { PremiumBadgeComponent } from "@bitwarden/angular/billing/components/premium-badge"; import { PremiumBadgeComponent } from "@bitwarden/angular/billing/components/premium-badge";
import { UserNamePipe } from "@bitwarden/angular/pipes/user-name.pipe"; import { UserNamePipe } from "@bitwarden/angular/pipes/user-name.pipe";
@@ -165,7 +165,15 @@ export class EmergencyAccessComponent implements OnInit {
}); });
const result = await lastValueFrom(dialogRef.closed); const result = await lastValueFrom(dialogRef.closed);
if (result === EmergencyAccessConfirmDialogResult.Confirmed) { if (result === EmergencyAccessConfirmDialogResult.Confirmed) {
await this.emergencyAccessService.confirm(contact.id, contact.granteeId, publicKey); const activeUserId = await firstValueFrom(
this.accountService.activeAccount$.pipe(getUserId),
);
await this.emergencyAccessService.confirm(
contact.id,
contact.granteeId,
publicKey,
activeUserId,
);
updateUser(); updateUser();
this.toastService.showToast({ this.toastService.showToast({
variant: "success", variant: "success",
@@ -176,10 +184,14 @@ export class EmergencyAccessComponent implements OnInit {
return; return;
} }
const activeUserId = await firstValueFrom(
this.accountService.activeAccount$.pipe(map((a) => a?.id)),
);
this.actionPromise = this.emergencyAccessService.confirm( this.actionPromise = this.emergencyAccessService.confirm(
contact.id, contact.id,
contact.granteeId, contact.granteeId,
publicKey, publicKey,
activeUserId,
); );
await this.actionPromise; await this.actionPromise;
updateUser(); updateUser();

View File

@@ -47,7 +47,7 @@ export class SetPinComponent implements OnInit {
} }
const userId = (await firstValueFrom(this.accountService.activeAccount$))?.id; const userId = (await firstValueFrom(this.accountService.activeAccount$))?.id;
const userKey = await this.keyService.getUserKey(); const userKey = await firstValueFrom(this.keyService.userKey$(userId));
const userKeyEncryptedPin = await this.pinService.createUserKeyEncryptedPin( const userKeyEncryptedPin = await this.pinService.createUserKeyEncryptedPin(
pinFormControl.value, pinFormControl.value,

View File

@@ -1291,6 +1291,7 @@ const safeProviders: SafeProvider[] = [
ApiServiceAbstraction, ApiServiceAbstraction,
StateProvider, StateProvider,
AuthRequestApiServiceAbstraction, AuthRequestApiServiceAbstraction,
AccountServiceAbstraction,
], ],
}), }),
safeProvider({ safeProvider({

View File

@@ -55,6 +55,7 @@ export abstract class AuthRequestServiceAbstraction {
* Approve or deny an auth request. * Approve or deny an auth request.
* @param approve True to approve, false to deny. * @param approve True to approve, false to deny.
* @param authRequest The auth request to approve or deny, must have an id and key. * @param authRequest The auth request to approve or deny, must have an id and key.
* @param activeUserId the active user id
* @returns The updated auth request, the `requestApproved` field will be true if * @returns The updated auth request, the `requestApproved` field will be true if
* approval was successful. * approval was successful.
* @throws If the auth request is missing an id or key. * @throws If the auth request is missing an id or key.

View File

@@ -337,7 +337,7 @@ describe("LoginStrategy", () => {
const tokenResponse = identityTokenResponseFactory(); const tokenResponse = identityTokenResponseFactory();
tokenResponse.privateKey = null; tokenResponse.privateKey = null;
keyService.makeKeyPair.mockResolvedValue(["PUBLIC_KEY", new EncString("PRIVATE_KEY")]); keyService.makeKeyPair.mockResolvedValue(["PUBLIC_KEY", new EncString("PRIVATE_KEY")]);
keyService.getUserKey.mockResolvedValue(userKey); keyService.userKey$.mockReturnValue(new BehaviorSubject<UserKey>(userKey).asObservable());
apiService.postIdentityToken.mockResolvedValue(tokenResponse); apiService.postIdentityToken.mockResolvedValue(tokenResponse);
masterPasswordService.masterKeySubject.next(masterKey); masterPasswordService.masterKeySubject.next(masterKey);
@@ -356,9 +356,11 @@ describe("LoginStrategy", () => {
}); });
it("throws if userKey is CoseEncrypt0 (V2 encryption) in createKeyPairForOldAccount", async () => { it("throws if userKey is CoseEncrypt0 (V2 encryption) in createKeyPairForOldAccount", async () => {
keyService.getUserKey.mockResolvedValue({ keyService.userKey$.mockReturnValue(
inner: () => ({ type: 7 }), new BehaviorSubject<UserKey>({
} as UserKey); inner: () => ({ type: 7 }),
} as unknown as UserKey).asObservable(),
);
await expect(passwordLoginStrategy["createKeyPairForOldAccount"](userId)).resolves.toBe( await expect(passwordLoginStrategy["createKeyPairForOldAccount"](userId)).resolves.toBe(
undefined, undefined,
); );

View File

@@ -306,7 +306,11 @@ export abstract class LoginStrategy {
protected async createKeyPairForOldAccount(userId: UserId) { protected async createKeyPairForOldAccount(userId: UserId) {
try { try {
const userKey = await this.keyService.getUserKey(userId); const userKey = await firstValueFrom(this.keyService.userKey$(userId));
if (userKey === null) {
throw new Error("User key is null when creating key pair for old account");
}
if (userKey.inner().type == EncryptionType.CoseEncrypt0) { if (userKey.inner().type == EncryptionType.CoseEncrypt0) {
throw new Error("Cannot create key pair for account on V2 encryption"); throw new Error("Cannot create key pair for account on V2 encryption");
} }

View File

@@ -1,7 +1,8 @@
import { mock } from "jest-mock-extended"; import { mock } from "jest-mock-extended";
import { firstValueFrom } from "rxjs"; import { firstValueFrom, of } 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 { AuthRequestResponse } from "@bitwarden/common/auth/models/response/auth-request.response"; import { AuthRequestResponse } from "@bitwarden/common/auth/models/response/auth-request.response";
import { EncryptService } from "@bitwarden/common/key-management/crypto/abstractions/encrypt.service"; import { EncryptService } from "@bitwarden/common/key-management/crypto/abstractions/encrypt.service";
import { EncString } from "@bitwarden/common/key-management/crypto/models/enc-string"; import { EncString } from "@bitwarden/common/key-management/crypto/models/enc-string";
@@ -9,11 +10,11 @@ import { FakeMasterPasswordService } from "@bitwarden/common/key-management/mast
import { ListResponse } from "@bitwarden/common/models/response/list.response"; import { ListResponse } from "@bitwarden/common/models/response/list.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 { 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 { StateProvider } from "@bitwarden/common/platform/state"; import { StateProvider } from "@bitwarden/common/platform/state";
import { UserId } from "@bitwarden/common/types/guid"; import { UserId } from "@bitwarden/common/types/guid";
import { MasterKey, UserKey } from "@bitwarden/common/types/key"; import { MasterKey, UserKey } from "@bitwarden/common/types/key";
import { newGuid } from "@bitwarden/guid";
import { KeyService } from "@bitwarden/key-management"; import { KeyService } from "@bitwarden/key-management";
import { DefaultAuthRequestApiService } from "./auth-request-api.service"; import { DefaultAuthRequestApiService } from "./auth-request-api.service";
@@ -29,10 +30,11 @@ describe("AuthRequestService", () => {
const encryptService = mock<EncryptService>(); const encryptService = mock<EncryptService>();
const apiService = mock<ApiService>(); const apiService = mock<ApiService>();
const authRequestApiService = mock<DefaultAuthRequestApiService>(); const authRequestApiService = mock<DefaultAuthRequestApiService>();
const accountService = mock<AccountService>();
let mockPrivateKey: Uint8Array; let mockPrivateKey: Uint8Array;
let mockPublicKey: Uint8Array; let mockPublicKey: Uint8Array;
const mockUserId = Utils.newGuid() as UserId; const mockUserId = newGuid() as UserId;
beforeEach(() => { beforeEach(() => {
jest.clearAllMocks(); jest.clearAllMocks();
@@ -46,6 +48,7 @@ describe("AuthRequestService", () => {
apiService, apiService,
stateProvider, stateProvider,
authRequestApiService, authRequestApiService,
accountService,
); );
mockPrivateKey = new Uint8Array(64); mockPrivateKey = new Uint8Array(64);
@@ -95,6 +98,8 @@ describe("AuthRequestService", () => {
const authRequestNoId = new AuthRequestResponse({ id: "", key: "KEY" }); const authRequestNoId = new AuthRequestResponse({ id: "", key: "KEY" });
const authRequestNoPublicKey = new AuthRequestResponse({ id: "123", publicKey: "" }); const authRequestNoPublicKey = new AuthRequestResponse({ id: "123", publicKey: "" });
accountService.activeAccount$ = of({ id: mockUserId } as any);
await expect(sut.approveOrDenyAuthRequest(true, authRequestNoId)).rejects.toThrow( await expect(sut.approveOrDenyAuthRequest(true, authRequestNoId)).rejects.toThrow(
"Auth request has no id", "Auth request has no id",
); );
@@ -104,8 +109,9 @@ describe("AuthRequestService", () => {
}); });
it("should use the user key if the master key and hash do not exist", async () => { it("should use the user key if the master key and hash do not exist", async () => {
keyService.getUserKey.mockResolvedValueOnce( accountService.activeAccount$ = of({ id: mockUserId } as any);
new SymmetricCryptoKey(new Uint8Array(64)) as UserKey, keyService.userKey$.mockReturnValue(
of(new SymmetricCryptoKey(new Uint8Array(64)) as UserKey),
); );
await sut.approveOrDenyAuthRequest( await sut.approveOrDenyAuthRequest(

View File

@@ -4,9 +4,11 @@ import { Observable, Subject, defer, firstValueFrom, map } 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 { AdminAuthRequestStorable } from "@bitwarden/common/auth/models/domain/admin-auth-req-storable"; import { AdminAuthRequestStorable } from "@bitwarden/common/auth/models/domain/admin-auth-req-storable";
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 { getUserId } from "@bitwarden/common/auth/services/account.service";
import { EncryptService } from "@bitwarden/common/key-management/crypto/abstractions/encrypt.service"; import { EncryptService } from "@bitwarden/common/key-management/crypto/abstractions/encrypt.service";
import { EncString } from "@bitwarden/common/key-management/crypto/models/enc-string"; 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 { InternalMasterPasswordServiceAbstraction } from "@bitwarden/common/key-management/master-password/abstractions/master-password.service.abstraction";
@@ -56,6 +58,7 @@ export class AuthRequestService implements AuthRequestServiceAbstraction {
private apiService: ApiService, private apiService: ApiService,
private stateProvider: StateProvider, private stateProvider: StateProvider,
private authRequestApiService: AuthRequestApiServiceAbstraction, private authRequestApiService: AuthRequestApiServiceAbstraction,
private accountService: AccountService,
) { ) {
this.authRequestPushNotification$ = this.authRequestPushNotificationSubject.asObservable(); this.authRequestPushNotification$ = this.authRequestPushNotificationSubject.asObservable();
this.adminLoginApproved$ = this.adminLoginApprovedSubject.asObservable(); this.adminLoginApproved$ = this.adminLoginApprovedSubject.asObservable();
@@ -124,15 +127,19 @@ export class AuthRequestService implements AuthRequestServiceAbstraction {
approve: boolean, approve: boolean,
authRequest: AuthRequestResponse, authRequest: AuthRequestResponse,
): Promise<AuthRequestResponse> { ): Promise<AuthRequestResponse> {
const activeUserId = await firstValueFrom(this.accountService.activeAccount$.pipe(getUserId));
if (!authRequest.id) { if (!authRequest.id) {
throw new Error("Auth request has no id"); throw new Error("Auth request has no id");
} }
if (!authRequest.publicKey) { if (!authRequest.publicKey) {
throw new Error("Auth request has no public key"); throw new Error("Auth request has no public key");
} }
if (activeUserId == null) {
throw new Error("User ID is required");
}
const pubKey = Utils.fromB64ToArray(authRequest.publicKey); const pubKey = Utils.fromB64ToArray(authRequest.publicKey);
const keyToEncrypt = await firstValueFrom(this.keyService.userKey$(activeUserId));
const keyToEncrypt = await this.keyService.getUserKey();
const encryptedKey = await this.encryptService.encapsulateKeyUnsigned(keyToEncrypt, pubKey); const encryptedKey = await this.encryptService.encapsulateKeyUnsigned(keyToEncrypt, pubKey);
const response = new PasswordlessAuthRequest( const response = new PasswordlessAuthRequest(

View File

@@ -1,5 +1,5 @@
import { mock, MockProxy } from "jest-mock-extended"; import { mock, MockProxy } from "jest-mock-extended";
import { BehaviorSubject } from "rxjs"; import { BehaviorSubject, of } from "rxjs";
// This import has been flagged as unallowed for this class. It may be involved in a circular dependency loop. // 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 // eslint-disable-next-line no-restricted-imports
@@ -103,7 +103,7 @@ describe("PasswordResetEnrollmentServiceImplementation", () => {
}; };
activeAccountSubject.next(Object.assign(user1AccountInfo, { id: "userId" as UserId })); activeAccountSubject.next(Object.assign(user1AccountInfo, { id: "userId" as UserId }));
keyService.getUserKey.mockResolvedValue({ key: "key" } as any); keyService.userKey$.mockReturnValue(of({ key: "key" } as any));
encryptService.encapsulateKeyUnsigned.mockResolvedValue(encryptedKey as any); encryptService.encapsulateKeyUnsigned.mockResolvedValue(encryptedKey as any);
await service.enroll("orgId"); await service.enroll("orgId");

View File

@@ -1,6 +1,6 @@
// FIXME: Update this file to be type safe and remove this and next line // FIXME: Update this file to be type safe and remove this and next line
// @ts-strict-ignore // @ts-strict-ignore
import { firstValueFrom, map } from "rxjs"; import { firstValueFrom } from "rxjs";
// This import has been flagged as unallowed for this class. It may be involved in a circular dependency loop. // 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 // eslint-disable-next-line no-restricted-imports
@@ -8,9 +8,11 @@ import {
OrganizationUserApiService, OrganizationUserApiService,
OrganizationUserResetPasswordEnrollmentRequest, OrganizationUserResetPasswordEnrollmentRequest,
} from "@bitwarden/admin-console/common"; } from "@bitwarden/admin-console/common";
import { getUserId } from "@bitwarden/common/auth/services/account.service";
// This import has been flagged as unallowed for this class. It may be involved in a circular dependency loop. // 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 // eslint-disable-next-line no-restricted-imports
import { KeyService } from "@bitwarden/key-management"; import { KeyService } from "@bitwarden/key-management";
import { UserId } from "@bitwarden/user-core";
import { OrganizationApiServiceAbstraction } from "../../admin-console/abstractions/organization/organization-api.service.abstraction"; import { OrganizationApiServiceAbstraction } from "../../admin-console/abstractions/organization/organization-api.service.abstraction";
import { EncryptService } from "../../key-management/crypto/abstractions/encrypt.service"; import { EncryptService } from "../../key-management/crypto/abstractions/encrypt.service";
@@ -43,7 +45,7 @@ export class PasswordResetEnrollmentServiceImplementation
async enroll(organizationId: string): Promise<void>; async enroll(organizationId: string): Promise<void>;
async enroll(organizationId: string, userId: string, userKey: UserKey): Promise<void>; async enroll(organizationId: string, userId: string, userKey: UserKey): Promise<void>;
async enroll(organizationId: string, userId?: string, userKey?: UserKey): Promise<void> { async enroll(organizationId: string, activeUserId?: string, userKey?: UserKey): Promise<void> {
const orgKeyResponse = await this.organizationApiService.getKeys(organizationId); const orgKeyResponse = await this.organizationApiService.getKeys(organizationId);
if (orgKeyResponse == null) { if (orgKeyResponse == null) {
throw new Error(this.i18nService.t("resetPasswordOrgKeysError")); throw new Error(this.i18nService.t("resetPasswordOrgKeysError"));
@@ -51,9 +53,12 @@ export class PasswordResetEnrollmentServiceImplementation
const orgPublicKey = Utils.fromB64ToArray(orgKeyResponse.publicKey); const orgPublicKey = Utils.fromB64ToArray(orgKeyResponse.publicKey);
userId = activeUserId =
userId ?? (await firstValueFrom(this.accountService.activeAccount$.pipe(map((a) => a?.id)))); activeUserId ?? (await firstValueFrom(this.accountService.activeAccount$.pipe(getUserId)));
userKey = userKey ?? (await this.keyService.getUserKey(userId)); if (activeUserId == null) {
throw new Error("User ID is required");
}
userKey = userKey ?? (await firstValueFrom(this.keyService.userKey$(activeUserId as UserId)));
// RSA Encrypt user's userKey.key with organization public key // RSA Encrypt user's userKey.key with organization public key
const encryptedKey = await this.encryptService.encapsulateKeyUnsigned(userKey, orgPublicKey); const encryptedKey = await this.encryptService.encapsulateKeyUnsigned(userKey, orgPublicKey);
@@ -62,7 +67,7 @@ export class PasswordResetEnrollmentServiceImplementation
await this.organizationUserApiService.putOrganizationUserResetPasswordEnrollment( await this.organizationUserApiService.putOrganizationUserResetPasswordEnrollment(
organizationId, organizationId,
userId, activeUserId,
resetRequest, resetRequest,
); );
} }