mirror of
https://github.com/bitwarden/browser
synced 2025-12-15 15:53:27 +00:00
[PM-4917, PM-8707, PM-9119] Persist login email memory through 2fa on browser (#9811)
* persist email memory through 2fa on browser * fix tests * fix desktop
This commit is contained in:
@@ -110,17 +110,8 @@ export class LoginComponent extends CaptchaProtectedComponent implements OnInit,
|
||||
});
|
||||
|
||||
if (!this.paramEmailSet) {
|
||||
const storedEmail = await firstValueFrom(this.loginEmailService.storedEmail$);
|
||||
this.formGroup.controls.email.setValue(storedEmail ?? "");
|
||||
await this.loadEmailSettings();
|
||||
}
|
||||
|
||||
let rememberEmail = this.loginEmailService.getRememberEmail();
|
||||
|
||||
if (!rememberEmail) {
|
||||
rememberEmail = (await firstValueFrom(this.loginEmailService.storedEmail$)) != null;
|
||||
}
|
||||
|
||||
this.formGroup.controls.rememberEmail.setValue(rememberEmail);
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
@@ -158,8 +149,7 @@ export class LoginComponent extends CaptchaProtectedComponent implements OnInit,
|
||||
this.formPromise = this.loginStrategyService.logIn(credentials);
|
||||
const response = await this.formPromise;
|
||||
|
||||
this.setLoginEmailValues();
|
||||
await this.loginEmailService.saveEmailSettings();
|
||||
await this.saveEmailSettings();
|
||||
|
||||
if (this.handleCaptchaRequired(response)) {
|
||||
return;
|
||||
@@ -181,6 +171,7 @@ export class LoginComponent extends CaptchaProtectedComponent implements OnInit,
|
||||
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
||||
this.onSuccessfulLoginForceResetNavigate();
|
||||
} else {
|
||||
this.loginEmailService.clearValues();
|
||||
// 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.forcePasswordResetRoute]);
|
||||
@@ -196,6 +187,7 @@ export class LoginComponent extends CaptchaProtectedComponent implements OnInit,
|
||||
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
||||
this.onSuccessfulLoginNavigate();
|
||||
} else {
|
||||
this.loginEmailService.clearValues();
|
||||
// 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]);
|
||||
@@ -225,12 +217,14 @@ export class LoginComponent extends CaptchaProtectedComponent implements OnInit,
|
||||
return;
|
||||
}
|
||||
|
||||
this.setLoginEmailValues();
|
||||
await this.saveEmailSettings();
|
||||
await this.router.navigate(["/login-with-device"]);
|
||||
}
|
||||
|
||||
async launchSsoBrowser(clientId: string, ssoRedirectUri: string) {
|
||||
await this.saveEmailSettings();
|
||||
// Save off email for SSO
|
||||
await this.ssoLoginService.setSsoEmail(this.formGroup.value.email);
|
||||
|
||||
// Generate necessary sso params
|
||||
const passwordOptions: any = {
|
||||
type: "password",
|
||||
@@ -301,17 +295,28 @@ export class LoginComponent extends CaptchaProtectedComponent implements OnInit,
|
||||
}
|
||||
}
|
||||
|
||||
setLoginEmailValues() {
|
||||
this.loginEmailService.setEmail(this.formGroup.value.email);
|
||||
this.loginEmailService.setRememberEmail(this.formGroup.value.rememberEmail);
|
||||
private async loadEmailSettings() {
|
||||
// Try to load from memory first
|
||||
const email = this.loginEmailService.getEmail();
|
||||
const rememberEmail = this.loginEmailService.getRememberEmail();
|
||||
if (email) {
|
||||
this.formGroup.controls.email.setValue(email);
|
||||
this.formGroup.controls.rememberEmail.setValue(rememberEmail);
|
||||
} else {
|
||||
// If not in memory, check email on disk
|
||||
const storedEmail = await firstValueFrom(this.loginEmailService.storedEmail$);
|
||||
if (storedEmail) {
|
||||
// If we have a stored email, rememberEmail should default to true
|
||||
this.formGroup.controls.email.setValue(storedEmail);
|
||||
this.formGroup.controls.rememberEmail.setValue(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async saveEmailSettings() {
|
||||
this.setLoginEmailValues();
|
||||
protected async saveEmailSettings() {
|
||||
this.loginEmailService.setEmail(this.formGroup.value.email);
|
||||
this.loginEmailService.setRememberEmail(this.formGroup.value.rememberEmail);
|
||||
await this.loginEmailService.saveEmailSettings();
|
||||
|
||||
// Save off email for SSO
|
||||
await this.ssoLoginService.setSsoEmail(this.formGroup.value.email);
|
||||
}
|
||||
|
||||
// Legacy accounts used the master key to encrypt data. Migration is required
|
||||
|
||||
@@ -137,14 +137,16 @@ describe("LoginEmailService", () => {
|
||||
expect(result).toEqual("initialEmail@bitwarden.com");
|
||||
});
|
||||
|
||||
it("clears the email and rememberEmail after saving", async () => {
|
||||
it("does not clear the email and rememberEmail after saving", async () => {
|
||||
// Browser uses these values to maintain the email between login and 2fa components so
|
||||
// we do not want to clear them too early.
|
||||
sut.setEmail("userEmail@bitwarden.com");
|
||||
sut.setRememberEmail(true);
|
||||
await sut.saveEmailSettings();
|
||||
|
||||
const result = sut.getEmail();
|
||||
|
||||
expect(result).toBeNull();
|
||||
expect(result).toBe("userEmail@bitwarden.com");
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -73,6 +73,9 @@ export class LoginEmailService implements LoginEmailServiceAbstraction {
|
||||
this.rememberEmail = value ?? false;
|
||||
}
|
||||
|
||||
// Note: only clear values on successful login or you are sure they are not needed.
|
||||
// Browser uses these values to maintain the email between login and 2fa components so
|
||||
// we do not want to clear them too early.
|
||||
clearValues() {
|
||||
this.email = null;
|
||||
this.rememberEmail = false;
|
||||
@@ -89,12 +92,11 @@ export class LoginEmailService implements LoginEmailServiceAbstraction {
|
||||
return storedEmail;
|
||||
}
|
||||
|
||||
// Logging in with rememberEmail set to false will clear the stored email
|
||||
// Saving with rememberEmail set to false will clear the stored email
|
||||
if (this.rememberEmail) {
|
||||
return this.email;
|
||||
}
|
||||
return null;
|
||||
});
|
||||
this.clearValues();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user