1
0
mirror of https://github.com/bitwarden/browser synced 2025-12-13 06:43:35 +00:00
* Remove default landing on masterpassword page

* Remove rememberEmail state service value that isn't needed

* Remove last occurence of setRememberEmail

* Remove alwaysRememberEmail functionality

* Remove always remember email from browser and add option to

* Add extra spacing around remember email check

* [SG-884] Fix Remember Email functionality for Login with SSO (#4238)

* Add saveEmailSettings method to LoginService

* Add StateService as a dependency to LoginService

* Update login components to utilize new login service method for saving rememberedEmail
This commit is contained in:
Robyn MacCallum
2022-12-16 10:08:44 -05:00
committed by GitHub
parent 8bfe48ea73
commit c06c0f9f2c
15 changed files with 75 additions and 59 deletions

View File

@@ -9,9 +9,18 @@
<label for="email">{{ "emailAddress" | i18n }}</label> <label for="email">{{ "emailAddress" | i18n }}</label>
<input id="email" type="email" formControlName="email" appInputVerbatim="false" /> <input id="email" type="email" formControlName="email" appInputVerbatim="false" />
</div> </div>
</div> <div class="box-footer no-margin" *ngIf="selfHostedDomain">
<div class="box-footer no-margin" *ngIf="selfHostedDomain"> {{ "loggingInTo" | i18n: selfHostedDomain }}
{{ "loggingInTo" | i18n: selfHostedDomain }} </div>
<div class="remember-email-check">
<input
id="rememberEmail"
type="checkbox"
name="rememberEmail"
formControlName="rememberEmail"
/>
<label for="rememberEmail">{{ "rememberEmail" | i18n }}</label>
</div>
</div> </div>
</div> </div>
<div class="box"> <div class="box">
@@ -22,10 +31,10 @@
</form> </form>
<p class="createAccountLink"> <p class="createAccountLink">
{{ "newAroundHere" | i18n }} {{ "newAroundHere" | i18n }}
<a routerLink="/register">{{ "createAccount" | i18n }}</a> <a routerLink="/register" (click)="setFormValues()">{{ "createAccount" | i18n }}</a>
</p> </p>
</div> </div>
</div> </div>
<button type="button" routerLink="/environment" class="settings-icon"> <button type="button" routerLink="/environment" class="settings-icon" (click)="setFormValues()">
<i class="bwi bwi-cog-f bwi-lg" aria-hidden="true"></i><span>&nbsp;{{ "settings" | i18n }}</span> <i class="bwi bwi-cog-f bwi-lg" aria-hidden="true"></i><span>&nbsp;{{ "settings" | i18n }}</span>
</button> </button>

View File

@@ -4,6 +4,7 @@ import { ActivatedRoute, Router } from "@angular/router";
import { EnvironmentService } from "@bitwarden/common/abstractions/environment.service"; import { EnvironmentService } from "@bitwarden/common/abstractions/environment.service";
import { I18nService } from "@bitwarden/common/abstractions/i18n.service"; import { I18nService } from "@bitwarden/common/abstractions/i18n.service";
import { LoginService } from "@bitwarden/common/abstractions/login.service";
import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUtils.service"; import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUtils.service";
import { StateService } from "@bitwarden/common/abstractions/state.service"; import { StateService } from "@bitwarden/common/abstractions/state.service";
@@ -16,6 +17,7 @@ export class HomeComponent implements OnInit {
formGroup = this.formBuilder.group({ formGroup = this.formBuilder.group({
email: ["", [Validators.required, Validators.email]], email: ["", [Validators.required, Validators.email]],
rememberEmail: [false],
}); });
constructor( constructor(
@@ -25,12 +27,26 @@ export class HomeComponent implements OnInit {
private router: Router, private router: Router,
private i18nService: I18nService, private i18nService: I18nService,
private environmentService: EnvironmentService, private environmentService: EnvironmentService,
private route: ActivatedRoute private route: ActivatedRoute,
private loginService: LoginService
) {} ) {}
async ngOnInit(): Promise<void> { async ngOnInit(): Promise<void> {
const rememberedEmail = await this.stateService.getRememberedEmail(); let savedEmail = this.loginService.getEmail();
if (rememberedEmail != null) { const rememberEmail = this.loginService.getRememberEmail();
this.formGroup.patchValue({ email: await this.stateService.getRememberedEmail() });
if (savedEmail != null) {
this.formGroup.patchValue({
email: savedEmail,
rememberEmail: rememberEmail,
});
} else {
savedEmail = await this.stateService.getRememberedEmail();
if (savedEmail != null) {
this.formGroup.patchValue({
email: savedEmail,
rememberEmail: true,
});
}
} }
} }
@@ -45,12 +61,17 @@ export class HomeComponent implements OnInit {
return; return;
} }
this.stateService.setRememberedEmail(this.formGroup.value.email); this.loginService.setEmail(this.formGroup.value.email);
this.loginService.setRememberEmail(this.formGroup.value.rememberEmail);
this.router.navigate(["login"], { queryParams: { email: this.formGroup.value.email } }); this.router.navigate(["login"], { queryParams: { email: this.formGroup.value.email } });
} }
get selfHostedDomain() { get selfHostedDomain() {
return this.environmentService.hasBaseUrl() ? this.environmentService.getWebVaultUrl() : null; return this.environmentService.hasBaseUrl() ? this.environmentService.getWebVaultUrl() : null;
} }
setFormValues() {
this.loginService.setEmail(this.formGroup.value.email);
this.loginService.setRememberEmail(this.formGroup.value.rememberEmail);
}
} }

View File

@@ -23,8 +23,6 @@ import { Utils } from "@bitwarden/common/misc/utils";
templateUrl: "login.component.html", templateUrl: "login.component.html",
}) })
export class LoginComponent extends BaseLoginComponent { export class LoginComponent extends BaseLoginComponent {
protected skipRememberEmail = true;
constructor( constructor(
apiService: ApiService, apiService: ApiService,
appIdService: AppIdService, appIdService: AppIdService,
@@ -73,6 +71,7 @@ export class LoginComponent extends BaseLoginComponent {
} }
async launchSsoBrowser() { async launchSsoBrowser() {
await this.loginService.saveEmailSettings();
// Generate necessary sso params // Generate necessary sso params
const passwordOptions: any = { const passwordOptions: any = {
type: "password", type: "password",

View File

@@ -143,6 +143,12 @@ body.body-full {
padding: 30px 10px 0 10px; padding: 30px 10px 0 10px;
} }
.remember-email-check {
padding-top: 8px;
padding-left: 10px;
padding-bottom: 18px;
}
.login-buttons > button { .login-buttons > button {
margin: 15px 0 15px 0; margin: 15px 0 15px 0;
} }

View File

@@ -367,6 +367,7 @@ function getBgService<T>(service: keyof MainBackground) {
{ {
provide: LoginServiceAbstraction, provide: LoginServiceAbstraction,
useClass: LoginService, useClass: LoginService,
deps: [StateServiceAbstraction],
}, },
{ {
provide: AbstractThemingService, provide: AbstractThemingService,

View File

@@ -180,6 +180,7 @@ const RELOAD_CALLBACK = new InjectionToken<() => any>("RELOAD_CALLBACK");
{ {
provide: LoginServiceAbstraction, provide: LoginServiceAbstraction,
useClass: LoginService, useClass: LoginService,
deps: [StateServiceAbstraction],
}, },
], ],
}) })

View File

@@ -142,7 +142,7 @@ export class LoginWithDeviceComponent
this.router.navigate([this.forcePasswordResetRoute]); this.router.navigate([this.forcePasswordResetRoute]);
} }
} else { } else {
await this.setRememberEmailValues(); await this.loginService.saveEmailSettings();
if (this.onSuccessfulLogin != null) { if (this.onSuccessfulLogin != null) {
this.onSuccessfulLogin(); this.onSuccessfulLogin();
} }
@@ -202,12 +202,4 @@ export class LoginWithDeviceComponent
localHashedPassword localHashedPassword
); );
} }
private async setRememberEmailValues() {
const rememberEmail = this.loginService.getRememberEmail();
const rememberedEmail = this.loginService.getEmail();
await this.stateService.setRememberEmail(rememberEmail);
await this.stateService.setRememberedEmail(rememberEmail ? rememberedEmail : null);
this.loginService.clearValues();
}
} }

View File

@@ -120,7 +120,7 @@
<div class="tw-mb-3"> <div class="tw-mb-3">
<a <a
routerLink="/sso" routerLink="/sso"
(click)="setFormValues()" (click)="saveEmailSettings()"
bitButton bitButton
buttonType="secondary" buttonType="secondary"
class="tw-w-full" class="tw-w-full"

View File

@@ -192,7 +192,6 @@ export class LoginComponent extends BaseLoginComponent implements OnInit, OnDest
async submit() { async submit() {
const rememberEmail = this.formGroup.value.rememberEmail; const rememberEmail = this.formGroup.value.rememberEmail;
await this.stateService.setRememberEmail(rememberEmail);
if (!rememberEmail) { if (!rememberEmail) {
await this.stateService.setRememberedEmail(null); await this.stateService.setRememberedEmail(null);
} }

View File

@@ -103,6 +103,7 @@ import { WebPlatformUtilsService } from "./web-platform-utils.service";
{ {
provide: LoginServiceAbstraction, provide: LoginServiceAbstraction,
useClass: LoginService, useClass: LoginService,
deps: [StateService],
}, },
], ],
}) })

View File

@@ -48,23 +48,6 @@ export class StateService extends BaseStateService<GlobalState, Account> {
await super.addAccount(account); await super.addAccount(account);
} }
async getRememberEmail(options?: StorageOptions) {
return (
await this.getGlobals(this.reconcileOptions(options, await this.defaultOnDiskLocalOptions()))
)?.rememberEmail;
}
async setRememberEmail(value: boolean, options?: StorageOptions): Promise<void> {
const globals = await this.getGlobals(
this.reconcileOptions(options, await this.defaultOnDiskLocalOptions())
);
globals.rememberEmail = value;
await this.saveGlobals(
globals,
this.reconcileOptions(options, await this.defaultOnDiskLocalOptions())
);
}
async getEncryptedCiphers(options?: StorageOptions): Promise<{ [id: string]: CipherData }> { async getEncryptedCiphers(options?: StorageOptions): Promise<{ [id: string]: CipherData }> {
options = this.reconcileOptions(options, await this.defaultInMemoryOptions()); options = this.reconcileOptions(options, await this.defaultInMemoryOptions());
return await super.getEncryptedCiphers(options); return await super.getEncryptedCiphers(options);

View File

@@ -46,8 +46,6 @@ export class LoginComponent extends CaptchaProtectedComponent implements OnInit
protected twoFactorRoute = "2fa"; protected twoFactorRoute = "2fa";
protected successRoute = "vault"; protected successRoute = "vault";
protected forcePasswordResetRoute = "update-temp-password"; protected forcePasswordResetRoute = "update-temp-password";
protected alwaysRememberEmail = false;
protected skipRememberEmail = false;
get loggedEmail() { get loggedEmail() {
return this.formGroup.value.email; return this.formGroup.value.email;
@@ -85,6 +83,7 @@ export class LoginComponent extends CaptchaProtectedComponent implements OnInit
const queryParamsEmail = params["email"]; const queryParamsEmail = params["email"];
if (queryParamsEmail != null && queryParamsEmail.indexOf("@") > -1) { if (queryParamsEmail != null && queryParamsEmail.indexOf("@") > -1) {
this.formGroup.get("email").setValue(queryParamsEmail); this.formGroup.get("email").setValue(queryParamsEmail);
this.loginService.setEmail(queryParamsEmail);
this.paramEmailSet = true; this.paramEmailSet = true;
} }
} }
@@ -98,17 +97,11 @@ export class LoginComponent extends CaptchaProtectedComponent implements OnInit
if (!this.paramEmailSet) { if (!this.paramEmailSet) {
this.formGroup.get("email")?.setValue(email ?? ""); this.formGroup.get("email")?.setValue(email ?? "");
} }
if (!this.alwaysRememberEmail) { let rememberEmail = this.loginService.getRememberEmail();
let rememberEmail = this.loginService.getRememberEmail(); if (rememberEmail == null) {
if (rememberEmail == null) { rememberEmail = (await this.stateService.getRememberedEmail()) != null;
rememberEmail = (await this.stateService.getRememberedEmail()) != null;
}
this.formGroup.get("rememberEmail")?.setValue(rememberEmail);
}
if (email) {
this.validateEmail();
} }
this.formGroup.get("rememberEmail")?.setValue(rememberEmail);
} }
async submit(showToast = true) { async submit(showToast = true) {
@@ -140,11 +133,7 @@ export class LoginComponent extends CaptchaProtectedComponent implements OnInit
this.formPromise = this.authService.logIn(credentials); this.formPromise = this.authService.logIn(credentials);
const response = await this.formPromise; const response = await this.formPromise;
this.setFormValues(); this.setFormValues();
if (data.rememberEmail || this.alwaysRememberEmail) { await this.loginService.saveEmailSettings();
await this.stateService.setRememberedEmail(data.email);
} else {
await this.stateService.setRememberedEmail(null);
}
if (this.handleCaptchaRequired(response)) { if (this.handleCaptchaRequired(response)) {
return; return;
} else if (response.requiresTwoFactor) { } else if (response.requiresTwoFactor) {
@@ -162,7 +151,6 @@ export class LoginComponent extends CaptchaProtectedComponent implements OnInit
} else { } else {
const disableFavicon = await this.stateService.getDisableFavicon(); const disableFavicon = await this.stateService.getDisableFavicon();
await this.stateService.setDisableFavicon(!!disableFavicon); await this.stateService.setDisableFavicon(!!disableFavicon);
this.loginService.clearValues();
if (this.onSuccessfulLogin != null) { if (this.onSuccessfulLogin != null) {
this.onSuccessfulLogin(); this.onSuccessfulLogin();
} }
@@ -189,6 +177,7 @@ export class LoginComponent extends CaptchaProtectedComponent implements OnInit
} }
async launchSsoBrowser(clientId: string, ssoRedirectUri: string) { async launchSsoBrowser(clientId: string, ssoRedirectUri: string) {
await this.saveEmailSettings();
// Generate necessary sso params // Generate necessary sso params
const passwordOptions: any = { const passwordOptions: any = {
type: "password", type: "password",
@@ -243,6 +232,11 @@ export class LoginComponent extends CaptchaProtectedComponent implements OnInit
this.loginService.setRememberEmail(this.formGroup.value.rememberEmail); this.loginService.setRememberEmail(this.formGroup.value.rememberEmail);
} }
async saveEmailSettings() {
this.setFormValues();
await this.loginService.saveEmailSettings();
}
private getErrorToastMessage() { private getErrorToastMessage() {
const error: AllValidationErrors = this.formValidationErrorService const error: AllValidationErrors = this.formValidationErrorService
.getFormValidationErrors(this.formGroup.controls) .getFormValidationErrors(this.formGroup.controls)

View File

@@ -598,6 +598,7 @@ import { AbstractThemingService } from "./theming/theming.service.abstraction";
{ {
provide: LoginServiceAbstraction, provide: LoginServiceAbstraction,
useClass: LoginService, useClass: LoginService,
deps: [StateServiceAbstraction],
}, },
], ],
}) })

View File

@@ -4,4 +4,5 @@ export abstract class LoginService {
setEmail: (value: string) => void; setEmail: (value: string) => void;
setRememberEmail: (value: boolean) => void; setRememberEmail: (value: boolean) => void;
clearValues: () => void; clearValues: () => void;
saveEmailSettings: () => Promise<void>;
} }

View File

@@ -1,9 +1,12 @@
import { LoginService as LoginServiceAbstraction } from "../abstractions/login.service"; import { LoginService as LoginServiceAbstraction } from "../abstractions/login.service";
import { StateService } from "../abstractions/state.service";
export class LoginService implements LoginServiceAbstraction { export class LoginService implements LoginServiceAbstraction {
private _email: string; private _email: string;
private _rememberEmail: boolean; private _rememberEmail: boolean;
constructor(private stateService: StateService) {}
getEmail() { getEmail() {
return this._email; return this._email;
} }
@@ -24,4 +27,9 @@ export class LoginService implements LoginServiceAbstraction {
this._email = null; this._email = null;
this._rememberEmail = null; this._rememberEmail = null;
} }
async saveEmailSettings() {
await this.stateService.setRememberedEmail(this._rememberEmail ? this._email : null);
this.clearValues();
}
} }