mirror of
https://github.com/bitwarden/browser
synced 2025-12-13 06:43:35 +00:00
[SG-742] (#4190)
* 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:
@@ -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> {{ "settings" | i18n }}</span>
|
<i class="bwi bwi-cog-f bwi-lg" aria-hidden="true"></i><span> {{ "settings" | i18n }}</span>
|
||||||
</button>
|
</button>
|
||||||
|
|||||||
@@ -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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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",
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -367,6 +367,7 @@ function getBgService<T>(service: keyof MainBackground) {
|
|||||||
{
|
{
|
||||||
provide: LoginServiceAbstraction,
|
provide: LoginServiceAbstraction,
|
||||||
useClass: LoginService,
|
useClass: LoginService,
|
||||||
|
deps: [StateServiceAbstraction],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
provide: AbstractThemingService,
|
provide: AbstractThemingService,
|
||||||
|
|||||||
@@ -180,6 +180,7 @@ const RELOAD_CALLBACK = new InjectionToken<() => any>("RELOAD_CALLBACK");
|
|||||||
{
|
{
|
||||||
provide: LoginServiceAbstraction,
|
provide: LoginServiceAbstraction,
|
||||||
useClass: LoginService,
|
useClass: LoginService,
|
||||||
|
deps: [StateServiceAbstraction],
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -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();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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"
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -103,6 +103,7 @@ import { WebPlatformUtilsService } from "./web-platform-utils.service";
|
|||||||
{
|
{
|
||||||
provide: LoginServiceAbstraction,
|
provide: LoginServiceAbstraction,
|
||||||
useClass: LoginService,
|
useClass: LoginService,
|
||||||
|
deps: [StateService],
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -598,6 +598,7 @@ import { AbstractThemingService } from "./theming/theming.service.abstraction";
|
|||||||
{
|
{
|
||||||
provide: LoginServiceAbstraction,
|
provide: LoginServiceAbstraction,
|
||||||
useClass: LoginService,
|
useClass: LoginService,
|
||||||
|
deps: [StateServiceAbstraction],
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -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>;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user