Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. Weโ€™ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[PM-9693] Refresh - LoginDecryptionOptionsComponent #11782

Open
wants to merge 29 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
d0bc2b9
rename legacy components to v1
rr-bw Oct 29, 2024
f453cc8
setup new component and routes
rr-bw Oct 29, 2024
d8927de
add template
rr-bw Oct 29, 2024
69a9671
Merge branch 'main' into auth/pm-9693/refresh-login-decryption-optionโ€ฆ
rr-bw Oct 31, 2024
32148cf
setup rememberDevice control methods
rr-bw Oct 31, 2024
c4fa333
use takeUntilDestroyed(this.destroyRef)
rr-bw Oct 31, 2024
335958e
migrate loadUntrustedDeviceData() and requestAdminApproval() methods
rr-bw Oct 31, 2024
d5660a9
migrate approveFromOtherDevice() method
rr-bw Oct 31, 2024
a2c3735
migrate approveWithMasterPassword() method
rr-bw Oct 31, 2024
6aa416e
migrate loadNewUserData() and restructure template
rr-bw Oct 31, 2024
b7b613b
setup services
rr-bw Nov 2, 2024
869add9
migrate and refactor createUser() method
rr-bw Nov 2, 2024
7f0ff35
remove comment
rr-bw Nov 2, 2024
ab66de1
refactor email usage and loading state
rr-bw Nov 2, 2024
eea4aac
refactor UI data properties
rr-bw Nov 2, 2024
3e66a05
refactor properties
rr-bw Nov 2, 2024
236210c
Merge branch 'main' into auth/pm-9693/refresh-login-decryption-optionโ€ฆ
rr-bw Nov 4, 2024
ff7fbc7
small reformatting and cleanup
rr-bw Nov 4, 2024
44dd2e8
Merge branch 'main' into auth/pm-9693/refresh-login-decryption-optionโ€ฆ
rr-bw Nov 4, 2024
0ff5104
add tests
rr-bw Nov 5, 2024
f72c2a0
extract functions - handleMissingEmail and handleCreateUserSuccessNavโ€ฆ
rr-bw Nov 7, 2024
ac97fae
update AnonLayout properties via AnonLayoutWrapperDataService
rr-bw Nov 7, 2024
8ff004a
Merge branch 'main' into auth/pm-9693/refresh-login-decryption-optionโ€ฆ
rr-bw Nov 7, 2024
14ffc1f
add devices icon
rr-bw Nov 7, 2024
c1a6655
remove TODO comments
rr-bw Nov 7, 2024
e94bffd
update logic for when the 'or' text is shown
rr-bw Nov 7, 2024
430d684
Merge branch 'main' into auth/pm-9693/refresh-login-decryption-optionโ€ฆ
withinfocus Nov 11, 2024
df815b1
Merge branch 'main' into auth/pm-9693/refresh-login-decryption-optionโ€ฆ
rr-bw Nov 13, 2024
aab0f60
better handling of missing email case
rr-bw Nov 19, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions apps/browser/src/_locales/en/messages.json
Original file line number Diff line number Diff line change
Expand Up @@ -3249,9 +3249,18 @@
"opensInANewWindow": {
"message": "Opens in a new window"
},
"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"
},
Expand Down Expand Up @@ -3761,6 +3770,9 @@
"accessing": {
"message": "Accessing"
},
"loggedInExclamation": {
"message": "Logged in!"
},
"passkeyNotCopied": {
"message": "Passkey will not be copied"
},
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { Router } from "@angular/router";
import { firstValueFrom } from "rxjs";

import {
DefaultLoginDecryptionOptionsService,
LoginDecryptionOptionsService,
} from "@bitwarden/auth/angular";
import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service";

import { postLogoutMessageListener$ } from "../utils/post-logout-message-listener";

export class ExtensionLoginDecryptionOptionsService
extends DefaultLoginDecryptionOptionsService
implements LoginDecryptionOptionsService
{
constructor(
protected messagingService: MessagingService,
private router: Router,
) {
super(messagingService);
}

override async logOut(): Promise<void> {
// start listening for "switchAccountFinish" or "doneLoggingOut"
const messagePromise = firstValueFrom(postLogoutMessageListener$);

super.logOut();

// wait for messages
const command = await messagePromise;

// doneLoggingOut already has a message handler that will navigate us
if (command === "switchAccountFinish") {
await this.router.navigate(["/"]);
}
}
}
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
import { Component } from "@angular/core";
import { firstValueFrom } from "rxjs";

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 { postLogoutMessageListener$ } from "../utils/post-logout-message-listener";

@Component({
selector: "browser-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 {
override async createUser(): Promise<void> {
try {
await super.createUser();
Expand Down
32 changes: 25 additions & 7 deletions apps/browser/src/popup/app-routing.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ import {
SetPasswordJitComponent,
UserLockIcon,
VaultIcon,
LoginDecryptionOptionsComponent,
} from "@bitwarden/auth/angular";
import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum";

Expand All @@ -49,7 +50,7 @@ import {
import { HintComponent } from "../auth/popup/hint.component";
import { HomeComponent } from "../auth/popup/home.component";
import { LockComponent } from "../auth/popup/lock.component";
import { LoginDecryptionOptionsComponent } from "../auth/popup/login-decryption-options/login-decryption-options.component";
import { LoginDecryptionOptionsComponentV1 } from "../auth/popup/login-decryption-options/login-decryption-options-v1.component";
import { LoginComponentV1 } from "../auth/popup/login-v1.component";
import { LoginViaAuthRequestComponent } from "../auth/popup/login-via-auth-request.component";
import { RegisterComponent } from "../auth/popup/register.component";
Expand Down Expand Up @@ -216,12 +217,6 @@ const routes: Routes = [
canActivate: [unauthGuardFn(unauthRouteOverrides)],
data: { state: "2fa-options" } satisfies RouteDataProperties,
},
{
path: "login-initiated",
component: LoginDecryptionOptionsComponent,
canActivate: [tdeDecryptionRequiredGuard()],
data: { state: "login-initiated" } satisfies RouteDataProperties,
},
{
path: "sso",
component: SsoComponent,
Expand Down Expand Up @@ -489,6 +484,29 @@ const routes: Routes = [
],
},
),
...unauthUiRefreshSwap(
LoginDecryptionOptionsComponentV1,
ExtensionAnonLayoutWrapperComponent,
{
path: "login-initiated",
canActivate: [tdeDecryptionRequiredGuard()],
data: { state: "login-initiated" } satisfies RouteDataProperties,
},
{
path: "login-initiated",
canActivate: [tdeDecryptionRequiredGuard()],
data: {
pageTitle: {
key: "deviceApprovalRequiredV2",
},
pageSubtitle: {
key: "selectAnApprovalOptionBelow",
},
titleId: "deviceApprovalRequiredV2",
},
children: [{ path: "", component: LoginDecryptionOptionsComponent }],
},
),
{
path: "",
component: ExtensionAnonLayoutWrapperComponent,
Expand Down
4 changes: 2 additions & 2 deletions apps/browser/src/popup/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ import { ExtensionAnonLayoutWrapperComponent } from "../auth/popup/extension-ano
import { HintComponent } from "../auth/popup/hint.component";
import { HomeComponent } from "../auth/popup/home.component";
import { LockComponent } from "../auth/popup/lock.component";
import { LoginDecryptionOptionsComponent } from "../auth/popup/login-decryption-options/login-decryption-options.component";
import { LoginDecryptionOptionsComponentV1 } from "../auth/popup/login-decryption-options/login-decryption-options-v1.component";
import { LoginComponentV1 } from "../auth/popup/login-v1.component";
import { LoginViaAuthRequestComponent } from "../auth/popup/login-via-auth-request.component";
import { RegisterComponent } from "../auth/popup/register.component";
Expand Down Expand Up @@ -161,7 +161,7 @@ import "../platform/popup/locales";
LockComponent,
LoginComponentV1,
LoginViaAuthRequestComponent,
LoginDecryptionOptionsComponent,
LoginDecryptionOptionsComponentV1,
NotificationsSettingsV1Component,
AppearanceComponent,
GeneratorComponent,
Expand Down
8 changes: 8 additions & 0 deletions apps/browser/src/popup/services/services.module.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { APP_INITIALIZER, NgModule, NgZone } from "@angular/core";
import { Router } from "@angular/router";
import { Subject, merge, of } from "rxjs";

import { CollectionService } from "@bitwarden/admin-console/common";
Expand All @@ -22,6 +23,7 @@ import {
AnonLayoutWrapperDataService,
LoginComponentService,
LockComponentService,
LoginDecryptionOptionsService,
} from "@bitwarden/auth/angular";
import { LockService, LoginEmailService, PinServiceAbstraction } from "@bitwarden/auth/common";
import { ApiService } from "@bitwarden/common/abstractions/api.service";
Expand Down Expand Up @@ -111,6 +113,7 @@ import { PasswordRepromptService } from "@bitwarden/vault";
import { ForegroundLockService } from "../../auth/popup/accounts/foreground-lock.service";
import { ExtensionAnonLayoutWrapperDataService } from "../../auth/popup/extension-anon-layout-wrapper/extension-anon-layout-wrapper-data.service";
import { ExtensionLoginComponentService } from "../../auth/popup/login/extension-login-component.service";
import { ExtensionLoginDecryptionOptionsService } from "../../auth/popup/login-decryption-options/extension-login-decryption-options.service";
import { AutofillService as AutofillServiceAbstraction } from "../../autofill/services/abstractions/autofill.service";
import AutofillService from "../../autofill/services/autofill.service";
import { InlineMenuFieldQualificationService } from "../../autofill/services/inline-menu-field-qualification.service";
Expand Down Expand Up @@ -581,6 +584,11 @@ const safeProviders: SafeProvider[] = [
useClass: ExtensionAnonLayoutWrapperDataService,
deps: [],
}),
safeProvider({
provide: LoginDecryptionOptionsService,
useClass: ExtensionLoginDecryptionOptionsService,
deps: [MessagingServiceAbstraction, Router],
}),
];

@NgModule({
Expand Down
30 changes: 24 additions & 6 deletions apps/desktop/src/app/app-routing.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import {
SetPasswordJitComponent,
UserLockIcon,
VaultIcon,
LoginDecryptionOptionsComponent,
} from "@bitwarden/auth/angular";
import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum";

Expand All @@ -40,7 +41,7 @@ import { AccessibilityCookieComponent } from "../auth/accessibility-cookie.compo
import { maxAccountsGuardFn } from "../auth/guards/max-accounts.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 { LoginViaAuthRequestComponent } from "../auth/login/login-via-auth-request.component";
import { RegisterComponent } from "../auth/register.component";
Expand Down Expand Up @@ -101,11 +102,6 @@ const routes: Routes = [
],
},
),
{
path: "login-initiated",
component: LoginDecryptionOptionsComponent,
canActivate: [tdeDecryptionRequiredGuard()],
},
{ path: "register", component: RegisterComponent },
{
path: "vault",
Expand Down Expand Up @@ -200,6 +196,28 @@ const routes: Routes = [
],
},
),
...unauthUiRefreshSwap(
LoginDecryptionOptionsComponentV1,
AnonLayoutWrapperComponent,
{
path: "login-initiated",
canActivate: [tdeDecryptionRequiredGuard()],
},
{
path: "login-initiated",
canActivate: [tdeDecryptionRequiredGuard()],
data: {
pageTitle: {
key: "deviceApprovalRequiredV2",
},
pageSubtitle: {
key: "selectAnApprovalOptionBelow",
},
titleId: "deviceApprovalRequiredV2",
},
children: [{ path: "", component: LoginDecryptionOptionsComponent }],
},
),
{
path: "",
component: AnonLayoutWrapperComponent,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import { Component } 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";

@Component({
selector: "desktop-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 {
override async createUser(): Promise<void> {
try {
await super.createUser();
Expand Down
4 changes: 2 additions & 2 deletions apps/desktop/src/auth/login/login.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { EnvironmentSelectorComponent } from "@bitwarden/angular/auth/components

import { SharedModule } from "../../app/shared/shared.module";

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 { LoginViaAuthRequestComponent } from "./login-via-auth-request.component";

Expand All @@ -15,7 +15,7 @@ import { LoginViaAuthRequestComponent } from "./login-via-auth-request.component
LoginComponentV1,
LoginViaAuthRequestComponent,
EnvironmentSelectorComponent,
LoginDecryptionOptionsComponent,
LoginDecryptionOptionsComponentV1,
],
exports: [LoginComponentV1, LoginViaAuthRequestComponent],
})
Expand Down
12 changes: 12 additions & 0 deletions apps/desktop/src/locales/en/messages.json
Original file line number Diff line number Diff line change
Expand Up @@ -2797,6 +2797,9 @@
"checkForBreaches": {
"message": "Check known data breaches for this password"
},
"loggedInExclamation": {
"message": "Logged in!"
},
"important": {
"message": "Important:"
},
Expand Down Expand Up @@ -2827,9 +2830,18 @@
"windowsBiometricUpdateWarningTitle": {
"message": "Recommended Settings Update"
},
"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"
},
Expand Down
1 change: 1 addition & 0 deletions apps/web/src/app/auth/core/services/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
export * from "./login";
export * from "./login-decryption-options";
export * from "./webauthn-login";
export * from "./set-password-jit";
export * from "./registration";
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from "./web-login-decryption-options.service";
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { MockProxy, mock } from "jest-mock-extended";

import { ValidationService } from "@bitwarden/common/platform/abstractions/validation.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 routerService: MockProxy<RouterService>;
let acceptOrganizationInviteService: MockProxy<AcceptOrganizationInviteService>;
let validationService: MockProxy<ValidationService>;

beforeEach(() => {
routerService = mock<RouterService>();
acceptOrganizationInviteService = mock<AcceptOrganizationInviteService>();
validationService = mock<ValidationService>();

service = new WebLoginDecryptionOptionsService(
routerService,
acceptOrganizationInviteService,
validationService,
);
});

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();
});
});
});
Loading
Loading