1
0
mirror of https://github.com/bitwarden/browser synced 2026-01-18 00:13:29 +00:00

feat(auth): [PM-9674] Remove Deprecated LockComponents (#12453)

This PR deletes the legacy lock components from the Angular clients and also removes feature flag control from the routing. The lock component will now be based entirely on the new, recently refreshed LockComponent in libs/auth/angular.
This commit is contained in:
rr-bw
2024-12-20 10:23:03 -08:00
committed by GitHub
parent 2e6031eee9
commit d209da4c94
14 changed files with 31 additions and 1629 deletions

View File

@@ -1,100 +0,0 @@
<form (ngSubmit)="submit()">
<app-header>
<div class="left"></div>
<h1 class="center">
<span class="title">{{ "verifyIdentity" | i18n }}</span>
</h1>
<div class="right">
<button type="submit" *ngIf="pinEnabled || masterPasswordEnabled">
{{ "unlock" | i18n }}
</button>
</div>
</app-header>
<main tabindex="-1">
<ng-container *ngIf="fido2PopoutSessionData$ | async as fido2Data">
<div class="box">
<div class="box-content">
<div
class="box-content-row box-content-row-flex"
appBoxRow
*ngIf="pinEnabled || masterPasswordEnabled"
>
<div class="row-main" *ngIf="pinEnabled">
<label for="pin">{{ "pin" | i18n }}</label>
<input
id="pin"
type="{{ showPassword ? 'text' : 'password' }}"
name="PIN"
class="monospaced"
[(ngModel)]="pin"
required
appInputVerbatim
/>
</div>
<div class="row-main" *ngIf="masterPasswordEnabled && !pinEnabled">
<label for="masterPassword">{{ "masterPass" | i18n }}</label>
<input
id="masterPassword"
type="{{ showPassword ? 'text' : 'password' }}"
name="MasterPassword"
aria-describedby="masterPasswordHelp"
class="monospaced"
[(ngModel)]="masterPassword"
required
appInputVerbatim
/>
</div>
<div class="action-buttons">
<button
type="button"
class="row-btn"
appStopClick
appA11yTitle="{{ 'toggleVisibility' | i18n }}"
(click)="togglePassword()"
[attr.aria-pressed]="showPassword"
>
<i
class="bwi bwi-lg"
[ngClass]="{ 'bwi-eye': !showPassword, 'bwi-eye-slash': showPassword }"
aria-hidden="true"
></i>
</button>
</div>
</div>
</div>
<div id="masterPasswordHelp" class="box-footer">
<p>
{{
fido2Data.isFido2Session
? ("yourPasskeyIsLocked" | i18n)
: ("yourVaultIsLocked" | i18n)
}}
</p>
{{ "loggedInAsOn" | i18n: email : webVaultHostname }}
</div>
</div>
<div class="box" *ngIf="biometricLock">
<div class="box-footer no-pad">
<button
type="button"
class="btn primary block"
(click)="unlockBiometric()"
appStopClick
[disabled]="pendingBiometric"
>
{{ "unlockWithBiometrics" | i18n }}
</button>
</div>
</div>
<p class="text-center" *ngIf="!fido2Data.isFido2Session">
<button type="button" appStopClick (click)="logOut()">{{ "logOut" | i18n }}</button>
</p>
<app-callout *ngIf="biometricError" type="danger">{{ biometricError }}</app-callout>
<p class="text-center text-muted" *ngIf="pendingBiometric">
<i class="bwi bwi-spinner bwi-spin" aria-hidden="true"></i> {{ "awaitDesktop" | i18n }}
</p>
<app-fido2-use-browser-link-v1></app-fido2-use-browser-link-v1>
</ng-container>
</main>
</form>

View File

@@ -1,185 +0,0 @@
// FIXME: Update this file to be type safe and remove this and next line
// @ts-strict-ignore
import { Component, NgZone, OnInit } from "@angular/core";
import { Router } from "@angular/router";
import { firstValueFrom } from "rxjs";
import { LockComponent as BaseLockComponent } from "@bitwarden/angular/auth/components/lock.component";
import { PinServiceAbstraction } from "@bitwarden/auth/common";
import { ApiService } from "@bitwarden/common/abstractions/api.service";
import { VaultTimeoutSettingsService } from "@bitwarden/common/abstractions/vault-timeout/vault-timeout-settings.service";
import { VaultTimeoutService } from "@bitwarden/common/abstractions/vault-timeout/vault-timeout.service";
import { PolicyApiServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/policy/policy-api.service.abstraction";
import { InternalPolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction";
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
import { AuthService } from "@bitwarden/common/auth/abstractions/auth.service";
import { DeviceTrustServiceAbstraction } from "@bitwarden/common/auth/abstractions/device-trust.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 { AuthenticationStatus } from "@bitwarden/common/auth/enums/authentication-status";
import { EnvironmentService } from "@bitwarden/common/platform/abstractions/environment.service";
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service";
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
import { StateService } from "@bitwarden/common/platform/abstractions/state.service";
import { PasswordStrengthServiceAbstraction } from "@bitwarden/common/tools/password-strength";
import { SyncService } from "@bitwarden/common/vault/abstractions/sync/sync.service.abstraction";
import { DialogService, ToastService } from "@bitwarden/components";
import {
KdfConfigService,
KeyService,
BiometricsService,
BiometricStateService,
} from "@bitwarden/key-management";
import { BiometricErrors, BiometricErrorTypes } from "../../models/biometricErrors";
import { BrowserRouterService } from "../../platform/popup/services/browser-router.service";
import { fido2PopoutSessionData$ } from "../../vault/popup/utils/fido2-popout-session-data";
@Component({
selector: "app-lock",
templateUrl: "lock.component.html",
})
export class LockComponent extends BaseLockComponent implements OnInit {
private isInitialLockScreen: boolean;
biometricError: string;
pendingBiometric = false;
fido2PopoutSessionData$ = fido2PopoutSessionData$();
constructor(
masterPasswordService: InternalMasterPasswordServiceAbstraction,
router: Router,
i18nService: I18nService,
platformUtilsService: PlatformUtilsService,
messagingService: MessagingService,
keyService: KeyService,
vaultTimeoutService: VaultTimeoutService,
vaultTimeoutSettingsService: VaultTimeoutSettingsService,
environmentService: EnvironmentService,
stateService: StateService,
apiService: ApiService,
logService: LogService,
ngZone: NgZone,
policyApiService: PolicyApiServiceAbstraction,
policyService: InternalPolicyService,
passwordStrengthService: PasswordStrengthServiceAbstraction,
authService: AuthService,
dialogService: DialogService,
deviceTrustService: DeviceTrustServiceAbstraction,
userVerificationService: UserVerificationService,
pinService: PinServiceAbstraction,
private routerService: BrowserRouterService,
biometricStateService: BiometricStateService,
biometricsService: BiometricsService,
accountService: AccountService,
kdfConfigService: KdfConfigService,
syncService: SyncService,
toastService: ToastService,
) {
super(
masterPasswordService,
router,
i18nService,
platformUtilsService,
messagingService,
keyService,
vaultTimeoutService,
vaultTimeoutSettingsService,
environmentService,
stateService,
apiService,
logService,
ngZone,
policyApiService,
policyService,
passwordStrengthService,
dialogService,
deviceTrustService,
userVerificationService,
pinService,
biometricStateService,
biometricsService,
accountService,
authService,
kdfConfigService,
syncService,
toastService,
);
this.successRoute = "/tabs/current";
this.isInitialLockScreen = (window as any).previousPopupUrl == null;
this.onSuccessfulSubmit = async () => {
const previousUrl = this.routerService.getPreviousUrl();
if (previousUrl) {
// 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.router.navigateByUrl(previousUrl);
} else {
// 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.router.navigate([this.successRoute]);
}
};
}
async ngOnInit() {
await super.ngOnInit();
const autoBiometricsPrompt = await firstValueFrom(
this.biometricStateService.promptAutomatically$,
);
window.setTimeout(async () => {
document.getElementById(this.pinEnabled ? "pin" : "masterPassword")?.focus();
if (
this.biometricLock &&
autoBiometricsPrompt &&
this.isInitialLockScreen &&
(await this.authService.getAuthStatus()) === AuthenticationStatus.Locked
) {
await this.unlockBiometric(true);
}
}, 100);
}
override async unlockBiometric(automaticPrompt: boolean = false): Promise<boolean> {
if (!this.biometricLock) {
return;
}
this.biometricError = null;
let success;
try {
const available = await super.isBiometricUnlockAvailable();
if (!available) {
if (!automaticPrompt) {
await this.dialogService.openSimpleDialog({
type: "warning",
title: { key: "biometricsNotAvailableTitle" },
content: { key: "biometricsNotAvailableDesc" },
acceptButtonText: { key: "ok" },
cancelButtonText: null,
});
}
} else {
this.pendingBiometric = true;
success = await super.unlockBiometric();
}
} catch (e) {
const error = BiometricErrors[e?.message as BiometricErrorTypes];
if (error == null) {
this.logService.error("Unknown error: " + e);
return false;
}
this.biometricError = this.i18nService.t(error.description);
} finally {
this.pendingBiometric = false;
}
return success;
}
}

View File

@@ -17,7 +17,6 @@ import {
unauthGuardFn,
} from "@bitwarden/angular/auth/guards";
import { canAccessFeature } from "@bitwarden/angular/platform/guard/feature-flag.guard";
import { extensionRefreshRedirect } from "@bitwarden/angular/utils/extension-refresh-redirect";
import { extensionRefreshSwap } from "@bitwarden/angular/utils/extension-refresh-swap";
import { NewDeviceVerificationNoticeGuard } from "@bitwarden/angular/vault/guards";
import {
@@ -26,7 +25,7 @@ import {
LoginComponent,
LoginSecondaryContentComponent,
LockIcon,
LockV2Component,
LockComponent,
LoginViaAuthRequestComponent,
PasswordHintComponent,
RegistrationFinishComponent,
@@ -60,7 +59,6 @@ import {
} from "../auth/popup/extension-anon-layout-wrapper/extension-anon-layout-wrapper.component";
import { HintComponent } from "../auth/popup/hint.component";
import { HomeComponent } from "../auth/popup/home.component";
import { LockComponent } from "../auth/popup/lock.component";
import { LoginDecryptionOptionsComponentV1 } from "../auth/popup/login-decryption-options/login-decryption-options-v1.component";
import { LoginComponentV1 } from "../auth/popup/login-v1.component";
import { LoginViaAuthRequestComponentV1 } from "../auth/popup/login-via-auth-request-v1.component";
@@ -173,13 +171,6 @@ const routes: Routes = [
canActivate: [fido2AuthGuard],
data: { elevation: 1 } satisfies RouteDataProperties,
}),
{
path: "lock",
component: LockComponent,
canActivate: [lockGuard()],
canMatch: [extensionRefreshRedirect("/lockV2")],
data: { elevation: 1, doNotSaveUrl: true } satisfies RouteDataProperties,
},
...twofactorRefactorSwap(
TwoFactorComponent,
AnonLayoutWrapperComponent,
@@ -650,8 +641,8 @@ const routes: Routes = [
],
},
{
path: "lockV2",
canActivate: [canAccessFeature(FeatureFlag.ExtensionRefresh), lockGuard()],
path: "lock",
canActivate: [lockGuard()],
data: {
pageIcon: LockIcon,
pageTitle: {
@@ -662,19 +653,19 @@ const routes: Routes = [
elevation: 1,
/**
* This ensures that in a passkey flow the `/fido2?<queryParams>` URL does not get
* overwritten in the `BrowserRouterService` by the `/lockV2` route. This way, after
* overwritten in the `BrowserRouterService` by the `/lock` route. This way, after
* unlocking, the user can be redirected back to the `/fido2?<queryParams>` URL.
*
* Also, this prevents a routing loop when using biometrics to unlock the vault in MV2 (Firefox),
* locking up the browser (https://bitwarden.atlassian.net/browse/PM-16116). This involves the
* `popup-router-cache.service` pushing the `lockV2` route to the history.
* `popup-router-cache.service` pushing the `lock` route to the history.
*/
doNotSaveUrl: true,
} satisfies ExtensionAnonLayoutWrapperData & RouteDataProperties,
children: [
{
path: "",
component: LockV2Component,
component: LockComponent,
},
],
},

View File

@@ -23,7 +23,6 @@ import { EnvironmentComponent } from "../auth/popup/environment.component";
import { ExtensionAnonLayoutWrapperComponent } from "../auth/popup/extension-anon-layout-wrapper/extension-anon-layout-wrapper.component";
import { HintComponent } from "../auth/popup/hint.component";
import { HomeComponent } from "../auth/popup/home.component";
import { LockComponent } from "../auth/popup/lock.component";
import { LoginDecryptionOptionsComponentV1 } from "../auth/popup/login-decryption-options/login-decryption-options-v1.component";
import { LoginComponentV1 } from "../auth/popup/login-v1.component";
import { LoginViaAuthRequestComponentV1 } from "../auth/popup/login-via-auth-request-v1.component";
@@ -156,7 +155,6 @@ import "../platform/popup/locales";
VaultFilterComponent,
HintComponent,
HomeComponent,
LockComponent,
LoginViaAuthRequestComponentV1,
LoginComponentV1,
LoginDecryptionOptionsComponentV1,