-
-
-
-
-
diff --git a/apps/desktop/src/app/accounts/login.component.ts b/apps/desktop/src/app/accounts/login.component.ts
index 33eefbd57e..43909423ee 100644
--- a/apps/desktop/src/app/accounts/login.component.ts
+++ b/apps/desktop/src/app/accounts/login.component.ts
@@ -1,9 +1,11 @@
import { Component, NgZone, OnDestroy, ViewChild, ViewContainerRef } from "@angular/core";
import { FormBuilder } from "@angular/forms";
-import { Router } from "@angular/router";
+import { ActivatedRoute, Router } from "@angular/router";
import { LoginComponent as BaseLoginComponent } from "@bitwarden/angular/components/login.component";
import { ModalService } from "@bitwarden/angular/services/modal.service";
+import { ApiService } from "@bitwarden/common/abstractions/api.service";
+import { AppIdService } from "@bitwarden/common/abstractions/appId.service";
import { AuthService } from "@bitwarden/common/abstractions/auth.service";
import { BroadcasterService } from "@bitwarden/common/abstractions/broadcaster.service";
import { CryptoFunctionService } from "@bitwarden/common/abstractions/cryptoFunction.service";
@@ -11,6 +13,7 @@ import { EnvironmentService } from "@bitwarden/common/abstractions/environment.s
import { FormValidationErrorsService } from "@bitwarden/common/abstractions/formValidationErrors.service";
import { I18nService } from "@bitwarden/common/abstractions/i18n.service";
import { LogService } from "@bitwarden/common/abstractions/log.service";
+import { LoginService } from "@bitwarden/common/abstractions/login.service";
import { MessagingService } from "@bitwarden/common/abstractions/messaging.service";
import { PasswordGenerationService } from "@bitwarden/common/abstractions/passwordGeneration.service";
import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUtils.service";
@@ -29,13 +32,23 @@ export class LoginComponent extends BaseLoginComponent implements OnDestroy {
@ViewChild("environment", { read: ViewContainerRef, static: true })
environmentModal: ViewContainerRef;
- showingModal = false;
+ webVaultHostname = "";
- protected alwaysRememberEmail = true;
+ showingModal = false;
private deferFocus: boolean = null;
+ get loggedEmail() {
+ return this.formGroup.value.email;
+ }
+
+ get selfHostedDomain() {
+ return this.environmentService.hasBaseUrl() ? this.environmentService.getWebVaultUrl() : null;
+ }
+
constructor(
+ apiService: ApiService,
+ appIdService: AppIdService,
authService: AuthService,
router: Router,
i18nService: I18nService,
@@ -51,9 +64,13 @@ export class LoginComponent extends BaseLoginComponent implements OnDestroy {
private messagingService: MessagingService,
logService: LogService,
formBuilder: FormBuilder,
- formValidationErrorService: FormValidationErrorsService
+ formValidationErrorService: FormValidationErrorsService,
+ route: ActivatedRoute,
+ loginService: LoginService
) {
super(
+ apiService,
+ appIdService,
authService,
router,
platformUtilsService,
@@ -65,7 +82,9 @@ export class LoginComponent extends BaseLoginComponent implements OnDestroy {
logService,
ngZone,
formBuilder,
- formValidationErrorService
+ formValidationErrorService,
+ route,
+ loginService
);
super.onSuccessfulLogin = () => {
return syncService.fullSync(true);
@@ -127,7 +146,23 @@ export class LoginComponent extends BaseLoginComponent implements OnDestroy {
this.showPassword = false;
}
+ async continue() {
+ await super.validateEmail();
+ if (!this.formGroup.controls.email.valid) {
+ this.platformUtilsService.showToast(
+ "error",
+ this.i18nService.t("errorOccured"),
+ this.i18nService.t("invalidEmail")
+ );
+ return;
+ }
+ }
+
async submit() {
+ if (!this.validatedEmail) {
+ return;
+ }
+
await super.submit();
if (this.captchaSiteKey) {
const content = document.getElementById("content") as HTMLDivElement;
diff --git a/apps/desktop/src/app/accounts/two-factor.component.ts b/apps/desktop/src/app/accounts/two-factor.component.ts
index 51ad6e1329..858ddfc5ae 100644
--- a/apps/desktop/src/app/accounts/two-factor.component.ts
+++ b/apps/desktop/src/app/accounts/two-factor.component.ts
@@ -9,6 +9,7 @@ import { AuthService } from "@bitwarden/common/abstractions/auth.service";
import { EnvironmentService } from "@bitwarden/common/abstractions/environment.service";
import { I18nService } from "@bitwarden/common/abstractions/i18n.service";
import { LogService } from "@bitwarden/common/abstractions/log.service";
+import { LoginService } from "@bitwarden/common/abstractions/login.service";
import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUtils.service";
import { StateService } from "@bitwarden/common/abstractions/state.service";
import { SyncService } from "@bitwarden/common/abstractions/sync/sync.service.abstraction";
@@ -41,7 +42,8 @@ export class TwoFactorComponent extends BaseTwoFactorComponent {
route: ActivatedRoute,
logService: LogService,
twoFactorService: TwoFactorService,
- appIdService: AppIdService
+ appIdService: AppIdService,
+ loginService: LoginService
) {
super(
authService,
@@ -55,9 +57,11 @@ export class TwoFactorComponent extends BaseTwoFactorComponent {
route,
logService,
twoFactorService,
- appIdService
+ appIdService,
+ loginService
);
super.onSuccessfulLogin = () => {
+ this.loginService.clearValues();
return syncService.fullSync(true);
};
}
diff --git a/apps/desktop/src/app/layout/account-switcher.component.html b/apps/desktop/src/app/layout/account-switcher.component.html
index 9b77638a6c..4080b2e031 100644
--- a/apps/desktop/src/app/layout/account-switcher.component.html
+++ b/apps/desktop/src/app/layout/account-switcher.component.html
@@ -90,7 +90,7 @@
0">
-
diff --git a/apps/desktop/src/app/layout/account-switcher.component.ts b/apps/desktop/src/app/layout/account-switcher.component.ts
index 0f03464acb..0c1ca74bd5 100644
--- a/apps/desktop/src/app/layout/account-switcher.component.ts
+++ b/apps/desktop/src/app/layout/account-switcher.component.ts
@@ -1,6 +1,7 @@
import { animate, state, style, transition, trigger } from "@angular/animations";
import { ConnectedPosition } from "@angular/cdk/overlay";
import { Component, OnDestroy, OnInit } from "@angular/core";
+import { Router } from "@angular/router";
import { concatMap, Subject, takeUntil } from "rxjs";
import { AuthService } from "@bitwarden/common/abstractions/auth.service";
@@ -91,6 +92,7 @@ export class AccountSwitcherComponent implements OnInit, OnDestroy {
private stateService: StateService,
private authService: AuthService,
private messagingService: MessagingService,
+ private router: Router,
private tokenService: TokenService
) {}
@@ -142,6 +144,8 @@ export class AccountSwitcherComponent implements OnInit, OnDestroy {
async addAccount() {
this.close();
await this.stateService.setActiveUser(null);
+ await this.stateService.setRememberedEmail(null);
+ this.router.navigate(["/login"]);
}
private async createSwitcherAccounts(baseAccounts: {
diff --git a/apps/desktop/src/app/services/services.module.ts b/apps/desktop/src/app/services/services.module.ts
index aa4e921089..6dc9b8b0db 100644
--- a/apps/desktop/src/app/services/services.module.ts
+++ b/apps/desktop/src/app/services/services.module.ts
@@ -23,6 +23,7 @@ import {
LogService,
LogService as LogServiceAbstraction,
} from "@bitwarden/common/abstractions/log.service";
+import { LoginService as LoginServiceAbstraction } from "@bitwarden/common/abstractions/login.service";
import { MessagingService as MessagingServiceAbstraction } from "@bitwarden/common/abstractions/messaging.service";
import { PasswordGenerationService as PasswordGenerationServiceAbstraction } from "@bitwarden/common/abstractions/passwordGeneration.service";
import { PasswordRepromptService as PasswordRepromptServiceAbstraction } from "@bitwarden/common/abstractions/passwordReprompt.service";
@@ -35,6 +36,7 @@ import { SystemService as SystemServiceAbstraction } from "@bitwarden/common/abs
import { ClientType } from "@bitwarden/common/enums/clientType";
import { StateFactory } from "@bitwarden/common/factories/stateFactory";
import { GlobalState } from "@bitwarden/common/models/domain/global-state";
+import { LoginService } from "@bitwarden/common/services/login.service";
import { MemoryStorageService } from "@bitwarden/common/services/memoryStorage.service";
import { SystemService } from "@bitwarden/common/services/system.service";
import { ElectronCryptoService } from "@bitwarden/electron/services/electronCrypto.service";
@@ -175,6 +177,10 @@ const RELOAD_CALLBACK = new InjectionToken<() => any>("RELOAD_CALLBACK");
EncryptedMessageHandlerService,
],
},
+ {
+ provide: LoginServiceAbstraction,
+ useClass: LoginService,
+ },
],
})
export class ServicesModule {}
diff --git a/apps/desktop/src/locales/en/messages.json b/apps/desktop/src/locales/en/messages.json
index c896cd3e26..fd168510b3 100644
--- a/apps/desktop/src/locales/en/messages.json
+++ b/apps/desktop/src/locales/en/messages.json
@@ -2021,5 +2021,32 @@
},
"vault": {
"message": "Vault"
+ },
+ "loginWithMasterPassword": {
+ "message": "Log in with master password"
+ },
+ "loggingInAs": {
+ "message": "Logging in as"
+ },
+ "rememberEmail": {
+ "message": "Remember email"
+ },
+ "notYou": {
+ "message": "Not you?"
+ },
+ "newAroundHere": {
+ "message": "New around here?"
+ },
+ "loggingInTo": {
+ "message": "Logging in to $DOMAIN$",
+ "placeholders": {
+ "domain": {
+ "content": "$1",
+ "example": "example.com"
+ }
+ }
+ },
+ "logInWithAnotherDevice": {
+ "message": "Log in with another device"
}
}
diff --git a/apps/desktop/src/scss/misc.scss b/apps/desktop/src/scss/misc.scss
index 50ba40ba70..5818b19471 100644
--- a/apps/desktop/src/scss/misc.scss
+++ b/apps/desktop/src/scss/misc.scss
@@ -310,6 +310,11 @@ form,
margin-top: 4px;
margin-left: -18px;
}
+
+ &.remember-email {
+ padding-left: 20px;
+ padding-bottom: 5px;
+ }
}
.radio {
@@ -482,6 +487,10 @@ app-root > #loading,
margin-top: 15px;
}
+.password-hint-btn {
+ margin-bottom: 10px;
+}
+
.set-pin-modal {
.box {
margin-bottom: 15px;
diff --git a/apps/desktop/src/scss/pages.scss b/apps/desktop/src/scss/pages.scss
index 87862bbef3..f5ca996c44 100644
--- a/apps/desktop/src/scss/pages.scss
+++ b/apps/desktop/src/scss/pages.scss
@@ -189,6 +189,8 @@
#login-page {
flex-direction: column;
+ justify-content: unset;
+ padding-top: 20px;
.login-header {
align-self: flex-start;
diff --git a/apps/web/src/app/accounts/hint.component.ts b/apps/web/src/app/accounts/hint.component.ts
index f6d3153b03..aaf58fe949 100644
--- a/apps/web/src/app/accounts/hint.component.ts
+++ b/apps/web/src/app/accounts/hint.component.ts
@@ -5,6 +5,7 @@ import { HintComponent as BaseHintComponent } from "@bitwarden/angular/component
import { ApiService } from "@bitwarden/common/abstractions/api.service";
import { I18nService } from "@bitwarden/common/abstractions/i18n.service";
import { LogService } from "@bitwarden/common/abstractions/log.service";
+import { LoginService } from "@bitwarden/common/abstractions/login.service";
import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUtils.service";
@Component({
@@ -17,8 +18,9 @@ export class HintComponent extends BaseHintComponent {
i18nService: I18nService,
apiService: ApiService,
platformUtilsService: PlatformUtilsService,
- logService: LogService
+ logService: LogService,
+ loginService: LoginService
) {
- super(router, i18nService, apiService, platformUtilsService, logService);
+ super(router, i18nService, apiService, platformUtilsService, logService, loginService);
}
}
diff --git a/apps/web/src/app/accounts/login/login.component.html b/apps/web/src/app/accounts/login/login.component.html
index 6152b58595..9854403548 100644
--- a/apps/web/src/app/accounts/login/login.component.html
+++ b/apps/web/src/app/accounts/login/login.component.html
@@ -16,102 +16,122 @@
-
- {{ "resetPasswordAutoEnrollInviteWarning" | i18n }}
-
-
-
-
- {{ "emailAddress" | i18n }}
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+ {{ "rememberEmail" | i18n }}
+
+
-
-
-
+
+
+ {{ "continue" | i18n }}
+
+
-
-
-
-
- {{ "loginWithDevice" | i18n }}
-
-
-
-
+
+ {{ "newAroundHere" | i18n }}
+ {{ "createAccount" | i18n }}
+
+
+
+