1
0
mirror of https://github.com/bitwarden/browser synced 2025-12-17 16:53:34 +00:00

fix(two-factor) [PM-21204]: Users without premium cannot disable premium 2FA (#17134)

* refactor(two-factor-service) [PM-21204]: Stub API methods in TwoFactorService (domain).

* refactor(two-factor-service) [PM-21204]: Build out stubs and add documentation.

* refactor(two-factor-service) [PM-21204]: Update TwoFactorApiService call sites to use TwoFactorService.

* refactor(two-fatcor) [PM-21204]: Remove deprecated and unused formPromise methods.

* refactor(two-factor) [PM-21204]: Move 2FA-supporting services into common/auth/two-factor feature namespace.

* refactor(two-factor) [PM-21204]: Update imports for service/init containers.

* feat(two-factor) [PM-21204]: Add a disabling flow for Premium 2FA when enabled on a non-Premium account.

* fix(two-factor-service) [PM-21204]: Fix type-safety of module constants.

* fix(multiple) [PM-21204]: Prettier.

* fix(user-verification-dialog) [PM-21204]: Remove bodyText configuration for this use.

* fix(user-verification-dialog) [PM-21204]: Improve the error message displayed to the user.
This commit is contained in:
Dave
2025-11-21 10:35:34 -05:00
committed by GitHub
parent 490ef1dab0
commit daf7b7d2ce
47 changed files with 966 additions and 441 deletions

View File

@@ -4,10 +4,9 @@ import { ReactiveFormsModule, FormsModule, FormControl } from "@angular/forms";
import { JslibModule } from "@bitwarden/angular/jslib.module";
import { LoginStrategyServiceAbstraction } from "@bitwarden/auth/common";
import { TwoFactorService } from "@bitwarden/common/auth/abstractions/two-factor.service";
import { TwoFactorProviderType } from "@bitwarden/common/auth/enums/two-factor-provider-type";
import { TwoFactorEmailRequest } from "@bitwarden/common/auth/models/request/two-factor-email.request";
import { TwoFactorApiService } from "@bitwarden/common/auth/two-factor";
import { TwoFactorService } from "@bitwarden/common/auth/two-factor";
import { AppIdService } from "@bitwarden/common/platform/abstractions/app-id.service";
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
@@ -68,7 +67,6 @@ export class TwoFactorAuthEmailComponent implements OnInit {
protected loginStrategyService: LoginStrategyServiceAbstraction,
protected platformUtilsService: PlatformUtilsService,
protected logService: LogService,
protected twoFactorApiService: TwoFactorApiService,
protected appIdService: AppIdService,
private toastService: ToastService,
private cacheService: TwoFactorAuthEmailComponentCacheService,
@@ -137,7 +135,7 @@ export class TwoFactorAuthEmailComponent implements OnInit {
request.deviceIdentifier = await this.appIdService.getAppId();
request.authRequestAccessCode = (await this.loginStrategyService.getAccessCode()) ?? "";
request.authRequestId = (await this.loginStrategyService.getAuthRequestId()) ?? "";
this.emailPromise = this.twoFactorApiService.postTwoFactorEmail(request);
this.emailPromise = this.twoFactorService.postTwoFactorEmail(request);
await this.emailPromise;
this.emailSent = true;

View File

@@ -6,8 +6,8 @@ import { firstValueFrom } from "rxjs";
import { JslibModule } from "@bitwarden/angular/jslib.module";
import { WINDOW } from "@bitwarden/angular/services/injection-tokens";
import { TwoFactorService } from "@bitwarden/common/auth/abstractions/two-factor.service";
import { TwoFactorProviderType } from "@bitwarden/common/auth/enums/two-factor-provider-type";
import { TwoFactorService } from "@bitwarden/common/auth/two-factor";
import { WebAuthnIFrame } from "@bitwarden/common/auth/webauthn-iframe";
import { EnvironmentService } from "@bitwarden/common/platform/abstractions/environment.service";
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";

View File

@@ -18,12 +18,12 @@ import { ApiService } from "@bitwarden/common/abstractions/api.service";
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
import { AuthService } from "@bitwarden/common/auth/abstractions/auth.service";
import { SsoLoginServiceAbstraction } from "@bitwarden/common/auth/abstractions/sso-login.service.abstraction";
import { TwoFactorService } from "@bitwarden/common/auth/abstractions/two-factor.service";
import { AuthenticationStatus } from "@bitwarden/common/auth/enums/authentication-status";
import { AuthenticationType } from "@bitwarden/common/auth/enums/authentication-type";
import { AuthResult } from "@bitwarden/common/auth/models/domain/auth-result";
import { ForceSetPasswordReason } from "@bitwarden/common/auth/models/domain/force-set-password-reason";
import { TokenTwoFactorRequest } from "@bitwarden/common/auth/models/request/identity-token/token-two-factor.request";
import { TwoFactorService } from "@bitwarden/common/auth/two-factor";
import { KeyConnectorService } from "@bitwarden/common/key-management/key-connector/abstractions/key-connector.service";
import {
InternalMasterPasswordServiceAbstraction,

View File

@@ -32,12 +32,12 @@ import {
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
import { AuthService } from "@bitwarden/common/auth/abstractions/auth.service";
import { SsoLoginServiceAbstraction } from "@bitwarden/common/auth/abstractions/sso-login.service.abstraction";
import { TwoFactorService } from "@bitwarden/common/auth/abstractions/two-factor.service";
import { AuthenticationStatus } from "@bitwarden/common/auth/enums/authentication-status";
import { TwoFactorProviderType } from "@bitwarden/common/auth/enums/two-factor-provider-type";
import { AuthResult } from "@bitwarden/common/auth/models/domain/auth-result";
import { ForceSetPasswordReason } from "@bitwarden/common/auth/models/domain/force-set-password-reason";
import { TokenTwoFactorRequest } from "@bitwarden/common/auth/models/request/identity-token/token-two-factor.request";
import { TwoFactorService } from "@bitwarden/common/auth/two-factor";
import { KeyConnectorService } from "@bitwarden/common/key-management/key-connector/abstractions/key-connector.service";
import { InternalMasterPasswordServiceAbstraction } from "@bitwarden/common/key-management/master-password/abstractions/master-password.service.abstraction";
import { EnvironmentService } from "@bitwarden/common/platform/abstractions/environment.service";

View File

@@ -4,8 +4,8 @@ import { provideRouter, Router } from "@angular/router";
import { mock, MockProxy } from "jest-mock-extended";
import { BehaviorSubject } from "rxjs";
import { TwoFactorService } from "@bitwarden/common/auth/abstractions/two-factor.service";
import { AuthenticationType } from "@bitwarden/common/auth/enums/authentication-type";
import { TwoFactorService } from "@bitwarden/common/auth/two-factor";
import { LoginStrategyServiceAbstraction } from "../../common";

View File

@@ -8,7 +8,7 @@ import {
} from "@angular/router";
import { firstValueFrom } from "rxjs";
import { TwoFactorService } from "@bitwarden/common/auth/abstractions/two-factor.service";
import { TwoFactorService } from "@bitwarden/common/auth/two-factor";
import { LoginStrategyServiceAbstraction } from "../../common";

View File

@@ -9,11 +9,8 @@ import {
TwoFactorAuthWebAuthnIcon,
TwoFactorAuthYubicoIcon,
} from "@bitwarden/assets/svg";
import {
TwoFactorProviderDetails,
TwoFactorService,
} from "@bitwarden/common/auth/abstractions/two-factor.service";
import { TwoFactorProviderType } from "@bitwarden/common/auth/enums/two-factor-provider-type";
import { TwoFactorProviderDetails, TwoFactorService } from "@bitwarden/common/auth/two-factor";
// 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 {

View File

@@ -277,13 +277,13 @@ export class UserVerificationDialogComponent {
});
}
}
} catch (e) {
} catch {
// Catch handles OTP and MP verification scenarios as those throw errors on verification failure instead of returning false like PIN and biometrics.
this.invalidSecret = true;
this.toastService.showToast({
variant: "error",
title: this.i18nService.t("error"),
message: e.message,
message: this.i18nService.t("userVerificationFailed"),
});
return;
}