1
0
mirror of https://github.com/bitwarden/browser.git synced 2025-03-22 15:19:15 +01:00

[PM-5800] Remove passwordless-login feature flag ()

* Removed passwordless-login feature flag

* Removed conditional on login component.

* Added back reference accidentally deleted.

* Fixed initialization of the service in tests.

* Removed unused private variable.

* Updated DI to remove configService

* Undid changes to workspace file.

* Undid all changes to workspace file

* Undid merge changes to collection dialog

* Linting
This commit is contained in:
Todd Martin 2024-02-13 11:15:16 -05:00 committed by GitHub
parent 2fa7580229
commit bdc951194e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 10 additions and 68 deletions

View File

@ -51,10 +51,7 @@
</button>
</div>
<div
class="tw-mb-3 tw-flex tw-flex-col tw-items-center tw-justify-center"
*ngIf="showWebauthnLogin$ | async"
>
<div class="tw-mb-3 tw-flex tw-flex-col tw-items-center tw-justify-center">
<p class="tw-mb-3">{{ "or" | i18n }}</p>
<a

View File

@ -126,6 +126,4 @@
</button>
</form>
<app-webauthn-login-settings
*ngIf="showWebauthnLoginSettings$ | async"
></app-webauthn-login-settings>
<app-webauthn-login-settings></app-webauthn-login-settings>

View File

@ -1,6 +1,5 @@
import { Component } from "@angular/core";
import { Router } from "@angular/router";
import { Observable } from "rxjs";
import { ChangePasswordComponent as BaseChangePasswordComponent } from "@bitwarden/angular/auth/components/change-password.component";
import { ApiService } from "@bitwarden/common/abstractions/api.service";
@ -8,7 +7,6 @@ import { AuditService } from "@bitwarden/common/abstractions/audit.service";
import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.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";
import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum";
import { ConfigServiceAbstraction } from "@bitwarden/common/platform/abstractions/config/config.service.abstraction";
import { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.service";
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
@ -35,8 +33,6 @@ export class ChangePasswordComponent extends BaseChangePasswordComponent {
checkForBreaches = true;
characterMinimumMessage = "";
protected showWebauthnLoginSettings$: Observable<boolean>;
constructor(
i18nService: I18nService,
cryptoService: CryptoService,
@ -68,10 +64,6 @@ export class ChangePasswordComponent extends BaseChangePasswordComponent {
}
async ngOnInit() {
this.showWebauthnLoginSettings$ = this.configService.getFeatureFlag$(
FeatureFlag.PasswordlessLogin,
);
if (!(await this.userVerificationService.hasMasterPassword())) {
// 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

View File

@ -1,7 +1,7 @@
import { Directive, ElementRef, NgZone, OnDestroy, OnInit, ViewChild } from "@angular/core";
import { FormBuilder, Validators } from "@angular/forms";
import { ActivatedRoute, Router } from "@angular/router";
import { Observable, Subject } from "rxjs";
import { Subject } from "rxjs";
import { take, takeUntil } from "rxjs/operators";
import { LoginStrategyServiceAbstraction, PasswordLoginCredentials } from "@bitwarden/auth/common";
@ -54,7 +54,6 @@ export class LoginComponent extends CaptchaProtectedComponent implements OnInit,
protected twoFactorRoute = "2fa";
protected successRoute = "vault";
protected forcePasswordResetRoute = "update-temp-password";
protected showWebauthnLogin$: Observable<boolean>;
protected destroy$ = new Subject<void>();
@ -90,8 +89,6 @@ export class LoginComponent extends CaptchaProtectedComponent implements OnInit,
}
async ngOnInit() {
this.showWebauthnLogin$ = this.webAuthnLoginService.enabled$;
this.route?.queryParams.pipe(takeUntil(this.destroy$)).subscribe((params) => {
if (!params) {
return;

View File

@ -864,7 +864,6 @@ import { ModalService } from "./modal.service";
deps: [
WebAuthnLoginApiServiceAbstraction,
LoginStrategyServiceAbstraction,
ConfigServiceAbstraction,
WebAuthnLoginPrfCryptoServiceAbstraction,
WINDOW,
LogService,

View File

@ -1,5 +1,3 @@
import { Observable } from "rxjs";
import { AuthResult } from "../../models/domain/auth-result";
import { WebAuthnLoginCredentialAssertionOptionsView } from "../../models/view/webauthn-login/webauthn-login-credential-assertion-options.view";
import { WebAuthnLoginCredentialAssertionView } from "../../models/view/webauthn-login/webauthn-login-credential-assertion.view";
@ -8,11 +6,6 @@ import { WebAuthnLoginCredentialAssertionView } from "../../models/view/webauthn
* Service for logging in with WebAuthnLogin credentials.
*/
export abstract class WebAuthnLoginServiceAbstraction {
/**
* An Observable that emits a boolean indicating whether the WebAuthn login feature is enabled.
*/
readonly enabled$: Observable<boolean>;
/**
* Gets the credential assertion options needed for initiating the WebAuthn
* authentication process. It should provide the challenge and other data

View File

@ -1,9 +1,7 @@
import { mock } from "jest-mock-extended";
import { firstValueFrom, of } from "rxjs";
import { LoginStrategyServiceAbstraction, WebAuthnLoginCredentials } from "@bitwarden/auth/common";
import { ConfigServiceAbstraction } from "../../../platform/abstractions/config/config.service.abstraction";
import { LogService } from "../../../platform/abstractions/log.service";
import { Utils } from "../../../platform/misc/utils";
import { SymmetricCryptoKey } from "../../../platform/models/domain/symmetric-crypto-key";
@ -23,7 +21,6 @@ describe("WebAuthnLoginService", () => {
const webAuthnLoginApiService = mock<WebAuthnLoginApiServiceAbstraction>();
const loginStrategyService = mock<LoginStrategyServiceAbstraction>();
const configService = mock<ConfigServiceAbstraction>();
const webAuthnLoginPrfCryptoService = mock<WebAuthnLoginPrfCryptoServiceAbstraction>();
const navigatorCredentials = mock<CredentialsContainer>();
const logService = mock<LogService>();
@ -71,12 +68,10 @@ describe("WebAuthnLoginService", () => {
});
});
function createWebAuthnLoginService(config: { featureEnabled: boolean }): WebAuthnLoginService {
configService.getFeatureFlag$.mockReturnValue(of(config.featureEnabled));
function createWebAuthnLoginService(): WebAuthnLoginService {
return new WebAuthnLoginService(
webAuthnLoginApiService,
loginStrategyService,
configService,
webAuthnLoginPrfCryptoService,
window,
logService,
@ -84,34 +79,14 @@ describe("WebAuthnLoginService", () => {
}
it("instantiates", () => {
webAuthnLoginService = createWebAuthnLoginService({ featureEnabled: true });
webAuthnLoginService = createWebAuthnLoginService();
expect(webAuthnLoginService).not.toBeFalsy();
});
describe("enabled$", () => {
it("should emit true when feature flag for PasswordlessLogin is enabled", async () => {
// Arrange
const webAuthnLoginService = createWebAuthnLoginService({ featureEnabled: true });
// Act & Assert
const result = await firstValueFrom(webAuthnLoginService.enabled$);
expect(result).toBe(true);
});
it("should emit false when feature flag for PasswordlessLogin is disabled", async () => {
// Arrange
const webAuthnLoginService = createWebAuthnLoginService({ featureEnabled: false });
// Act & Assert
const result = await firstValueFrom(webAuthnLoginService.enabled$);
expect(result).toBe(false);
});
});
describe("getCredentialAssertionOptions()", () => {
it("webAuthnLoginService returns WebAuthnLoginCredentialAssertionOptionsView when getCredentialAssertionOptions is called with the feature enabled", async () => {
// Arrange
const webAuthnLoginService = createWebAuthnLoginService({ featureEnabled: true });
const webAuthnLoginService = createWebAuthnLoginService();
const challenge = "6CG3jqMCVASJVXySMi9KWw";
const token = "BWWebAuthnLoginAssertionOptions_CfDJ_2KBN892w";
@ -154,7 +129,7 @@ describe("WebAuthnLoginService", () => {
describe("assertCredential(...)", () => {
it("should assert the credential and return WebAuthnLoginAssertionView on success", async () => {
// Arrange
const webAuthnLoginService = createWebAuthnLoginService({ featureEnabled: true });
const webAuthnLoginService = createWebAuthnLoginService();
const credentialAssertionOptions = buildCredentialAssertionOptions();
// Mock webAuthnUtils functions
@ -222,7 +197,7 @@ describe("WebAuthnLoginService", () => {
it("should return undefined on non-PublicKeyCredential browser response", async () => {
// Arrange
const webAuthnLoginService = createWebAuthnLoginService({ featureEnabled: true });
const webAuthnLoginService = createWebAuthnLoginService();
const credentialAssertionOptions = buildCredentialAssertionOptions();
// Mock the navigatorCredentials.get to return null
@ -237,7 +212,7 @@ describe("WebAuthnLoginService", () => {
it("should log an error and return undefined when navigatorCredentials.get throws an error", async () => {
// Arrange
const webAuthnLoginService = createWebAuthnLoginService({ featureEnabled: true });
const webAuthnLoginService = createWebAuthnLoginService();
const credentialAssertionOptions = buildCredentialAssertionOptions();
// Mock navigatorCredentials.get to throw an error
@ -269,7 +244,7 @@ describe("WebAuthnLoginService", () => {
it("should accept an assertion with a signed challenge and use it to try and login", async () => {
// Arrange
const webAuthnLoginService = createWebAuthnLoginService({ featureEnabled: true });
const webAuthnLoginService = createWebAuthnLoginService();
const assertion = buildWebAuthnLoginCredentialAssertionView();
const mockAuthResult: AuthResult = new AuthResult();

View File

@ -1,9 +1,5 @@
import { Observable } from "rxjs";
import { LoginStrategyServiceAbstraction, WebAuthnLoginCredentials } from "@bitwarden/auth/common";
import { FeatureFlag } from "../../../enums/feature-flag.enum";
import { ConfigServiceAbstraction } from "../../../platform/abstractions/config/config.service.abstraction";
import { LogService } from "../../../platform/abstractions/log.service";
import { PrfKey } from "../../../types/key";
import { WebAuthnLoginApiServiceAbstraction } from "../../abstractions/webauthn/webauthn-login-api.service.abstraction";
@ -16,19 +12,15 @@ import { WebAuthnLoginCredentialAssertionView } from "../../models/view/webauthn
import { WebAuthnLoginAssertionResponseRequest } from "./request/webauthn-login-assertion-response.request";
export class WebAuthnLoginService implements WebAuthnLoginServiceAbstraction {
readonly enabled$: Observable<boolean>;
private navigatorCredentials: CredentialsContainer;
constructor(
private webAuthnLoginApiService: WebAuthnLoginApiServiceAbstraction,
private loginStrategyService: LoginStrategyServiceAbstraction,
private configService: ConfigServiceAbstraction,
private webAuthnLoginPrfCryptoService: WebAuthnLoginPrfCryptoServiceAbstraction,
private window: Window,
private logService?: LogService,
) {
this.enabled$ = this.configService.getFeatureFlag$(FeatureFlag.PasswordlessLogin, false);
this.navigatorCredentials = this.window.navigator.credentials;
}

View File

@ -1,5 +1,4 @@
export enum FeatureFlag {
PasswordlessLogin = "passwordless-login",
BrowserFilelessImport = "browser-fileless-import",
ItemShare = "item-share",
FlexibleCollectionsV1 = "flexible-collections-v-1", // v-1 is intentional