1
0
mirror of https://github.com/bitwarden/browser synced 2025-12-15 15:53:27 +00:00

feat(auth): [PM-9693] Refresh LoginDecryptionOptionsComponent (#11782)

Creates a refreshed and consolidated `LoginDecryptionOptionsComponent` for use on all visual clients, which will be used when the `UnauthenticatedExtensionUIRefresh` feature flag is on.
This commit is contained in:
rr-bw
2024-11-21 13:31:20 -08:00
committed by GitHub
parent 228817b85f
commit 9f99454b37
31 changed files with 742 additions and 38 deletions

View File

@@ -1,4 +1,5 @@
export * from "./login";
export * from "./login-decryption-options";
export * from "./webauthn-login";
export * from "./set-password-jit";
export * from "./registration";

View File

@@ -0,0 +1 @@
export * from "./web-login-decryption-options.service";

View File

@@ -0,0 +1,41 @@
import { MockProxy, mock } from "jest-mock-extended";
import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service";
import { RouterService } from "../../../../core/router.service";
import { AcceptOrganizationInviteService } from "../../../organization-invite/accept-organization.service";
import { WebLoginDecryptionOptionsService } from "./web-login-decryption-options.service";
describe("WebLoginDecryptionOptionsService", () => {
let service: WebLoginDecryptionOptionsService;
let messagingService: MockProxy<MessagingService>;
let routerService: MockProxy<RouterService>;
let acceptOrganizationInviteService: MockProxy<AcceptOrganizationInviteService>;
beforeEach(() => {
messagingService = mock<MessagingService>();
routerService = mock<RouterService>();
acceptOrganizationInviteService = mock<AcceptOrganizationInviteService>();
service = new WebLoginDecryptionOptionsService(
messagingService,
routerService,
acceptOrganizationInviteService,
);
});
it("should instantiate the service", () => {
expect(service).not.toBeFalsy();
});
describe("handleCreateUserSuccess()", () => {
it("should clear the redirect URL and the org invite", async () => {
await service.handleCreateUserSuccess();
expect(routerService.getAndClearLoginRedirectUrl).toHaveBeenCalled();
expect(acceptOrganizationInviteService.clearOrganizationInvitation).toHaveBeenCalled();
});
});
});

View File

@@ -0,0 +1,33 @@
import {
LoginDecryptionOptionsService,
DefaultLoginDecryptionOptionsService,
} from "@bitwarden/auth/angular";
import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service";
import { RouterService } from "../../../../core/router.service";
import { AcceptOrganizationInviteService } from "../../../organization-invite/accept-organization.service";
export class WebLoginDecryptionOptionsService
extends DefaultLoginDecryptionOptionsService
implements LoginDecryptionOptionsService
{
constructor(
protected messagingService: MessagingService,
private routerService: RouterService,
private acceptOrganizationInviteService: AcceptOrganizationInviteService,
) {
super(messagingService);
}
override async handleCreateUserSuccess(): Promise<void> {
try {
// Invites from TDE orgs go through here, but the invite is
// accepted while being enrolled in admin recovery. So we need to clear
// the redirect and stored org invite.
await this.routerService.getAndClearLoginRedirectUrl();
await this.acceptOrganizationInviteService.clearOrganizationInvitation();
} catch (error) {
throw new Error(error);
}
}
}

View File

@@ -1,14 +1,14 @@
import { Component, inject } from "@angular/core";
import { BaseLoginDecryptionOptionsComponent } from "@bitwarden/angular/auth/components/base-login-decryption-options.component";
import { BaseLoginDecryptionOptionsComponentV1 } from "@bitwarden/angular/auth/components/base-login-decryption-options-v1.component";
import { RouterService } from "../../../core";
import { AcceptOrganizationInviteService } from "../../organization-invite/accept-organization.service";
@Component({
selector: "web-login-decryption-options",
templateUrl: "login-decryption-options.component.html",
templateUrl: "login-decryption-options-v1.component.html",
})
export class LoginDecryptionOptionsComponent extends BaseLoginDecryptionOptionsComponent {
export class LoginDecryptionOptionsComponentV1 extends BaseLoginDecryptionOptionsComponentV1 {
protected routerService = inject(RouterService);
protected acceptOrganizationInviteService = inject(AcceptOrganizationInviteService);

View File

@@ -4,7 +4,7 @@ import { CheckboxModule } from "@bitwarden/components";
import { SharedModule } from "../../../app/shared";
import { LoginDecryptionOptionsComponent } from "./login-decryption-options/login-decryption-options.component";
import { LoginDecryptionOptionsComponentV1 } from "./login-decryption-options/login-decryption-options-v1.component";
import { LoginComponentV1 } from "./login-v1.component";
import { LoginViaAuthRequestComponentV1 } from "./login-via-auth-request-v1.component";
import { LoginViaWebAuthnComponent } from "./login-via-webauthn/login-via-webauthn.component";
@@ -14,13 +14,13 @@ import { LoginViaWebAuthnComponent } from "./login-via-webauthn/login-via-webaut
declarations: [
LoginComponentV1,
LoginViaAuthRequestComponentV1,
LoginDecryptionOptionsComponent,
LoginDecryptionOptionsComponentV1,
LoginViaWebAuthnComponent,
],
exports: [
LoginComponentV1,
LoginViaAuthRequestComponentV1,
LoginDecryptionOptionsComponent,
LoginDecryptionOptionsComponentV1,
LoginViaWebAuthnComponent,
],
})

View File

@@ -30,6 +30,7 @@ import {
LoginComponentService,
LockComponentService,
SetPasswordJitService,
LoginDecryptionOptionsService,
} from "@bitwarden/auth/angular";
import {
InternalUserDecryptionOptionsServiceAbstraction,
@@ -60,6 +61,7 @@ import {
import { FileDownloadService } from "@bitwarden/common/platform/abstractions/file-download/file-download.service";
import { I18nService as I18nServiceAbstraction } 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 { SdkClientFactory } from "@bitwarden/common/platform/abstractions/sdk/sdk-client-factory";
import { AbstractStorageService } from "@bitwarden/common/platform/abstractions/storage.service";
@@ -95,6 +97,7 @@ import {
WebRegistrationFinishService,
WebLoginComponentService,
WebLockComponentService,
WebLoginDecryptionOptionsService,
} from "../auth";
import { AcceptOrganizationInviteService } from "../auth/organization-invite/accept-organization.service";
import { HtmlStorageService } from "../core/html-storage.service";
@@ -296,6 +299,11 @@ const safeProviders: SafeProvider[] = [
useClass: LoginEmailService,
deps: [AccountService, AuthService, StateProvider],
}),
safeProvider({
provide: LoginDecryptionOptionsService,
useClass: WebLoginDecryptionOptionsService,
deps: [MessagingService, RouterService, AcceptOrganizationInviteService],
}),
];
@NgModule({

View File

@@ -33,6 +33,7 @@ import {
RegistrationLockAltIcon,
RegistrationExpiredLinkIcon,
VaultIcon,
LoginDecryptionOptionsComponent,
} from "@bitwarden/auth/angular";
import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum";
@@ -46,7 +47,7 @@ import { CreateOrganizationComponent } from "./admin-console/settings/create-org
import { deepLinkGuard } from "./auth/guards/deep-link.guard";
import { HintComponent } from "./auth/hint.component";
import { LockComponent } from "./auth/lock.component";
import { LoginDecryptionOptionsComponent } from "./auth/login/login-decryption-options/login-decryption-options.component";
import { LoginDecryptionOptionsComponentV1 } from "./auth/login/login-decryption-options/login-decryption-options-v1.component";
import { LoginComponentV1 } from "./auth/login/login-v1.component";
import { LoginViaAuthRequestComponentV1 } from "./auth/login/login-via-auth-request-v1.component";
import { LoginViaWebAuthnComponent } from "./auth/login/login-via-webauthn/login-via-webauthn.component";
@@ -103,11 +104,6 @@ const routes: Routes = [
component: LoginViaWebAuthnComponent,
data: { titleId: "logInWithPasskey" } satisfies RouteDataProperties,
},
{
path: "login-initiated",
component: LoginDecryptionOptionsComponent,
canActivate: [tdeDecryptionRequiredGuard()],
},
{
path: "register",
component: TrialInitiationComponent,
@@ -272,6 +268,22 @@ const routes: Routes = [
],
},
),
...unauthUiRefreshSwap(
LoginDecryptionOptionsComponentV1,
AnonLayoutWrapperComponent,
{
path: "login-initiated",
canActivate: [tdeDecryptionRequiredGuard()],
},
{
path: "login-initiated",
canActivate: [tdeDecryptionRequiredGuard()],
data: {
pageIcon: DevicesIcon,
},
children: [{ path: "", component: LoginDecryptionOptionsComponent }],
},
),
...unauthUiRefreshSwap(
AnonLayoutWrapperComponent,
AnonLayoutWrapperComponent,

View File

@@ -8051,9 +8051,18 @@
"loginInitiated": {
"message": "Login initiated"
},
"rememberThisDeviceToMakeFutureLoginsSeamless": {
"message": "Remember this device to make future logins seamless"
},
"deviceApprovalRequired": {
"message": "Device approval required. Select an approval option below:"
},
"deviceApprovalRequiredV2": {
"message": "Device approval required"
},
"selectAnApprovalOptionBelow": {
"message": "Select an approval option below"
},
"rememberThisDevice": {
"message": "Remember this device"
},
@@ -8283,6 +8292,9 @@
"userEmailMissing": {
"message": "User email missing"
},
"activeUserEmailNotFoundLoggingYouOut": {
"message": "Active user email not found. Logging you out."
},
"deviceTrusted": {
"message": "Device trusted"
},