Skip to content

Commit daf7b7d

Browse files
authored
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.
1 parent 490ef1d commit daf7b7d

File tree

47 files changed

+966
-441
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

47 files changed

+966
-441
lines changed

apps/browser/src/popup/services/init.service.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { DOCUMENT } from "@angular/common";
22
import { inject, Inject, Injectable } from "@angular/core";
33

44
import { AbstractThemingService } from "@bitwarden/angular/platform/services/theming/theming.service.abstraction";
5-
import { TwoFactorService } from "@bitwarden/common/auth/abstractions/two-factor.service";
5+
import { TwoFactorService } from "@bitwarden/common/auth/two-factor";
66
import { EncryptService } from "@bitwarden/common/key-management/crypto/abstractions/encrypt.service";
77
import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service";
88
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";

apps/cli/src/auth/commands/login.command.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,15 +20,14 @@ import { PolicyService } from "@bitwarden/common/admin-console/abstractions/poli
2020
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
2121
import { AuthService } from "@bitwarden/common/auth/abstractions/auth.service";
2222
import { MasterPasswordApiService } from "@bitwarden/common/auth/abstractions/master-password-api.service.abstraction";
23-
import { TwoFactorService } from "@bitwarden/common/auth/abstractions/two-factor.service";
2423
import { TwoFactorProviderType } from "@bitwarden/common/auth/enums/two-factor-provider-type";
2524
import { AuthResult } from "@bitwarden/common/auth/models/domain/auth-result";
2625
import { ForceSetPasswordReason } from "@bitwarden/common/auth/models/domain/force-set-password-reason";
2726
import { TokenTwoFactorRequest } from "@bitwarden/common/auth/models/request/identity-token/token-two-factor.request";
2827
import { PasswordRequest } from "@bitwarden/common/auth/models/request/password.request";
2928
import { TwoFactorEmailRequest } from "@bitwarden/common/auth/models/request/two-factor-email.request";
3029
import { UpdateTempPasswordRequest } from "@bitwarden/common/auth/models/request/update-temp-password.request";
31-
import { TwoFactorApiService } from "@bitwarden/common/auth/two-factor";
30+
import { TwoFactorService, TwoFactorApiService } from "@bitwarden/common/auth/two-factor";
3231
import { ClientType } from "@bitwarden/common/enums";
3332
import { CryptoFunctionService } from "@bitwarden/common/key-management/crypto/abstractions/crypto-function.service";
3433
import { EncString } from "@bitwarden/common/key-management/crypto/models/enc-string";

apps/cli/src/service-container/service-container.ts

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -49,10 +49,14 @@ import { DefaultActiveUserAccessor } from "@bitwarden/common/auth/services/defau
4949
import { DevicesApiServiceImplementation } from "@bitwarden/common/auth/services/devices-api.service.implementation";
5050
import { MasterPasswordApiService } from "@bitwarden/common/auth/services/master-password/master-password-api.service.implementation";
5151
import { TokenService } from "@bitwarden/common/auth/services/token.service";
52-
import { TwoFactorService } from "@bitwarden/common/auth/services/two-factor.service";
5352
import { UserVerificationApiService } from "@bitwarden/common/auth/services/user-verification/user-verification-api.service";
5453
import { UserVerificationService } from "@bitwarden/common/auth/services/user-verification/user-verification.service";
55-
import { TwoFactorApiService, DefaultTwoFactorApiService } from "@bitwarden/common/auth/two-factor";
54+
import {
55+
DefaultTwoFactorService,
56+
TwoFactorService,
57+
TwoFactorApiService,
58+
DefaultTwoFactorApiService,
59+
} from "@bitwarden/common/auth/two-factor";
5660
import {
5761
AutofillSettingsService,
5862
AutofillSettingsServiceAbstraction,
@@ -627,10 +631,11 @@ export class ServiceContainer {
627631
this.stateProvider,
628632
);
629633

630-
this.twoFactorService = new TwoFactorService(
634+
this.twoFactorService = new DefaultTwoFactorService(
631635
this.i18nService,
632636
this.platformUtilsService,
633637
this.globalStateProvider,
638+
this.twoFactorApiService,
634639
);
635640

636641
const sdkClientFactory = flagEnabled("sdk")

apps/desktop/src/app/services/init.service.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import { AbstractThemingService } from "@bitwarden/angular/platform/services/the
66
import { WINDOW } from "@bitwarden/angular/services/injection-tokens";
77
import { EventUploadService as EventUploadServiceAbstraction } from "@bitwarden/common/abstractions/event/event-upload.service";
88
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
9-
import { TwoFactorService as TwoFactorServiceAbstraction } from "@bitwarden/common/auth/abstractions/two-factor.service";
9+
import { TwoFactorService } from "@bitwarden/common/auth/two-factor";
1010
import { EncryptService } from "@bitwarden/common/key-management/crypto/abstractions/encrypt.service";
1111
import { DefaultVaultTimeoutService } from "@bitwarden/common/key-management/vault-timeout";
1212
import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service";
@@ -39,7 +39,7 @@ export class InitService {
3939
private vaultTimeoutService: DefaultVaultTimeoutService,
4040
private i18nService: I18nServiceAbstraction,
4141
private eventUploadService: EventUploadServiceAbstraction,
42-
private twoFactorService: TwoFactorServiceAbstraction,
42+
private twoFactorService: TwoFactorService,
4343
private notificationsService: ServerNotificationsService,
4444
private platformUtilsService: PlatformUtilsServiceAbstraction,
4545
private stateService: StateServiceAbstraction,

apps/web/src/app/admin-console/organizations/settings/two-factor-setup.component.ts

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,16 +11,17 @@ import {
1111
} from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
1212
import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction";
1313
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
14+
import { UserVerificationService } from "@bitwarden/common/auth/abstractions/user-verification/user-verification.service.abstraction";
1415
import { TwoFactorProviderType } from "@bitwarden/common/auth/enums/two-factor-provider-type";
1516
import { TwoFactorDuoResponse } from "@bitwarden/common/auth/models/response/two-factor-duo.response";
1617
import { getUserId } from "@bitwarden/common/auth/services/account.service";
17-
import { TwoFactorApiService } from "@bitwarden/common/auth/two-factor";
18+
import { TwoFactorService } from "@bitwarden/common/auth/two-factor";
1819
import { AuthResponse } from "@bitwarden/common/auth/types/auth-response";
1920
import { BillingAccountProfileStateService } from "@bitwarden/common/billing/abstractions/account/billing-account-profile-state.service";
2021
import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service";
2122
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
2223
import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service";
23-
import { DialogRef, DialogService } from "@bitwarden/components";
24+
import { DialogRef, DialogService, ToastService } from "@bitwarden/components";
2425

2526
import { TwoFactorSetupDuoComponent } from "../../../auth/settings/two-factor/two-factor-setup-duo.component";
2627
import { TwoFactorSetupComponent as BaseTwoFactorSetupComponent } from "../../../auth/settings/two-factor/two-factor-setup.component";
@@ -37,7 +38,7 @@ export class TwoFactorSetupComponent extends BaseTwoFactorSetupComponent impleme
3738
tabbedHeader = false;
3839
constructor(
3940
dialogService: DialogService,
40-
twoFactorApiService: TwoFactorApiService,
41+
twoFactorService: TwoFactorService,
4142
messagingService: MessagingService,
4243
policyService: PolicyService,
4344
private route: ActivatedRoute,
@@ -46,16 +47,20 @@ export class TwoFactorSetupComponent extends BaseTwoFactorSetupComponent impleme
4647
protected accountService: AccountService,
4748
configService: ConfigService,
4849
i18nService: I18nService,
50+
protected userVerificationService: UserVerificationService,
51+
protected toastService: ToastService,
4952
) {
5053
super(
5154
dialogService,
52-
twoFactorApiService,
55+
twoFactorService,
5356
messagingService,
5457
policyService,
5558
billingAccountProfileStateService,
5659
accountService,
5760
configService,
5861
i18nService,
62+
userVerificationService,
63+
toastService,
5964
);
6065
}
6166

@@ -118,7 +123,7 @@ export class TwoFactorSetupComponent extends BaseTwoFactorSetupComponent impleme
118123
}
119124

120125
protected getTwoFactorProviders() {
121-
return this.twoFactorApiService.getTwoFactorOrganizationProviders(this.organizationId);
126+
return this.twoFactorService.getTwoFactorOrganizationProviders(this.organizationId);
122127
}
123128

124129
protected filterProvider(type: TwoFactorProviderType): boolean {

apps/web/src/app/auth/settings/account/change-email.component.spec.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import { ApiService } from "@bitwarden/common/abstractions/api.service";
77
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
88
import { TwoFactorProviderType } from "@bitwarden/common/auth/enums/two-factor-provider-type";
99
import { TwoFactorProviderResponse } from "@bitwarden/common/auth/models/response/two-factor-provider.response";
10-
import { TwoFactorApiService } from "@bitwarden/common/auth/two-factor";
10+
import { TwoFactorService } from "@bitwarden/common/auth/two-factor";
1111
import { ListResponse } from "@bitwarden/common/models/response/list.response";
1212
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
1313
import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service";
@@ -23,14 +23,14 @@ describe("ChangeEmailComponent", () => {
2323
let fixture: ComponentFixture<ChangeEmailComponent>;
2424

2525
let apiService: MockProxy<ApiService>;
26-
let twoFactorApiService: MockProxy<TwoFactorApiService>;
26+
let twoFactorService: MockProxy<TwoFactorService>;
2727
let accountService: FakeAccountService;
2828
let keyService: MockProxy<KeyService>;
2929
let kdfConfigService: MockProxy<KdfConfigService>;
3030

3131
beforeEach(async () => {
3232
apiService = mock<ApiService>();
33-
twoFactorApiService = mock<TwoFactorApiService>();
33+
twoFactorService = mock<TwoFactorService>();
3434
keyService = mock<KeyService>();
3535
kdfConfigService = mock<KdfConfigService>();
3636
accountService = mockAccountServiceWith("UserId" as UserId);
@@ -40,7 +40,7 @@ describe("ChangeEmailComponent", () => {
4040
providers: [
4141
{ provide: AccountService, useValue: accountService },
4242
{ provide: ApiService, useValue: apiService },
43-
{ provide: TwoFactorApiService, useValue: twoFactorApiService },
43+
{ provide: TwoFactorService, useValue: twoFactorService },
4444
{ provide: I18nService, useValue: { t: (key: string) => key } },
4545
{ provide: KeyService, useValue: keyService },
4646
{ provide: MessagingService, useValue: mock<MessagingService>() },
@@ -61,7 +61,7 @@ describe("ChangeEmailComponent", () => {
6161

6262
describe("ngOnInit", () => {
6363
beforeEach(() => {
64-
twoFactorApiService.getTwoFactorProviders.mockResolvedValue({
64+
twoFactorService.getEnabledTwoFactorProviders.mockResolvedValue({
6565
data: [{ type: TwoFactorProviderType.Email, enabled: true } as TwoFactorProviderResponse],
6666
} as ListResponse<TwoFactorProviderResponse>);
6767
});

apps/web/src/app/auth/settings/account/change-email.component.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import { TwoFactorProviderType } from "@bitwarden/common/auth/enums/two-factor-p
88
import { EmailTokenRequest } from "@bitwarden/common/auth/models/request/email-token.request";
99
import { EmailRequest } from "@bitwarden/common/auth/models/request/email.request";
1010
import { getUserId } from "@bitwarden/common/auth/services/account.service";
11-
import { TwoFactorApiService } from "@bitwarden/common/auth/two-factor";
11+
import { TwoFactorService } from "@bitwarden/common/auth/two-factor";
1212
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
1313
import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service";
1414
import { UserId } from "@bitwarden/common/types/guid";
@@ -40,7 +40,7 @@ export class ChangeEmailComponent implements OnInit {
4040
constructor(
4141
private accountService: AccountService,
4242
private apiService: ApiService,
43-
private twoFactorApiService: TwoFactorApiService,
43+
private twoFactorService: TwoFactorService,
4444
private i18nService: I18nService,
4545
private keyService: KeyService,
4646
private messagingService: MessagingService,
@@ -52,7 +52,7 @@ export class ChangeEmailComponent implements OnInit {
5252
async ngOnInit() {
5353
this.userId = await firstValueFrom(getUserId(this.accountService.activeAccount$));
5454

55-
const twoFactorProviders = await this.twoFactorApiService.getTwoFactorProviders();
55+
const twoFactorProviders = await this.twoFactorService.getEnabledTwoFactorProviders();
5656
this.showTwoFactorEmailWarning = twoFactorProviders.data.some(
5757
(p) => p.type === TwoFactorProviderType.Email && p.enabled,
5858
);

apps/web/src/app/auth/settings/account/set-account-verify-devices-dialog.component.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import { AccountApiService } from "@bitwarden/common/auth/abstractions/account-a
99
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
1010
import { UserVerificationService } from "@bitwarden/common/auth/abstractions/user-verification/user-verification.service.abstraction";
1111
import { SetVerifyDevicesRequest } from "@bitwarden/common/auth/models/request/set-verify-devices.request";
12-
import { TwoFactorApiService } from "@bitwarden/common/auth/two-factor";
12+
import { TwoFactorService } from "@bitwarden/common/auth/two-factor";
1313
import { Verification } from "@bitwarden/common/auth/types/verification";
1414
import { ErrorResponse } from "@bitwarden/common/models/response/error.response";
1515
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
@@ -66,7 +66,7 @@ export class SetAccountVerifyDevicesDialogComponent implements OnInit, OnDestroy
6666
private userVerificationService: UserVerificationService,
6767
private dialogRef: DialogRef,
6868
private toastService: ToastService,
69-
private twoFactorApiService: TwoFactorApiService,
69+
private twoFactorService: TwoFactorService,
7070
) {
7171
this.accountService.accountVerifyNewDeviceLogin$
7272
.pipe(takeUntil(this.destroy$))
@@ -76,7 +76,7 @@ export class SetAccountVerifyDevicesDialogComponent implements OnInit, OnDestroy
7676
}
7777

7878
async ngOnInit() {
79-
const twoFactorProviders = await this.twoFactorApiService.getTwoFactorProviders();
79+
const twoFactorProviders = await this.twoFactorService.getEnabledTwoFactorProviders();
8080
this.has2faConfigured = twoFactorProviders.data.length > 0;
8181
}
8282

apps/web/src/app/auth/settings/two-factor/two-factor-setup-authenticator.component.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import { TwoFactorProviderType } from "@bitwarden/common/auth/enums/two-factor-p
1212
import { DisableTwoFactorAuthenticatorRequest } from "@bitwarden/common/auth/models/request/disable-two-factor-authenticator.request";
1313
import { UpdateTwoFactorAuthenticatorRequest } from "@bitwarden/common/auth/models/request/update-two-factor-authenticator.request";
1414
import { TwoFactorAuthenticatorResponse } from "@bitwarden/common/auth/models/response/two-factor-authenticator.response";
15-
import { TwoFactorApiService } from "@bitwarden/common/auth/two-factor";
15+
import { TwoFactorService } from "@bitwarden/common/auth/two-factor";
1616
import { AuthResponse } from "@bitwarden/common/auth/types/auth-response";
1717
import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service";
1818
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
@@ -96,7 +96,7 @@ export class TwoFactorSetupAuthenticatorComponent
9696
constructor(
9797
@Inject(DIALOG_DATA) protected data: AuthResponse<TwoFactorAuthenticatorResponse>,
9898
private dialogRef: DialogRef,
99-
twoFactorApiService: TwoFactorApiService,
99+
twoFactorService: TwoFactorService,
100100
i18nService: I18nService,
101101
userVerificationService: UserVerificationService,
102102
private formBuilder: FormBuilder,
@@ -108,7 +108,7 @@ export class TwoFactorSetupAuthenticatorComponent
108108
protected toastService: ToastService,
109109
) {
110110
super(
111-
twoFactorApiService,
111+
twoFactorService,
112112
i18nService,
113113
platformUtilsService,
114114
logService,
@@ -158,7 +158,7 @@ export class TwoFactorSetupAuthenticatorComponent
158158
request.key = this.key;
159159
request.userVerificationToken = this.userVerificationToken;
160160

161-
const response = await this.twoFactorApiService.putTwoFactorAuthenticator(request);
161+
const response = await this.twoFactorService.putTwoFactorAuthenticator(request);
162162
await this.processResponse(response);
163163
this.onUpdated.emit(true);
164164
}
@@ -178,7 +178,7 @@ export class TwoFactorSetupAuthenticatorComponent
178178
request.type = this.type;
179179
request.key = this.key;
180180
request.userVerificationToken = this.userVerificationToken;
181-
await this.twoFactorApiService.deleteTwoFactorAuthenticator(request);
181+
await this.twoFactorService.deleteTwoFactorAuthenticator(request);
182182
this.enabled = false;
183183
this.toastService.showToast({
184184
variant: "success",

apps/web/src/app/auth/settings/two-factor/two-factor-setup-duo.component.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import { UserVerificationService } from "@bitwarden/common/auth/abstractions/use
66
import { TwoFactorProviderType } from "@bitwarden/common/auth/enums/two-factor-provider-type";
77
import { UpdateTwoFactorDuoRequest } from "@bitwarden/common/auth/models/request/update-two-factor-duo.request";
88
import { TwoFactorDuoResponse } from "@bitwarden/common/auth/models/response/two-factor-duo.response";
9-
import { TwoFactorApiService } from "@bitwarden/common/auth/two-factor";
9+
import { TwoFactorService } from "@bitwarden/common/auth/two-factor";
1010
import { AuthResponse } from "@bitwarden/common/auth/types/auth-response";
1111
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
1212
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
@@ -67,7 +67,7 @@ export class TwoFactorSetupDuoComponent
6767

6868
constructor(
6969
@Inject(DIALOG_DATA) protected data: TwoFactorDuoComponentConfig,
70-
twoFactorApiService: TwoFactorApiService,
70+
twoFactorService: TwoFactorService,
7171
i18nService: I18nService,
7272
platformUtilsService: PlatformUtilsService,
7373
logService: LogService,
@@ -78,7 +78,7 @@ export class TwoFactorSetupDuoComponent
7878
protected toastService: ToastService,
7979
) {
8080
super(
81-
twoFactorApiService,
81+
twoFactorService,
8282
i18nService,
8383
platformUtilsService,
8484
logService,
@@ -143,12 +143,12 @@ export class TwoFactorSetupDuoComponent
143143
let response: TwoFactorDuoResponse;
144144

145145
if (this.organizationId != null) {
146-
response = await this.twoFactorApiService.putTwoFactorOrganizationDuo(
146+
response = await this.twoFactorService.putTwoFactorOrganizationDuo(
147147
this.organizationId,
148148
request,
149149
);
150150
} else {
151-
response = await this.twoFactorApiService.putTwoFactorDuo(request);
151+
response = await this.twoFactorService.putTwoFactorDuo(request);
152152
}
153153

154154
this.processResponse(response);

0 commit comments

Comments
 (0)