mirror of
https://github.com/bitwarden/browser
synced 2025-12-17 16:53:34 +00:00
feat(prelogin): [Auth/PM-23801] Move Prelogin Request (#17080)
* feat(prelogin): [PM-23801] Move Prelogin Request - Initial implementation. * test(prelogin): [PM-23801] Move Prelogin Request - Removed unneeded test.
This commit is contained in:
committed by
GitHub
parent
f7899991a0
commit
5aa6d38d80
@@ -1,4 +1,4 @@
|
||||
<!--
|
||||
<!--
|
||||
# Table of Contents
|
||||
|
||||
This file contains a single consolidated template for all visual clients.
|
||||
|
||||
102
libs/auth/src/angular/login/login.component.spec.ts
Normal file
102
libs/auth/src/angular/login/login.component.spec.ts
Normal file
@@ -0,0 +1,102 @@
|
||||
import { FormBuilder } from "@angular/forms";
|
||||
import { mock } from "jest-mock-extended";
|
||||
|
||||
import { LoginStrategyServiceAbstraction } from "@bitwarden/auth/common";
|
||||
import { ClientType } from "@bitwarden/common/enums";
|
||||
import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service";
|
||||
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
||||
|
||||
import { LoginComponent } from "./login.component";
|
||||
|
||||
describe("LoginComponent continue() integration", () => {
|
||||
function createComponent({ flagEnabled }: { flagEnabled: boolean }) {
|
||||
const activatedRoute: any = { queryParams: { subscribe: () => {} } };
|
||||
const anonLayoutWrapperDataService: any = { setAnonLayoutWrapperData: () => {} };
|
||||
const appIdService: any = {};
|
||||
const broadcasterService: any = { subscribe: () => {}, unsubscribe: () => {} };
|
||||
const destroyRef: any = {};
|
||||
const devicesApiService: any = {};
|
||||
const formBuilder = new FormBuilder();
|
||||
const i18nService: any = { t: () => "" };
|
||||
const loginEmailService: any = {
|
||||
rememberedEmail$: { pipe: () => ({}) },
|
||||
setLoginEmail: async () => {},
|
||||
setRememberedEmailChoice: async () => {},
|
||||
clearLoginEmail: async () => {},
|
||||
};
|
||||
const loginComponentService: any = {
|
||||
showBackButton: () => {},
|
||||
isLoginWithPasskeySupported: () => false,
|
||||
redirectToSsoLogin: async () => {},
|
||||
};
|
||||
const loginStrategyService = mock<LoginStrategyServiceAbstraction>();
|
||||
const messagingService: any = { send: () => {} };
|
||||
const ngZone: any = { isStable: true, onStable: { pipe: () => ({ subscribe: () => {} }) } };
|
||||
const passwordStrengthService: any = {};
|
||||
const platformUtilsService = mock<PlatformUtilsService>();
|
||||
platformUtilsService.getClientType.mockReturnValue(ClientType.Browser);
|
||||
const policyService: any = { replace: async () => {}, evaluateMasterPassword: () => true };
|
||||
const router: any = { navigate: async () => {}, navigateByUrl: async () => {} };
|
||||
const toastService: any = { showToast: () => {} };
|
||||
const logService: any = { error: () => {} };
|
||||
const validationService: any = { showError: () => {} };
|
||||
const loginSuccessHandlerService: any = { run: async () => {} };
|
||||
const configService = mock<ConfigService>();
|
||||
configService.getFeatureFlag.mockResolvedValue(flagEnabled);
|
||||
const ssoLoginService: any = { ssoRequiredCache$: { pipe: () => ({}) } };
|
||||
const environmentService: any = { environment$: { pipe: () => ({}) } };
|
||||
|
||||
const component = new LoginComponent(
|
||||
activatedRoute,
|
||||
anonLayoutWrapperDataService,
|
||||
appIdService,
|
||||
broadcasterService,
|
||||
destroyRef,
|
||||
devicesApiService,
|
||||
formBuilder,
|
||||
i18nService,
|
||||
loginEmailService,
|
||||
loginComponentService,
|
||||
loginStrategyService,
|
||||
messagingService,
|
||||
ngZone,
|
||||
passwordStrengthService,
|
||||
platformUtilsService,
|
||||
policyService,
|
||||
router,
|
||||
toastService,
|
||||
logService,
|
||||
validationService,
|
||||
loginSuccessHandlerService,
|
||||
configService,
|
||||
ssoLoginService,
|
||||
environmentService,
|
||||
);
|
||||
|
||||
jest.spyOn(component as any, "toggleLoginUiState").mockResolvedValue(undefined);
|
||||
|
||||
return { component, loginStrategyService };
|
||||
}
|
||||
|
||||
it("calls getPasswordPrelogin on continue when flag enabled and email valid", async () => {
|
||||
const { component, loginStrategyService } = createComponent({ flagEnabled: true });
|
||||
(component as any).formGroup.controls.email.setValue("user@example.com");
|
||||
(component as any).formGroup.controls.rememberEmail.setValue(false);
|
||||
(component as any).formGroup.controls.masterPassword.setValue("irrelevant");
|
||||
|
||||
await (component as any).continue();
|
||||
|
||||
expect(loginStrategyService.getPasswordPrelogin).toHaveBeenCalledWith("user@example.com");
|
||||
});
|
||||
|
||||
it("does not call getPasswordPrelogin when flag disabled", async () => {
|
||||
const { component, loginStrategyService } = createComponent({ flagEnabled: false });
|
||||
(component as any).formGroup.controls.email.setValue("user@example.com");
|
||||
(component as any).formGroup.controls.rememberEmail.setValue(false);
|
||||
(component as any).formGroup.controls.masterPassword.setValue("irrelevant");
|
||||
|
||||
await (component as any).continue();
|
||||
|
||||
expect(loginStrategyService.getPasswordPrelogin).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
@@ -550,6 +550,8 @@ export class LoginComponent implements OnInit, OnDestroy {
|
||||
const isEmailValid = this.validateEmail();
|
||||
|
||||
if (isEmailValid) {
|
||||
await this.makePasswordPreloginCall();
|
||||
|
||||
await this.toggleLoginUiState(LoginUiState.MASTER_PASSWORD_ENTRY);
|
||||
}
|
||||
}
|
||||
@@ -652,6 +654,23 @@ export class LoginComponent implements OnInit, OnDestroy {
|
||||
history.back();
|
||||
}
|
||||
|
||||
private async makePasswordPreloginCall() {
|
||||
// Prefetch prelogin KDF config when enabled
|
||||
try {
|
||||
const flagEnabled = await this.configService.getFeatureFlag(
|
||||
FeatureFlag.PM23801_PrefetchPasswordPrelogin,
|
||||
);
|
||||
if (flagEnabled) {
|
||||
const email = this.formGroup.value.email;
|
||||
if (email) {
|
||||
void this.loginStrategyService.getPasswordPrelogin(email);
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
this.logService.error("Failed to prefetch prelogin data.", error);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the popstate event to transition back to the email entry state when the back button is clicked.
|
||||
* Also handles the case where the user clicks the forward button.
|
||||
|
||||
Reference in New Issue
Block a user