diff --git a/apps/cli/src/auth/commands/login.command.ts b/apps/cli/src/auth/commands/login.command.ts index 1851e8fe9c7..8fae8302bc9 100644 --- a/apps/cli/src/auth/commands/login.command.ts +++ b/apps/cli/src/auth/commands/login.command.ts @@ -21,6 +21,7 @@ import { PolicyService } from "@bitwarden/common/admin-console/abstractions/poli import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; import { AuthService } from "@bitwarden/common/auth/abstractions/auth.service"; import { KeyConnectorService } from "@bitwarden/common/auth/abstractions/key-connector.service"; +import { MasterPasswordApiService } from "@bitwarden/common/auth/abstractions/master-password-api.service.abstraction"; import { TwoFactorService } from "@bitwarden/common/auth/abstractions/two-factor.service"; import { TwoFactorProviderType } from "@bitwarden/common/auth/enums/two-factor-provider-type"; import { AuthResult } from "@bitwarden/common/auth/models/domain/auth-result"; @@ -58,6 +59,7 @@ export class LoginCommand { protected loginStrategyService: LoginStrategyServiceAbstraction, protected authService: AuthService, protected apiService: ApiService, + protected masterPasswordApiService: MasterPasswordApiService, protected cryptoFunctionService: CryptoFunctionService, protected environmentService: EnvironmentService, protected passwordGenerationService: PasswordGenerationServiceAbstraction, @@ -454,7 +456,7 @@ export class LoginCommand { request.newMasterPasswordHash = newPasswordHash; request.key = newUserKey[1].encryptedString; - await this.apiService.postPassword(request); + await this.masterPasswordApiService.postPassword(request); return await this.handleUpdatePasswordSuccessResponse(); } catch (e) { @@ -491,7 +493,7 @@ export class LoginCommand { request.newMasterPasswordHash = newPasswordHash; request.masterPasswordHint = hint; - await this.apiService.putUpdateTempPassword(request); + await this.masterPasswordApiService.putUpdateTempPassword(request); return await this.handleUpdatePasswordSuccessResponse(); } catch (e) { diff --git a/apps/cli/src/program.ts b/apps/cli/src/program.ts index a118985bf0d..c6b79c7dff2 100644 --- a/apps/cli/src/program.ts +++ b/apps/cli/src/program.ts @@ -155,6 +155,7 @@ export class Program extends BaseProgram { this.serviceContainer.loginStrategyService, this.serviceContainer.authService, this.serviceContainer.apiService, + this.serviceContainer.masterPasswordApiService, this.serviceContainer.cryptoFunctionService, this.serviceContainer.environmentService, this.serviceContainer.passwordGenerationService, diff --git a/apps/cli/src/service-container/service-container.ts b/apps/cli/src/service-container/service-container.ts index 555337736c7..72faca48a33 100644 --- a/apps/cli/src/service-container/service-container.ts +++ b/apps/cli/src/service-container/service-container.ts @@ -36,6 +36,7 @@ import { AccountService } from "@bitwarden/common/auth/abstractions/account.serv import { AvatarService as AvatarServiceAbstraction } from "@bitwarden/common/auth/abstractions/avatar.service"; import { DeviceTrustServiceAbstraction } from "@bitwarden/common/auth/abstractions/device-trust.service.abstraction"; import { DevicesApiServiceAbstraction } from "@bitwarden/common/auth/abstractions/devices-api.service.abstraction"; +import { MasterPasswordApiService as MasterPasswordApiServiceAbstraction } from "@bitwarden/common/auth/abstractions/master-password-api.service.abstraction"; import { InternalMasterPasswordServiceAbstraction } from "@bitwarden/common/auth/abstractions/master-password.service.abstraction"; import { AccountServiceImplementation, @@ -46,6 +47,7 @@ import { AvatarService } from "@bitwarden/common/auth/services/avatar.service"; import { DeviceTrustService } from "@bitwarden/common/auth/services/device-trust.service.implementation"; import { DevicesApiServiceImplementation } from "@bitwarden/common/auth/services/devices-api.service.implementation"; import { KeyConnectorService } from "@bitwarden/common/auth/services/key-connector.service"; +import { MasterPasswordApiService } from "@bitwarden/common/auth/services/master-password/master-password-api.service.implementation"; import { MasterPasswordService } from "@bitwarden/common/auth/services/master-password/master-password.service"; import { TokenService } from "@bitwarden/common/auth/services/token.service"; import { TwoFactorService } from "@bitwarden/common/auth/services/two-factor.service"; @@ -280,6 +282,7 @@ export class ServiceContainer { sdkLoadService: SdkLoadService; cipherAuthorizationService: CipherAuthorizationService; ssoUrlService: SsoUrlService; + masterPasswordApiService: MasterPasswordApiServiceAbstraction; constructor() { let p = null; @@ -843,6 +846,8 @@ export class ServiceContainer { this.organizationService, this.accountService, ); + + this.masterPasswordApiService = new MasterPasswordApiService(this.apiService, this.logService); } async logout() { diff --git a/apps/desktop/src/app/services/services.module.ts b/apps/desktop/src/app/services/services.module.ts index 5f8b9762594..c86309f50ff 100644 --- a/apps/desktop/src/app/services/services.module.ts +++ b/apps/desktop/src/app/services/services.module.ts @@ -46,6 +46,7 @@ import { AuthService, AuthService as AuthServiceAbstraction, } from "@bitwarden/common/auth/abstractions/auth.service"; +import { MasterPasswordApiService } from "@bitwarden/common/auth/abstractions/master-password-api.service.abstraction"; import { InternalMasterPasswordServiceAbstraction } from "@bitwarden/common/auth/abstractions/master-password.service.abstraction"; import { SsoLoginServiceAbstraction } from "@bitwarden/common/auth/abstractions/sso-login.service.abstraction"; import { AutofillSettingsServiceAbstraction } from "@bitwarden/common/autofill/services/autofill-settings.service"; @@ -367,6 +368,7 @@ const safeProviders: SafeProvider[] = [ useClass: DesktopSetPasswordJitService, deps: [ ApiService, + MasterPasswordApiService, KeyService, EncryptService, I18nServiceAbstraction, diff --git a/apps/desktop/src/auth/set-password.component.ts b/apps/desktop/src/auth/set-password.component.ts index ed4e8de5b3d..a41c87e1cdb 100644 --- a/apps/desktop/src/auth/set-password.component.ts +++ b/apps/desktop/src/auth/set-password.component.ts @@ -9,6 +9,7 @@ import { OrganizationApiServiceAbstraction } from "@bitwarden/common/admin-conso 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 { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; +import { MasterPasswordApiService } from "@bitwarden/common/auth/abstractions/master-password-api.service.abstraction"; import { InternalMasterPasswordServiceAbstraction } from "@bitwarden/common/auth/abstractions/master-password.service.abstraction"; import { SsoLoginServiceAbstraction } from "@bitwarden/common/auth/abstractions/sso-login.service.abstraction"; import { EncryptService } from "@bitwarden/common/key-management/crypto/abstractions/encrypt.service"; @@ -40,6 +41,7 @@ export class SetPasswordComponent extends BaseSetPasswordComponent implements On policyApiService: PolicyApiServiceAbstraction, policyService: PolicyService, router: Router, + masterPasswordApiService: MasterPasswordApiService, syncService: SyncService, route: ActivatedRoute, private broadcasterService: BroadcasterService, @@ -63,6 +65,7 @@ export class SetPasswordComponent extends BaseSetPasswordComponent implements On policyApiService, policyService, router, + masterPasswordApiService, apiService, syncService, route, diff --git a/apps/web/src/app/auth/settings/change-password.component.ts b/apps/web/src/app/auth/settings/change-password.component.ts index eb98f7fde07..f4a71d81e77 100644 --- a/apps/web/src/app/auth/settings/change-password.component.ts +++ b/apps/web/src/app/auth/settings/change-password.component.ts @@ -5,10 +5,10 @@ import { Router } from "@angular/router"; import { firstValueFrom, map } from "rxjs"; import { ChangePasswordComponent as BaseChangePasswordComponent } from "@bitwarden/angular/auth/components/change-password.component"; -import { ApiService } from "@bitwarden/common/abstractions/api.service"; import { AuditService } from "@bitwarden/common/abstractions/audit.service"; import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction"; import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; +import { MasterPasswordApiService } from "@bitwarden/common/auth/abstractions/master-password-api.service.abstraction"; import { InternalMasterPasswordServiceAbstraction } from "@bitwarden/common/auth/abstractions/master-password.service.abstraction"; import { UserVerificationService } from "@bitwarden/common/auth/abstractions/user-verification/user-verification.service.abstraction"; import { PasswordRequest } from "@bitwarden/common/auth/models/request/password.request"; @@ -50,7 +50,7 @@ export class ChangePasswordComponent private auditService: AuditService, private cipherService: CipherService, private syncService: SyncService, - private apiService: ApiService, + private masterPasswordApiService: MasterPasswordApiService, private router: Router, dialogService: DialogService, private userVerificationService: UserVerificationService, @@ -213,14 +213,14 @@ export class ChangePasswordComponent try { if (this.rotateUserKey) { - this.formPromise = this.apiService.postPassword(request).then(async () => { + this.formPromise = this.masterPasswordApiService.postPassword(request).then(async () => { // we need to save this for local masterkey verification during rotation await this.masterPasswordService.setMasterKeyHash(newLocalKeyHash, userId as UserId); await this.masterPasswordService.setMasterKey(newMasterKey, userId as UserId); return this.updateKey(); }); } else { - this.formPromise = this.apiService.postPassword(request); + this.formPromise = this.masterPasswordApiService.postPassword(request); } await this.formPromise; diff --git a/apps/web/src/app/core/core.module.ts b/apps/web/src/app/core/core.module.ts index d0e876026d2..d253dd608a2 100644 --- a/apps/web/src/app/core/core.module.ts +++ b/apps/web/src/app/core/core.module.ts @@ -50,6 +50,7 @@ import { import { AccountApiService as AccountApiServiceAbstraction } from "@bitwarden/common/auth/abstractions/account-api.service"; import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; import { AuthService } from "@bitwarden/common/auth/abstractions/auth.service"; +import { MasterPasswordApiService } from "@bitwarden/common/auth/abstractions/master-password-api.service.abstraction"; import { InternalMasterPasswordServiceAbstraction } from "@bitwarden/common/auth/abstractions/master-password.service.abstraction"; import { SsoLoginServiceAbstraction } from "@bitwarden/common/auth/abstractions/sso-login.service.abstraction"; import { ClientType } from "@bitwarden/common/enums"; @@ -279,6 +280,7 @@ const safeProviders: SafeProvider[] = [ useClass: WebSetPasswordJitService, deps: [ ApiService, + MasterPasswordApiService, KeyServiceAbstraction, EncryptService, I18nServiceAbstraction, diff --git a/libs/angular/src/auth/components/set-password.component.ts b/libs/angular/src/auth/components/set-password.component.ts index de079a7ebca..3d14eecd963 100644 --- a/libs/angular/src/auth/components/set-password.component.ts +++ b/libs/angular/src/auth/components/set-password.component.ts @@ -17,6 +17,7 @@ import { PolicyService } from "@bitwarden/common/admin-console/abstractions/poli 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 { InternalMasterPasswordServiceAbstraction } from "@bitwarden/common/auth/abstractions/master-password.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"; @@ -62,6 +63,7 @@ export class SetPasswordComponent extends BaseChangePasswordComponent implements private policyApiService: PolicyApiServiceAbstraction, policyService: PolicyService, protected router: Router, + private masterPasswordApiService: MasterPasswordApiService, private apiService: ApiService, private syncService: SyncService, private route: ActivatedRoute, @@ -195,7 +197,7 @@ export class SetPasswordComponent extends BaseChangePasswordComponent implements ); try { if (this.resetPasswordAutoEnroll) { - this.formPromise = this.apiService + this.formPromise = this.masterPasswordApiService .setPassword(request) .then(async () => { await this.onSetPasswordSuccess(masterKey, userKey, newKeyPair); @@ -222,7 +224,7 @@ export class SetPasswordComponent extends BaseChangePasswordComponent implements ); }); } else { - this.formPromise = this.apiService.setPassword(request).then(async () => { + this.formPromise = this.masterPasswordApiService.setPassword(request).then(async () => { await this.onSetPasswordSuccess(masterKey, userKey, newKeyPair); }); } diff --git a/libs/angular/src/auth/components/update-password.component.ts b/libs/angular/src/auth/components/update-password.component.ts index e6cefd40d1d..a7c5fdfe131 100644 --- a/libs/angular/src/auth/components/update-password.component.ts +++ b/libs/angular/src/auth/components/update-password.component.ts @@ -3,10 +3,10 @@ import { Directive } from "@angular/core"; import { Router } from "@angular/router"; -import { ApiService } from "@bitwarden/common/abstractions/api.service"; 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 { InternalMasterPasswordServiceAbstraction } from "@bitwarden/common/auth/abstractions/master-password.service.abstraction"; import { UserVerificationService } from "@bitwarden/common/auth/abstractions/user-verification/user-verification.service.abstraction"; import { VerificationType } from "@bitwarden/common/auth/enums/verification-type"; @@ -40,7 +40,7 @@ export class UpdatePasswordComponent extends BaseChangePasswordComponent { policyService: PolicyService, keyService: KeyService, messagingService: MessagingService, - private apiService: ApiService, + private masterPasswordApiService: MasterPasswordApiService, private userVerificationService: UserVerificationService, private logService: LogService, dialogService: DialogService, @@ -117,9 +117,7 @@ export class UpdatePasswordComponent extends BaseChangePasswordComponent { request.key = newUserKey[1].encryptedString; // Update user's password - // 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.apiService.postPassword(request); + await this.masterPasswordApiService.postPassword(request); this.toastService.showToast({ variant: "success", diff --git a/libs/angular/src/auth/components/update-temp-password.component.ts b/libs/angular/src/auth/components/update-temp-password.component.ts index 95c56d08486..9375bd03baa 100644 --- a/libs/angular/src/auth/components/update-temp-password.component.ts +++ b/libs/angular/src/auth/components/update-temp-password.component.ts @@ -4,10 +4,10 @@ import { Directive, OnInit } from "@angular/core"; import { Router } from "@angular/router"; import { firstValueFrom, map } from "rxjs"; -import { ApiService } from "@bitwarden/common/abstractions/api.service"; 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 { InternalMasterPasswordServiceAbstraction } from "@bitwarden/common/auth/abstractions/master-password.service.abstraction"; import { UserVerificationService } from "@bitwarden/common/auth/abstractions/user-verification/user-verification.service.abstraction"; import { VerificationType } from "@bitwarden/common/auth/enums/verification-type"; @@ -52,7 +52,7 @@ export class UpdateTempPasswordComponent extends BaseChangePasswordComponent imp policyService: PolicyService, keyService: KeyService, messagingService: MessagingService, - private apiService: ApiService, + private masterPasswordApiService: MasterPasswordApiService, private syncService: SyncService, private logService: LogService, private userVerificationService: UserVerificationService, @@ -202,7 +202,7 @@ export class UpdateTempPasswordComponent extends BaseChangePasswordComponent imp request.newMasterPasswordHash = masterPasswordHash; request.masterPasswordHint = this.hint; - return this.apiService.putUpdateTempPassword(request); + return this.masterPasswordApiService.putUpdateTempPassword(request); } private async updatePassword(newMasterPasswordHash: string, userKey: [UserKey, EncString]) { @@ -214,7 +214,7 @@ export class UpdateTempPasswordComponent extends BaseChangePasswordComponent imp request.newMasterPasswordHash = newMasterPasswordHash; request.key = userKey[1].encryptedString; - return this.apiService.postPassword(request); + return this.masterPasswordApiService.postPassword(request); } private async updateTdeOffboardingPassword( @@ -226,6 +226,6 @@ export class UpdateTempPasswordComponent extends BaseChangePasswordComponent imp request.newMasterPasswordHash = masterPasswordHash; request.masterPasswordHint = this.hint; - return this.apiService.putUpdateTdeOffboardingPassword(request); + return this.masterPasswordApiService.putUpdateTdeOffboardingPassword(request); } } diff --git a/libs/angular/src/services/jslib-services.module.ts b/libs/angular/src/services/jslib-services.module.ts index d31cd0c84e2..906b99d096e 100644 --- a/libs/angular/src/services/jslib-services.module.ts +++ b/libs/angular/src/services/jslib-services.module.ts @@ -91,6 +91,7 @@ import { DeviceTrustServiceAbstraction } from "@bitwarden/common/auth/abstractio import { DevicesServiceAbstraction } from "@bitwarden/common/auth/abstractions/devices/devices.service.abstraction"; import { DevicesApiServiceAbstraction } from "@bitwarden/common/auth/abstractions/devices-api.service.abstraction"; import { KeyConnectorService as KeyConnectorServiceAbstraction } from "@bitwarden/common/auth/abstractions/key-connector.service"; +import { MasterPasswordApiService as MasterPasswordApiServiceAbstraction } from "@bitwarden/common/auth/abstractions/master-password-api.service.abstraction"; import { InternalMasterPasswordServiceAbstraction, MasterPasswordServiceAbstraction, @@ -113,6 +114,7 @@ import { DeviceTrustService } from "@bitwarden/common/auth/services/device-trust import { DevicesServiceImplementation } from "@bitwarden/common/auth/services/devices/devices.service.implementation"; import { DevicesApiServiceImplementation } from "@bitwarden/common/auth/services/devices-api.service.implementation"; import { KeyConnectorService } from "@bitwarden/common/auth/services/key-connector.service"; +import { MasterPasswordApiService } from "@bitwarden/common/auth/services/master-password/master-password-api.service.implementation"; import { MasterPasswordService } from "@bitwarden/common/auth/services/master-password/master-password.service"; import { PasswordResetEnrollmentServiceImplementation } from "@bitwarden/common/auth/services/password-reset-enrollment.service.implementation"; import { SsoLoginService } from "@bitwarden/common/auth/services/sso-login.service"; @@ -1350,6 +1352,7 @@ const safeProviders: SafeProvider[] = [ useClass: DefaultSetPasswordJitService, deps: [ ApiServiceAbstraction, + MasterPasswordApiService, KeyService, EncryptService, I18nServiceAbstraction, @@ -1482,6 +1485,11 @@ const safeProviders: SafeProvider[] = [ ToastService, ], }), + safeProvider({ + provide: MasterPasswordApiServiceAbstraction, + useClass: MasterPasswordApiService, + deps: [ApiServiceAbstraction, LogService], + }), ]; @NgModule({ diff --git a/libs/auth/src/angular/set-password-jit/default-set-password-jit.service.spec.ts b/libs/auth/src/angular/set-password-jit/default-set-password-jit.service.spec.ts index 726110663fc..69d82a3bb77 100644 --- a/libs/auth/src/angular/set-password-jit/default-set-password-jit.service.spec.ts +++ b/libs/auth/src/angular/set-password-jit/default-set-password-jit.service.spec.ts @@ -9,6 +9,7 @@ import { import { ApiService } from "@bitwarden/common/abstractions/api.service"; import { OrganizationApiServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/organization/organization-api.service.abstraction"; import { OrganizationKeysResponse } from "@bitwarden/common/admin-console/models/response/organization-keys.response"; +import { MasterPasswordApiService } from "@bitwarden/common/auth/abstractions/master-password-api.service.abstraction"; import { InternalMasterPasswordServiceAbstraction } from "@bitwarden/common/auth/abstractions/master-password.service.abstraction"; import { SetPasswordRequest } from "@bitwarden/common/auth/models/request/set-password.request"; import { EncryptService } from "@bitwarden/common/key-management/crypto/abstractions/encrypt.service"; @@ -31,6 +32,7 @@ describe("DefaultSetPasswordJitService", () => { let sut: DefaultSetPasswordJitService; let apiService: MockProxy; + let masterPasswordApiService: MockProxy; let keyService: MockProxy; let encryptService: MockProxy; let i18nService: MockProxy; @@ -42,6 +44,7 @@ describe("DefaultSetPasswordJitService", () => { beforeEach(() => { apiService = mock(); + masterPasswordApiService = mock(); keyService = mock(); encryptService = mock(); i18nService = mock(); @@ -53,6 +56,7 @@ describe("DefaultSetPasswordJitService", () => { sut = new DefaultSetPasswordJitService( apiService, + masterPasswordApiService, keyService, encryptService, i18nService, @@ -148,7 +152,7 @@ describe("DefaultSetPasswordJitService", () => { keyService.makeKeyPair.mockResolvedValue(keyPair); - apiService.setPassword.mockResolvedValue(undefined); + masterPasswordApiService.setPassword.mockResolvedValue(undefined); masterPasswordService.setForceSetPasswordReason.mockResolvedValue(undefined); userDecryptionOptionsSubject.next(new UserDecryptionOptions({ hasMasterPassword: true })); @@ -185,7 +189,7 @@ describe("DefaultSetPasswordJitService", () => { await sut.setPassword(credentials); // Assert - expect(apiService.setPassword).toHaveBeenCalledWith(setPasswordRequest); + expect(masterPasswordApiService.setPassword).toHaveBeenCalledWith(setPasswordRequest); }); it("should set password successfully (given no user key)", async () => { @@ -196,7 +200,7 @@ describe("DefaultSetPasswordJitService", () => { await sut.setPassword(credentials); // Assert - expect(apiService.setPassword).toHaveBeenCalledWith(setPasswordRequest); + expect(masterPasswordApiService.setPassword).toHaveBeenCalledWith(setPasswordRequest); }); it("should handle reset password auto enroll", async () => { @@ -210,7 +214,7 @@ describe("DefaultSetPasswordJitService", () => { await sut.setPassword(credentials); // Assert - expect(apiService.setPassword).toHaveBeenCalledWith(setPasswordRequest); + expect(masterPasswordApiService.setPassword).toHaveBeenCalledWith(setPasswordRequest); expect(organizationApiService.getKeys).toHaveBeenCalledWith(orgId); expect(encryptService.rsaEncrypt).toHaveBeenCalledWith(userKey.key, orgPublicKey); expect( diff --git a/libs/auth/src/angular/set-password-jit/default-set-password-jit.service.ts b/libs/auth/src/angular/set-password-jit/default-set-password-jit.service.ts index 6c9ce8f9267..65428ff4dff 100644 --- a/libs/auth/src/angular/set-password-jit/default-set-password-jit.service.ts +++ b/libs/auth/src/angular/set-password-jit/default-set-password-jit.service.ts @@ -9,6 +9,7 @@ import { import { InternalUserDecryptionOptionsServiceAbstraction } from "@bitwarden/auth/common"; import { ApiService } from "@bitwarden/common/abstractions/api.service"; import { OrganizationApiServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/organization/organization-api.service.abstraction"; +import { MasterPasswordApiService } from "@bitwarden/common/auth/abstractions/master-password-api.service.abstraction"; import { InternalMasterPasswordServiceAbstraction } from "@bitwarden/common/auth/abstractions/master-password.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"; @@ -29,6 +30,7 @@ import { export class DefaultSetPasswordJitService implements SetPasswordJitService { constructor( protected apiService: ApiService, + protected masterPasswordApiService: MasterPasswordApiService, protected keyService: KeyService, protected encryptService: EncryptService, protected i18nService: I18nService, @@ -77,7 +79,7 @@ export class DefaultSetPasswordJitService implements SetPasswordJitService { kdfConfig.iterations, ); - await this.apiService.setPassword(request); + await this.masterPasswordApiService.setPassword(request); // Clear force set password reason to allow navigation back to vault. await this.masterPasswordService.setForceSetPasswordReason(ForceSetPasswordReason.None, userId); diff --git a/libs/common/src/abstractions/api.service.ts b/libs/common/src/abstractions/api.service.ts index fe3f356719b..32cabbf7618 100644 --- a/libs/common/src/abstractions/api.service.ts +++ b/libs/common/src/abstractions/api.service.ts @@ -49,17 +49,13 @@ import { UserApiTokenRequest } from "../auth/models/request/identity-token/user- import { WebAuthnLoginTokenRequest } from "../auth/models/request/identity-token/webauthn-login-token.request"; import { KeyConnectorUserKeyRequest } from "../auth/models/request/key-connector-user-key.request"; import { PasswordHintRequest } from "../auth/models/request/password-hint.request"; -import { PasswordRequest } from "../auth/models/request/password.request"; import { PasswordlessAuthRequest } from "../auth/models/request/passwordless-auth.request"; import { SecretVerificationRequest } from "../auth/models/request/secret-verification.request"; import { SetKeyConnectorKeyRequest } from "../auth/models/request/set-key-connector-key.request"; -import { SetPasswordRequest } from "../auth/models/request/set-password.request"; import { TwoFactorEmailRequest } from "../auth/models/request/two-factor-email.request"; import { TwoFactorProviderRequest } from "../auth/models/request/two-factor-provider.request"; import { TwoFactorRecoveryRequest } from "../auth/models/request/two-factor-recovery.request"; import { UpdateProfileRequest } from "../auth/models/request/update-profile.request"; -import { UpdateTdeOffboardingPasswordRequest } from "../auth/models/request/update-tde-offboarding-password.request"; -import { UpdateTempPasswordRequest } from "../auth/models/request/update-temp-password.request"; import { UpdateTwoFactorAuthenticatorRequest } from "../auth/models/request/update-two-factor-authenticator.request"; import { UpdateTwoFactorDuoRequest } from "../auth/models/request/update-two-factor-duo.request"; import { UpdateTwoFactorEmailRequest } from "../auth/models/request/update-two-factor-email.request"; @@ -169,8 +165,6 @@ export abstract class ApiService { postPrelogin: (request: PreloginRequest) => Promise; postEmailToken: (request: EmailTokenRequest) => Promise; postEmail: (request: EmailRequest) => Promise; - postPassword: (request: PasswordRequest) => Promise; - setPassword: (request: SetPasswordRequest) => Promise; postSetKeyConnectorKey: (request: SetKeyConnectorKeyRequest) => Promise; postSecurityStamp: (request: SecretVerificationRequest) => Promise; getAccountRevisionDate: () => Promise; @@ -189,8 +183,6 @@ export abstract class ApiService { postAccountKdf: (request: KdfRequest) => Promise; postUserApiKey: (id: string, request: SecretVerificationRequest) => Promise; postUserRotateApiKey: (id: string, request: SecretVerificationRequest) => Promise; - putUpdateTempPassword: (request: UpdateTempPasswordRequest) => Promise; - putUpdateTdeOffboardingPassword: (request: UpdateTdeOffboardingPasswordRequest) => Promise; postConvertToKeyConnector: () => Promise; //passwordless postAuthRequest: (request: AuthRequest) => Promise; diff --git a/libs/common/src/auth/abstractions/master-password-api.service.abstraction.ts b/libs/common/src/auth/abstractions/master-password-api.service.abstraction.ts new file mode 100644 index 00000000000..442347ca456 --- /dev/null +++ b/libs/common/src/auth/abstractions/master-password-api.service.abstraction.ts @@ -0,0 +1,28 @@ +import { PasswordRequest } from "../models/request/password.request"; +import { SetPasswordRequest } from "../models/request/set-password.request"; +import { UpdateTdeOffboardingPasswordRequest } from "../models/request/update-tde-offboarding-password.request"; +import { UpdateTempPasswordRequest } from "../models/request/update-temp-password.request"; + +export abstract class MasterPasswordApiService { + /** + * POSTs a SetPasswordRequest to "/accounts/set-password" + */ + abstract setPassword: (request: SetPasswordRequest) => Promise; + + /** + * POSTs a PasswordRequest to "/accounts/password" + */ + abstract postPassword: (request: PasswordRequest) => Promise; + + /** + * PUTs an UpdateTempPasswordRequest to "/accounts/update-temp-password" + */ + abstract putUpdateTempPassword: (request: UpdateTempPasswordRequest) => Promise; + + /** + * PUTs an UpdateTdeOffboardingPasswordRequest to "/accounts/update-tde-offboarding-password" + */ + abstract putUpdateTdeOffboardingPassword: ( + request: UpdateTdeOffboardingPasswordRequest, + ) => Promise; +} diff --git a/libs/common/src/auth/services/master-password/master-password-api.service.implementation.ts b/libs/common/src/auth/services/master-password/master-password-api.service.implementation.ts new file mode 100644 index 00000000000..a91ccab24ef --- /dev/null +++ b/libs/common/src/auth/services/master-password/master-password-api.service.implementation.ts @@ -0,0 +1,85 @@ +import { ApiService } from "@bitwarden/common/abstractions/api.service"; +import { LogService } from "@bitwarden/common/platform/abstractions/log.service"; + +import { MasterPasswordApiService as MasterPasswordApiServiceAbstraction } from "../../abstractions/master-password-api.service.abstraction"; +import { PasswordRequest } from "../../models/request/password.request"; +import { SetPasswordRequest } from "../../models/request/set-password.request"; +import { UpdateTdeOffboardingPasswordRequest } from "../../models/request/update-tde-offboarding-password.request"; +import { UpdateTempPasswordRequest } from "../../models/request/update-temp-password.request"; + +export class MasterPasswordApiService implements MasterPasswordApiServiceAbstraction { + constructor( + private apiService: ApiService, + private logService: LogService, + ) {} + + async setPassword(request: SetPasswordRequest): Promise { + try { + const response = await this.apiService.send( + "POST", + "/accounts/set-password", + request, + true, + false, + ); + + return response; + } catch (e: unknown) { + this.logService.error(e); + throw e; + } + } + + async postPassword(request: PasswordRequest): Promise { + try { + const response = await this.apiService.send( + "POST", + "/accounts/password", + request, + true, + false, + ); + + return response; + } catch (e: unknown) { + this.logService.error(e); + throw e; + } + } + + async putUpdateTempPassword(request: UpdateTempPasswordRequest): Promise { + try { + const response = await this.apiService.send( + "PUT", + "/accounts/update-temp-password", + request, + true, + false, + ); + + return response; + } catch (e: unknown) { + this.logService.error(e); + throw e; + } + } + + async putUpdateTdeOffboardingPassword( + request: UpdateTdeOffboardingPasswordRequest, + ): Promise { + try { + const response = await this.apiService.send( + "PUT", + "/accounts/update-tde-offboarding-password", + request, + true, + false, + ); + + return response; + } catch (e: unknown) { + this.logService.error(e); + throw e; + } + } +} diff --git a/libs/common/src/auth/services/master-password/master-password-api.service.spec.ts b/libs/common/src/auth/services/master-password/master-password-api.service.spec.ts new file mode 100644 index 00000000000..64d4fdf1c7b --- /dev/null +++ b/libs/common/src/auth/services/master-password/master-password-api.service.spec.ts @@ -0,0 +1,130 @@ +import { mock, MockProxy } from "jest-mock-extended"; + +import { ApiService } from "@bitwarden/common/abstractions/api.service"; +import { LogService } from "@bitwarden/common/platform/abstractions/log.service"; +import { KdfType } from "@bitwarden/key-management"; + +import { PasswordRequest } from "../../models/request/password.request"; +import { SetPasswordRequest } from "../../models/request/set-password.request"; +import { UpdateTdeOffboardingPasswordRequest } from "../../models/request/update-tde-offboarding-password.request"; +import { UpdateTempPasswordRequest } from "../../models/request/update-temp-password.request"; + +import { MasterPasswordApiService } from "./master-password-api.service.implementation"; + +describe("MasterPasswordApiService", () => { + let apiService: MockProxy; + let logService: MockProxy; + + let sut: MasterPasswordApiService; + + beforeEach(() => { + apiService = mock(); + logService = mock(); + + sut = new MasterPasswordApiService(apiService, logService); + }); + + it("should instantiate", () => { + expect(sut).not.toBeFalsy(); + }); + + describe("setPassword", () => { + it("should call apiService.send with the correct parameters", async () => { + // Arrange + const request = new SetPasswordRequest( + "masterPasswordHash", + "key", + "masterPasswordHint", + "orgIdentifier", + { + publicKey: "publicKey", + encryptedPrivateKey: "encryptedPrivateKey", + }, + KdfType.PBKDF2_SHA256, + 600_000, + ); + + // Act + await sut.setPassword(request); + + // Assert + expect(apiService.send).toHaveBeenCalledWith( + "POST", + "/accounts/set-password", + request, + true, + false, + ); + }); + }); + + describe("postPassword", () => { + it("should call apiService.send with the correct parameters", async () => { + // Arrange + const request = { + newMasterPasswordHash: "newMasterPasswordHash", + masterPasswordHint: "masterPasswordHint", + key: "key", + masterPasswordHash: "masterPasswordHash", + } as PasswordRequest; + + // Act + await sut.postPassword(request); + + // Assert + expect(apiService.send).toHaveBeenCalledWith( + "POST", + "/accounts/password", + request, + true, + false, + ); + }); + }); + + describe("putUpdateTempPassword", () => { + it("should call apiService.send with the correct parameters", async () => { + // Arrange + const request = { + masterPasswordHint: "masterPasswordHint", + newMasterPasswordHash: "newMasterPasswordHash", + key: "key", + } as UpdateTempPasswordRequest; + + // Act + await sut.putUpdateTempPassword(request); + + // Assert + expect(apiService.send).toHaveBeenCalledWith( + "PUT", + "/accounts/update-temp-password", + request, + true, + false, + ); + }); + }); + + describe("putUpdateTdeOffboardingPassword", () => { + it("should call apiService.send with the correct parameters", async () => { + // Arrange + const request = { + masterPasswordHint: "masterPasswordHint", + newMasterPasswordHash: "newMasterPasswordHash", + key: "key", + } as UpdateTdeOffboardingPasswordRequest; + + // Act + await sut.putUpdateTdeOffboardingPassword(request); + + // Assert + expect(apiService.send).toHaveBeenCalledWith( + "PUT", + "/accounts/update-tde-offboarding-password", + request, + true, + false, + ); + }); + }); +}); diff --git a/libs/common/src/services/api.service.ts b/libs/common/src/services/api.service.ts index 7a43daccf6e..3d89e75cf8a 100644 --- a/libs/common/src/services/api.service.ts +++ b/libs/common/src/services/api.service.ts @@ -56,17 +56,13 @@ import { UserApiTokenRequest } from "../auth/models/request/identity-token/user- import { WebAuthnLoginTokenRequest } from "../auth/models/request/identity-token/webauthn-login-token.request"; import { KeyConnectorUserKeyRequest } from "../auth/models/request/key-connector-user-key.request"; import { PasswordHintRequest } from "../auth/models/request/password-hint.request"; -import { PasswordRequest } from "../auth/models/request/password.request"; import { PasswordlessAuthRequest } from "../auth/models/request/passwordless-auth.request"; import { SecretVerificationRequest } from "../auth/models/request/secret-verification.request"; import { SetKeyConnectorKeyRequest } from "../auth/models/request/set-key-connector-key.request"; -import { SetPasswordRequest } from "../auth/models/request/set-password.request"; import { TwoFactorEmailRequest } from "../auth/models/request/two-factor-email.request"; import { TwoFactorProviderRequest } from "../auth/models/request/two-factor-provider.request"; import { TwoFactorRecoveryRequest } from "../auth/models/request/two-factor-recovery.request"; import { UpdateProfileRequest } from "../auth/models/request/update-profile.request"; -import { UpdateTdeOffboardingPasswordRequest } from "../auth/models/request/update-tde-offboarding-password.request"; -import { UpdateTempPasswordRequest } from "../auth/models/request/update-temp-password.request"; import { UpdateTwoFactorAuthenticatorRequest } from "../auth/models/request/update-two-factor-authenticator.request"; import { UpdateTwoFactorDuoRequest } from "../auth/models/request/update-two-factor-duo.request"; import { UpdateTwoFactorEmailRequest } from "../auth/models/request/update-two-factor-email.request"; @@ -374,14 +370,6 @@ export class ApiService implements ApiServiceAbstraction { return this.send("POST", "/accounts/email", request, true, false); } - postPassword(request: PasswordRequest): Promise { - return this.send("POST", "/accounts/password", request, true, false); - } - - setPassword(request: SetPasswordRequest): Promise { - return this.send("POST", "/accounts/set-password", request, true, false); - } - postSetKeyConnectorKey(request: SetKeyConnectorKeyRequest): Promise { return this.send("POST", "/accounts/set-key-connector-key", request, true, false); } @@ -479,14 +467,6 @@ export class ApiService implements ApiServiceAbstraction { return new ApiKeyResponse(r); } - putUpdateTempPassword(request: UpdateTempPasswordRequest): Promise { - return this.send("PUT", "/accounts/update-temp-password", request, true, false); - } - - putUpdateTdeOffboardingPassword(request: UpdateTdeOffboardingPasswordRequest): Promise { - return this.send("PUT", "/accounts/update-tde-offboarding-password", request, true, false); - } - postConvertToKeyConnector(): Promise { return this.send("POST", "/accounts/convert-to-key-connector", null, true, false); }