diff --git a/apps/browser/src/_locales/en/messages.json b/apps/browser/src/_locales/en/messages.json index 127e07f25e8..86977b950f3 100644 --- a/apps/browser/src/_locales/en/messages.json +++ b/apps/browser/src/_locales/en/messages.json @@ -3338,9 +3338,6 @@ "loginWithDevice": { "message": "Log in with device" }, - "loginWithDeviceEnabledInfo": { - "message": "Log in with device must be set up in the settings of the Bitwarden app. Need another option?" - }, "fingerprintPhraseHeader": { "message": "Fingerprint phrase" }, @@ -3353,9 +3350,6 @@ "viewAllLogInOptions": { "message": "View all log in options" }, - "viewAllLoginOptionsV1": { - "message": "View all log in options" - }, "notificationSentDevice": { "message": "A notification has been sent to your device." }, @@ -3546,9 +3540,6 @@ "adminApprovalRequestSentToAdmins": { "message": "Your request has been sent to your admin." }, - "youWillBeNotifiedOnceApproved": { - "message": "You will be notified once approved." - }, "troubleLoggingIn": { "message": "Trouble logging in?" }, diff --git a/apps/browser/src/auth/popup/login-via-auth-request-v1.component.html b/apps/browser/src/auth/popup/login-via-auth-request-v1.component.html deleted file mode 100644 index 34c0cbe9614..00000000000 --- a/apps/browser/src/auth/popup/login-via-auth-request-v1.component.html +++ /dev/null @@ -1,68 +0,0 @@ -
-
-

- {{ "logIn" | i18n }} -

-
-
- -
-

{{ "logInRequestSent" | i18n }}

- -
-

- {{ "notificationSentDevicePart1" | i18n }} - {{ "notificationSentDeviceAnchor" | i18n }}. {{ "notificationSentDevicePart2" | i18n }} -

-
- -
- {{ "fingerprintPhraseHeader" | i18n }} -

- {{ fingerprintPhrase }} -

-
- - - - -
-
- - -
-

{{ "adminApprovalRequested" | i18n }}

- -
-

{{ "adminApprovalRequestSentToAdmins" | i18n }}

-

{{ "youWillBeNotifiedOnceApproved" | i18n }}

-
- -
- {{ "fingerprintPhraseHeader" | i18n }} -

- {{ fingerprintPhrase }} -

-
- - -
-
-
-
diff --git a/apps/browser/src/auth/popup/login-via-auth-request-v1.component.ts b/apps/browser/src/auth/popup/login-via-auth-request-v1.component.ts deleted file mode 100644 index 66c69d0a41a..00000000000 --- a/apps/browser/src/auth/popup/login-via-auth-request-v1.component.ts +++ /dev/null @@ -1,85 +0,0 @@ -import { Location } from "@angular/common"; -import { Component } from "@angular/core"; -import { Router } from "@angular/router"; - -import { LoginViaAuthRequestComponentV1 as BaseLoginViaAuthRequestComponentV1 } from "@bitwarden/angular/auth/components/login-via-auth-request-v1.component"; -import { - AuthRequestServiceAbstraction, - LoginStrategyServiceAbstraction, - LoginEmailServiceAbstraction, -} from "@bitwarden/auth/common"; -import { ApiService } from "@bitwarden/common/abstractions/api.service"; -import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; -import { AnonymousHubService } from "@bitwarden/common/auth/abstractions/anonymous-hub.service"; -import { AuthService } from "@bitwarden/common/auth/abstractions/auth.service"; -import { DeviceTrustServiceAbstraction } from "@bitwarden/common/auth/abstractions/device-trust.service.abstraction"; -import { AppIdService } from "@bitwarden/common/platform/abstractions/app-id.service"; -import { CryptoFunctionService } from "@bitwarden/common/platform/abstractions/crypto-function.service"; -import { EnvironmentService } from "@bitwarden/common/platform/abstractions/environment.service"; -import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; -import { LogService } from "@bitwarden/common/platform/abstractions/log.service"; -import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; -import { ValidationService } from "@bitwarden/common/platform/abstractions/validation.service"; -import { SyncService } from "@bitwarden/common/vault/abstractions/sync/sync.service.abstraction"; -import { ToastService } from "@bitwarden/components"; -import { PasswordGenerationServiceAbstraction } from "@bitwarden/generator-legacy"; -import { KeyService } from "@bitwarden/key-management"; - -@Component({ - selector: "app-login-via-auth-request", - templateUrl: "login-via-auth-request-v1.component.html", -}) -export class LoginViaAuthRequestComponentV1 extends BaseLoginViaAuthRequestComponentV1 { - constructor( - router: Router, - keyService: KeyService, - cryptoFunctionService: CryptoFunctionService, - appIdService: AppIdService, - passwordGenerationService: PasswordGenerationServiceAbstraction, - apiService: ApiService, - authService: AuthService, - logService: LogService, - environmentService: EnvironmentService, - i18nService: I18nService, - platformUtilsService: PlatformUtilsService, - anonymousHubService: AnonymousHubService, - validationService: ValidationService, - loginEmailService: LoginEmailServiceAbstraction, - syncService: SyncService, - deviceTrustService: DeviceTrustServiceAbstraction, - authRequestService: AuthRequestServiceAbstraction, - loginStrategyService: LoginStrategyServiceAbstraction, - accountService: AccountService, - private location: Location, - toastService: ToastService, - ) { - super( - router, - keyService, - cryptoFunctionService, - appIdService, - passwordGenerationService, - apiService, - authService, - logService, - environmentService, - i18nService, - platformUtilsService, - anonymousHubService, - validationService, - accountService, - loginEmailService, - deviceTrustService, - authRequestService, - loginStrategyService, - toastService, - ); - this.onSuccessfulLogin = async () => { - await syncService.fullSync(true); - }; - } - - protected back() { - this.location.back(); - } -} diff --git a/apps/browser/src/popup/app.module.ts b/apps/browser/src/popup/app.module.ts index 13aeb25b998..72117a2f900 100644 --- a/apps/browser/src/popup/app.module.ts +++ b/apps/browser/src/popup/app.module.ts @@ -23,7 +23,6 @@ import { EnvironmentComponent } from "../auth/popup/environment.component"; import { ExtensionAnonLayoutWrapperComponent } from "../auth/popup/extension-anon-layout-wrapper/extension-anon-layout-wrapper.component"; import { HintComponent } from "../auth/popup/hint.component"; import { LoginDecryptionOptionsComponentV1 } from "../auth/popup/login-decryption-options/login-decryption-options-v1.component"; -import { LoginViaAuthRequestComponentV1 } from "../auth/popup/login-via-auth-request-v1.component"; import { RemovePasswordComponent } from "../auth/popup/remove-password.component"; import { SetPasswordComponent } from "../auth/popup/set-password.component"; import { AccountSecurityComponent } from "../auth/popup/settings/account-security.component"; @@ -96,7 +95,6 @@ import "../platform/popup/locales"; ColorPasswordCountPipe, EnvironmentComponent, HintComponent, - LoginViaAuthRequestComponentV1, LoginDecryptionOptionsComponentV1, SetPasswordComponent, SsoComponentV1, diff --git a/apps/browser/src/popup/scss/base.scss b/apps/browser/src/popup/scss/base.scss index bfa037eea23..7a8d39c6f3e 100644 --- a/apps/browser/src/popup/scss/base.scss +++ b/apps/browser/src/popup/scss/base.scss @@ -448,38 +448,6 @@ main:not(popup-page main) { width: 100%; } -.login-with-device { - .fingerprint-phrase-header { - padding-top: 1rem; - display: block; - } - - @include themify($themes) { - .fingerprint-text { - color: themed("codeColor"); - font-family: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", - monospace; - padding: 1rem 0; - } - } - - .resend-notification { - padding-bottom: 1rem; - a { - cursor: pointer; - } - } - - .footer { - padding-top: 1rem; - - a { - padding-top: 1rem; - display: block; - } - } -} - #login-initiated { .margin-auto { margin: auto; diff --git a/apps/desktop/src/auth/login/login-via-auth-request-v1.component.html b/apps/desktop/src/auth/login/login-via-auth-request-v1.component.html deleted file mode 100644 index 9825949f7ec..00000000000 --- a/apps/desktop/src/auth/login/login-via-auth-request-v1.component.html +++ /dev/null @@ -1,80 +0,0 @@ -
-
- Bitwarden - - -

{{ "logInRequestSent" | i18n }}

- -
-
-
-
-

- {{ "notificationSentDevicePart1" | i18n }} - {{ "notificationSentDeviceAnchor" | i18n }}. {{ "notificationSentDevicePart2" | i18n }} -

-
- -
-

{{ "fingerprintPhraseHeader" | i18n }}

- {{ fingerprintPhrase }} -
- - - -
-

- {{ "needAnotherOption" | i18n }} - - {{ "viewAllLoginOptions" | i18n }} - -

-
-
-
-
-
- - -

{{ "adminApprovalRequested" | i18n }}

- -
-
-
-
-

{{ "adminApprovalRequestSentToAdmins" | i18n }}

-

{{ "youWillBeNotifiedOnceApproved" | i18n }}

-
- -
-

{{ "fingerprintPhraseHeader" | i18n }}

- {{ fingerprintPhrase }} -
- -
-

- {{ "troubleLoggingIn" | i18n }} - - {{ "viewAllLoginOptions" | i18n }} - -

-
-
-
-
-
-
-
- diff --git a/apps/desktop/src/auth/login/login-via-auth-request-v1.component.ts b/apps/desktop/src/auth/login/login-via-auth-request-v1.component.ts deleted file mode 100644 index 30e693b9ac6..00000000000 --- a/apps/desktop/src/auth/login/login-via-auth-request-v1.component.ts +++ /dev/null @@ -1,117 +0,0 @@ -// FIXME: Update this file to be type safe and remove this and next line -// @ts-strict-ignore -import { Location } from "@angular/common"; -import { Component, ViewChild, ViewContainerRef } from "@angular/core"; -import { Router } from "@angular/router"; - -import { LoginViaAuthRequestComponentV1 as BaseLoginViaAuthRequestComponentV1 } from "@bitwarden/angular/auth/components/login-via-auth-request-v1.component"; -import { ModalService } from "@bitwarden/angular/services/modal.service"; -import { - AuthRequestServiceAbstraction, - LoginStrategyServiceAbstraction, - LoginEmailServiceAbstraction, -} from "@bitwarden/auth/common"; -import { ApiService } from "@bitwarden/common/abstractions/api.service"; -import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; -import { AnonymousHubService } from "@bitwarden/common/auth/abstractions/anonymous-hub.service"; -import { AuthService } from "@bitwarden/common/auth/abstractions/auth.service"; -import { DeviceTrustServiceAbstraction } from "@bitwarden/common/auth/abstractions/device-trust.service.abstraction"; -import { AppIdService } from "@bitwarden/common/platform/abstractions/app-id.service"; -import { CryptoFunctionService } from "@bitwarden/common/platform/abstractions/crypto-function.service"; -import { EnvironmentService } from "@bitwarden/common/platform/abstractions/environment.service"; -import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; -import { LogService } from "@bitwarden/common/platform/abstractions/log.service"; -import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; -import { ValidationService } from "@bitwarden/common/platform/abstractions/validation.service"; -import { SyncService } from "@bitwarden/common/vault/abstractions/sync/sync.service.abstraction"; -import { ToastService } from "@bitwarden/components"; -import { PasswordGenerationServiceAbstraction } from "@bitwarden/generator-legacy"; -import { KeyService } from "@bitwarden/key-management"; - -import { EnvironmentComponent } from "../environment.component"; - -@Component({ - selector: "app-login-via-auth-request", - templateUrl: "login-via-auth-request-v1.component.html", -}) -export class LoginViaAuthRequestComponentV1 extends BaseLoginViaAuthRequestComponentV1 { - @ViewChild("environment", { read: ViewContainerRef, static: true }) - environmentModal: ViewContainerRef; - showingModal = false; - - constructor( - protected router: Router, - keyService: KeyService, - cryptoFunctionService: CryptoFunctionService, - appIdService: AppIdService, - passwordGenerationService: PasswordGenerationServiceAbstraction, - apiService: ApiService, - authService: AuthService, - logService: LogService, - environmentService: EnvironmentService, - i18nService: I18nService, - platformUtilsService: PlatformUtilsService, - anonymousHubService: AnonymousHubService, - validationService: ValidationService, - private modalService: ModalService, - syncService: SyncService, - loginEmailService: LoginEmailServiceAbstraction, - deviceTrustService: DeviceTrustServiceAbstraction, - authRequestService: AuthRequestServiceAbstraction, - loginStrategyService: LoginStrategyServiceAbstraction, - accountService: AccountService, - private location: Location, - toastService: ToastService, - ) { - super( - router, - keyService, - cryptoFunctionService, - appIdService, - passwordGenerationService, - apiService, - authService, - logService, - environmentService, - i18nService, - platformUtilsService, - anonymousHubService, - validationService, - accountService, - loginEmailService, - deviceTrustService, - authRequestService, - loginStrategyService, - toastService, - ); - - this.onSuccessfulLogin = () => { - return syncService.fullSync(true); - }; - } - - async settings() { - const [modal, childComponent] = await this.modalService.openViewRef( - EnvironmentComponent, - this.environmentModal, - ); - - // eslint-disable-next-line rxjs-angular/prefer-takeuntil - modal.onShown.subscribe(() => { - this.showingModal = true; - }); - // eslint-disable-next-line rxjs-angular/prefer-takeuntil - modal.onClosed.subscribe(() => { - this.showingModal = false; - }); - - // eslint-disable-next-line rxjs-angular/prefer-takeuntil - childComponent.onSaved.subscribe(() => { - modal.close(); - }); - } - - back() { - this.location.back(); - } -} diff --git a/apps/desktop/src/auth/login/login.module.ts b/apps/desktop/src/auth/login/login.module.ts index 8cd1bdb9212..6fe9f9b07d3 100644 --- a/apps/desktop/src/auth/login/login.module.ts +++ b/apps/desktop/src/auth/login/login.module.ts @@ -6,15 +6,10 @@ import { EnvironmentSelectorComponent } from "@bitwarden/angular/auth/components import { SharedModule } from "../../app/shared/shared.module"; import { LoginDecryptionOptionsComponentV1 } from "./login-decryption-options/login-decryption-options-v1.component"; -import { LoginViaAuthRequestComponentV1 } from "./login-via-auth-request-v1.component"; @NgModule({ imports: [SharedModule, RouterModule], - declarations: [ - LoginViaAuthRequestComponentV1, - EnvironmentSelectorComponent, - LoginDecryptionOptionsComponentV1, - ], - exports: [LoginViaAuthRequestComponentV1], + declarations: [EnvironmentSelectorComponent, LoginDecryptionOptionsComponentV1], + exports: [], }) export class LoginModule {} diff --git a/apps/desktop/src/locales/en/messages.json b/apps/desktop/src/locales/en/messages.json index 7739ab84577..0bc76287adb 100644 --- a/apps/desktop/src/locales/en/messages.json +++ b/apps/desktop/src/locales/en/messages.json @@ -3060,9 +3060,6 @@ "adminApprovalRequestSentToAdmins": { "message": "Your request has been sent to your admin." }, - "youWillBeNotifiedOnceApproved": { - "message": "You will be notified once approved." - }, "troubleLoggingIn": { "message": "Trouble logging in?" }, diff --git a/apps/desktop/src/scss/pages.scss b/apps/desktop/src/scss/pages.scss index fda75e834f3..5f8f501d420 100644 --- a/apps/desktop/src/scss/pages.scss +++ b/apps/desktop/src/scss/pages.scss @@ -1,7 +1,6 @@ @import "variables.scss"; #login-page, -#login-with-device-page, #lock-page, #sso-page, #set-password-page, @@ -191,7 +190,6 @@ } #login-page, -#login-with-device-page, #login-decryption-options-page { flex-direction: column; justify-content: unset; @@ -222,41 +220,6 @@ } } -#login-with-device-page { - .content { - display: block; - padding-top: 70px; - width: 350px !important; - - .fingerprint { - margin: auto; - width: 315px; - - .fingerpint-header { - padding-left: 15px; - } - } - - .section { - margin-bottom: 30px; - } - - .another-method { - display: flex; - margin: auto; - .description-text { - padding-right: 5px; - } - } - - code { - @include themify($themes) { - color: themed("codeColor"); - } - } - } -} - #login-approval-page { .section-title { padding: 20px; diff --git a/apps/web/src/app/auth/login/login-via-auth-request-v1.component.html b/apps/web/src/app/auth/login/login-via-auth-request-v1.component.html deleted file mode 100644 index ed157eb9cf4..00000000000 --- a/apps/web/src/app/auth/login/login-via-auth-request-v1.component.html +++ /dev/null @@ -1,70 +0,0 @@ -
-
- - - -

- {{ "loginOrCreateNewAccount" | i18n }} -

- -
-

{{ "logInRequestSent" | i18n }}

- -

- {{ "notificationSentDeviceComplete" | i18n }} -

- -
-

{{ "fingerprintPhraseHeader" | i18n }}

-

- {{ fingerprintPhrase }} -

-
- - - -
- -
- {{ "loginWithDeviceEnabledNote" | i18n }} - {{ "viewAllLoginOptions" | i18n }} -
-
-
- - -
-

{{ "adminApprovalRequested" | i18n }}

- -
-

{{ "adminApprovalRequestSentToAdmins" | i18n }}

-

{{ "youWillBeNotifiedOnceApproved" | i18n }}

-
- -
-

{{ "fingerprintPhraseHeader" | i18n }}

-

- {{ fingerprintPhrase }} -

-
- -
- -
- {{ "troubleLoggingIn" | i18n }} - {{ "viewAllLoginOptions" | i18n }} -
-
-
-
-
diff --git a/apps/web/src/app/auth/login/login-via-auth-request-v1.component.ts b/apps/web/src/app/auth/login/login-via-auth-request-v1.component.ts deleted file mode 100644 index 8a8883e035b..00000000000 --- a/apps/web/src/app/auth/login/login-via-auth-request-v1.component.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { Component } from "@angular/core"; - -import { LoginViaAuthRequestComponentV1 as BaseLoginViaAuthRequestComponentV1 } from "@bitwarden/angular/auth/components/login-via-auth-request-v1.component"; - -@Component({ - selector: "app-login-via-auth-request", - templateUrl: "login-via-auth-request-v1.component.html", -}) -export class LoginViaAuthRequestComponentV1 extends BaseLoginViaAuthRequestComponentV1 {} diff --git a/apps/web/src/app/auth/login/login.module.ts b/apps/web/src/app/auth/login/login.module.ts index 60c20eb4b7b..12f908324a3 100644 --- a/apps/web/src/app/auth/login/login.module.ts +++ b/apps/web/src/app/auth/login/login.module.ts @@ -5,20 +5,11 @@ import { CheckboxModule } from "@bitwarden/components"; import { SharedModule } from "../../../app/shared"; import { LoginDecryptionOptionsComponentV1 } from "./login-decryption-options/login-decryption-options-v1.component"; -import { LoginViaAuthRequestComponentV1 } from "./login-via-auth-request-v1.component"; import { LoginViaWebAuthnComponent } from "./login-via-webauthn/login-via-webauthn.component"; @NgModule({ imports: [SharedModule, CheckboxModule], - declarations: [ - LoginViaAuthRequestComponentV1, - LoginDecryptionOptionsComponentV1, - LoginViaWebAuthnComponent, - ], - exports: [ - LoginViaAuthRequestComponentV1, - LoginDecryptionOptionsComponentV1, - LoginViaWebAuthnComponent, - ], + declarations: [LoginDecryptionOptionsComponentV1, LoginViaWebAuthnComponent], + exports: [LoginDecryptionOptionsComponentV1, LoginViaWebAuthnComponent], }) export class LoginModule {} diff --git a/apps/web/src/locales/en/messages.json b/apps/web/src/locales/en/messages.json index 68900b2ed74..3e47e2b2279 100644 --- a/apps/web/src/locales/en/messages.json +++ b/apps/web/src/locales/en/messages.json @@ -8681,9 +8681,6 @@ "adminApprovalRequestSentToAdmins": { "message": "Your request has been sent to your admin." }, - "youWillBeNotifiedOnceApproved": { - "message": "You will be notified once approved." - }, "troubleLoggingIn": { "message": "Trouble logging in?" }, diff --git a/libs/angular/src/auth/components/login-via-auth-request-v1.component.ts b/libs/angular/src/auth/components/login-via-auth-request-v1.component.ts deleted file mode 100644 index 7f5a5c3f299..00000000000 --- a/libs/angular/src/auth/components/login-via-auth-request-v1.component.ts +++ /dev/null @@ -1,538 +0,0 @@ -// FIXME: Update this file to be type safe and remove this and next line -// @ts-strict-ignore -import { Directive, OnDestroy, OnInit } from "@angular/core"; -import { IsActiveMatchOptions, Router } from "@angular/router"; -import { Subject, firstValueFrom, map, takeUntil } from "rxjs"; - -import { - AuthRequestLoginCredentials, - AuthRequestServiceAbstraction, - LoginStrategyServiceAbstraction, - LoginEmailServiceAbstraction, -} from "@bitwarden/auth/common"; -import { ApiService } from "@bitwarden/common/abstractions/api.service"; -import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; -import { AnonymousHubService } from "@bitwarden/common/auth/abstractions/anonymous-hub.service"; -import { AuthService } from "@bitwarden/common/auth/abstractions/auth.service"; -import { DeviceTrustServiceAbstraction } from "@bitwarden/common/auth/abstractions/device-trust.service.abstraction"; -import { AuthRequestType } from "@bitwarden/common/auth/enums/auth-request-type"; -import { AuthenticationStatus } from "@bitwarden/common/auth/enums/authentication-status"; -import { AdminAuthRequestStorable } from "@bitwarden/common/auth/models/domain/admin-auth-req-storable"; -import { AuthResult } from "@bitwarden/common/auth/models/domain/auth-result"; -import { ForceSetPasswordReason } from "@bitwarden/common/auth/models/domain/force-set-password-reason"; -import { AuthRequest } from "@bitwarden/common/auth/models/request/auth.request"; -import { AuthRequestResponse } from "@bitwarden/common/auth/models/response/auth-request.response"; -import { HttpStatusCode } from "@bitwarden/common/enums/http-status-code.enum"; -import { ErrorResponse } from "@bitwarden/common/models/response/error.response"; -import { AppIdService } from "@bitwarden/common/platform/abstractions/app-id.service"; -import { CryptoFunctionService } from "@bitwarden/common/platform/abstractions/crypto-function.service"; -import { EnvironmentService } from "@bitwarden/common/platform/abstractions/environment.service"; -import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; -import { LogService } from "@bitwarden/common/platform/abstractions/log.service"; -import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; -import { ValidationService } from "@bitwarden/common/platform/abstractions/validation.service"; -import { Utils } from "@bitwarden/common/platform/misc/utils"; -import { UserId } from "@bitwarden/common/types/guid"; -import { ToastService } from "@bitwarden/components"; -import { PasswordGenerationServiceAbstraction } from "@bitwarden/generator-legacy"; -import { KeyService } from "@bitwarden/key-management"; - -import { CaptchaProtectedComponent } from "./captcha-protected.component"; - -enum State { - StandardAuthRequest, - AdminAuthRequest, -} - -@Directive() -export class LoginViaAuthRequestComponentV1 - extends CaptchaProtectedComponent - implements OnInit, OnDestroy -{ - private destroy$ = new Subject(); - userAuthNStatus: AuthenticationStatus; - email: string; - showResendNotification = false; - authRequest: AuthRequest; - fingerprintPhrase: string; - onSuccessfulLoginTwoFactorNavigate: () => Promise; - onSuccessfulLogin: () => Promise; - onSuccessfulLoginNavigate: () => Promise; - onSuccessfulLoginForceResetNavigate: () => Promise; - - protected adminApprovalRoute = "admin-approval-requested"; - - protected StateEnum = State; - protected state = State.StandardAuthRequest; - protected webVaultUrl: string; - protected twoFactorRoute = "2fa"; - protected successRoute = "vault"; - protected forcePasswordResetRoute = "update-temp-password"; - private resendTimeout = 12000; - protected deviceManagementUrl: string; - - private authRequestKeyPair: { publicKey: Uint8Array; privateKey: Uint8Array }; - - constructor( - protected router: Router, - private keyService: KeyService, - private cryptoFunctionService: CryptoFunctionService, - private appIdService: AppIdService, - private passwordGenerationService: PasswordGenerationServiceAbstraction, - private apiService: ApiService, - private authService: AuthService, - private logService: LogService, - environmentService: EnvironmentService, - i18nService: I18nService, - platformUtilsService: PlatformUtilsService, - private anonymousHubService: AnonymousHubService, - private validationService: ValidationService, - private accountService: AccountService, - private loginEmailService: LoginEmailServiceAbstraction, - private deviceTrustService: DeviceTrustServiceAbstraction, - private authRequestService: AuthRequestServiceAbstraction, - private loginStrategyService: LoginStrategyServiceAbstraction, - protected toastService: ToastService, - ) { - super(environmentService, i18nService, platformUtilsService, toastService); - - // Get the web vault URL from the environment service - environmentService.environment$.pipe(takeUntil(this.destroy$)).subscribe((env) => { - this.webVaultUrl = env.getWebVaultUrl(); - this.deviceManagementUrl = `${this.webVaultUrl}/#/settings/security/device-management`; - }); - - // Gets signalR push notification - // Only fires on approval to prevent enumeration - this.authRequestService.authRequestPushNotification$ - .pipe(takeUntil(this.destroy$)) - .subscribe((id) => { - this.verifyAndHandleApprovedAuthReq(id).catch((e: Error) => { - this.toastService.showToast({ - variant: "error", - title: this.i18nService.t("error"), - message: e.message, - }); - this.logService.error("Failed to use approved auth request: " + e.message); - }); - }); - } - - async ngOnInit() { - this.email = await firstValueFrom(this.loginEmailService.loginEmail$); - this.userAuthNStatus = await this.authService.getAuthStatus(); - - const matchOptions: IsActiveMatchOptions = { - paths: "exact", - queryParams: "ignored", - fragment: "ignored", - matrixParams: "ignored", - }; - - if (this.router.isActive(this.adminApprovalRoute, matchOptions)) { - this.state = State.AdminAuthRequest; - } - - if (this.state === State.AdminAuthRequest) { - // Pull email from state for admin auth reqs b/c it is available - // This also prevents it from being lost on refresh as the - // login service email does not persist. - this.email = await firstValueFrom( - this.accountService.activeAccount$.pipe(map((a) => a?.email)), - ); - const userId = (await firstValueFrom(this.accountService.activeAccount$)).id; - - if (!this.email) { - this.toastService.showToast({ - variant: "error", - title: null, - message: this.i18nService.t("userEmailMissing"), - }); - // 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(["/login-initiated"]); - return; - } - - // We only allow a single admin approval request to be active at a time - // so must check state to see if we have an existing one or not - const adminAuthReqStorable = await this.authRequestService.getAdminAuthRequest(userId); - - if (adminAuthReqStorable) { - await this.handleExistingAdminAuthRequest(adminAuthReqStorable, userId); - } else { - // No existing admin auth request; so we need to create one - await this.startAuthRequestLogin(); - } - } else { - // Standard auth request - // TODO: evaluate if we can remove the setting of this.email in the constructor - this.email = await firstValueFrom(this.loginEmailService.loginEmail$); - - if (!this.email) { - this.toastService.showToast({ - variant: "error", - title: null, - message: this.i18nService.t("userEmailMissing"), - }); - // 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(["/login"]); - return; - } - - await this.startAuthRequestLogin(); - } - } - - async ngOnDestroy() { - await this.anonymousHubService.stopHubConnection(); - this.destroy$.next(); - this.destroy$.complete(); - } - - private async handleExistingAdminAuthRequest( - adminAuthReqStorable: AdminAuthRequestStorable, - userId: UserId, - ) { - // Note: on login, the SSOLoginStrategy will also call to see an existing admin auth req - // has been approved and handle it if so. - - // Regardless, we always retrieve the auth request from the server verify and handle status changes here as well - let adminAuthReqResponse: AuthRequestResponse; - try { - adminAuthReqResponse = await this.apiService.getAuthRequest(adminAuthReqStorable.id); - } catch (error) { - if (error instanceof ErrorResponse && error.statusCode === HttpStatusCode.NotFound) { - return await this.handleExistingAdminAuthReqDeletedOrDenied(userId); - } - } - - // Request doesn't exist anymore - if (!adminAuthReqResponse) { - return await this.handleExistingAdminAuthReqDeletedOrDenied(userId); - } - - // Re-derive the user's fingerprint phrase - // It is important to not use the server's public key here as it could have been compromised via MITM - const derivedPublicKeyArrayBuffer = await this.cryptoFunctionService.rsaExtractPublicKey( - adminAuthReqStorable.privateKey, - ); - this.fingerprintPhrase = await this.authRequestService.getFingerprintPhrase( - this.email, - derivedPublicKeyArrayBuffer, - ); - - // Request denied - if (adminAuthReqResponse.isAnswered && !adminAuthReqResponse.requestApproved) { - return await this.handleExistingAdminAuthReqDeletedOrDenied(userId); - } - - // Request approved - if (adminAuthReqResponse.requestApproved) { - return await this.handleApprovedAdminAuthRequest( - adminAuthReqResponse, - adminAuthReqStorable.privateKey, - userId, - ); - } - - // Request still pending response from admin - // set keypair and create hub connection so that any approvals will be received via push notification - this.authRequestKeyPair = { privateKey: adminAuthReqStorable.privateKey, publicKey: null }; - await this.anonymousHubService.createHubConnection(adminAuthReqStorable.id); - } - - private async handleExistingAdminAuthReqDeletedOrDenied(userId: UserId) { - // clear the admin auth request from state - await this.authRequestService.clearAdminAuthRequest(userId); - - // start new auth request - // 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.startAuthRequestLogin(); - } - - private async buildAuthRequest(authRequestType: AuthRequestType) { - const authRequestKeyPairArray = await this.cryptoFunctionService.rsaGenerateKeyPair(2048); - - this.authRequestKeyPair = { - publicKey: authRequestKeyPairArray[0], - privateKey: authRequestKeyPairArray[1], - }; - - const deviceIdentifier = await this.appIdService.getAppId(); - const publicKey = Utils.fromBufferToB64(this.authRequestKeyPair.publicKey); - const accessCode = await this.passwordGenerationService.generatePassword({ - type: "password", - length: 25, - }); - - this.fingerprintPhrase = await this.authRequestService.getFingerprintPhrase( - this.email, - this.authRequestKeyPair.publicKey, - ); - - this.authRequest = new AuthRequest( - this.email, - deviceIdentifier, - publicKey, - authRequestType, - accessCode, - ); - } - - async startAuthRequestLogin() { - this.showResendNotification = false; - - try { - let reqResponse: AuthRequestResponse; - - if (this.state === State.AdminAuthRequest) { - await this.buildAuthRequest(AuthRequestType.AdminApproval); - reqResponse = await this.apiService.postAdminAuthRequest(this.authRequest); - - const adminAuthReqStorable = new AdminAuthRequestStorable({ - id: reqResponse.id, - privateKey: this.authRequestKeyPair.privateKey, - }); - - const userId = (await firstValueFrom(this.accountService.activeAccount$)).id; - await this.authRequestService.setAdminAuthRequest(adminAuthReqStorable, userId); - } else { - await this.buildAuthRequest(AuthRequestType.AuthenticateAndUnlock); - reqResponse = await this.apiService.postAuthRequest(this.authRequest); - } - - if (reqResponse.id) { - await this.anonymousHubService.createHubConnection(reqResponse.id); - } - } catch (e) { - this.logService.error(e); - } - - setTimeout(() => { - this.showResendNotification = true; - }, this.resendTimeout); - } - - private async verifyAndHandleApprovedAuthReq(requestId: string) { - try { - // Retrieve the auth request from server and verify it's approved - let authReqResponse: AuthRequestResponse; - - switch (this.state) { - case State.StandardAuthRequest: - // Unauthed - access code required for user verification - authReqResponse = await this.apiService.getAuthResponse( - requestId, - this.authRequest.accessCode, - ); - break; - - case State.AdminAuthRequest: - // Authed - no access code required - authReqResponse = await this.apiService.getAuthRequest(requestId); - break; - - default: - break; - } - - if (!authReqResponse.requestApproved) { - return; - } - - // Approved so proceed: - - // 4 Scenarios to handle for approved auth requests: - // Existing flow 1: - // - Anon Login with Device > User is not AuthN > receives approval from device with pubKey(masterKey) - // > decrypt masterKey > must authenticate > gets masterKey(userKey) > decrypt userKey and proceed to vault - - // 3 new flows from TDE: - // Flow 2: - // - Post SSO > User is AuthN > SSO login strategy success sets masterKey(userKey) > receives approval from device with pubKey(masterKey) - // > decrypt masterKey > decrypt userKey > establish trust if required > proceed to vault - // Flow 3: - // - Post SSO > User is AuthN > Receives approval from device with pubKey(userKey) > decrypt userKey > establish trust if required > proceed to vault - // Flow 4: - // - Anon Login with Device > User is not AuthN > receives approval from device with pubKey(userKey) - // > decrypt userKey > must authenticate > set userKey > proceed to vault - - // if user has authenticated via SSO - if (this.userAuthNStatus === AuthenticationStatus.Locked) { - const userId = (await firstValueFrom(this.accountService.activeAccount$)).id; - return await this.handleApprovedAdminAuthRequest( - authReqResponse, - this.authRequestKeyPair.privateKey, - userId, - ); - } - - // Flow 1 and 4: - const loginAuthResult = await this.loginViaAuthRequestStrategy(requestId, authReqResponse); - await this.handlePostLoginNavigation(loginAuthResult); - } catch (error) { - if (error instanceof ErrorResponse) { - let errorRoute = "/login"; - if (this.state === State.AdminAuthRequest) { - errorRoute = "/login-initiated"; - } - - // 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([errorRoute]); - this.validationService.showError(error); - return; - } - - this.logService.error(error); - } - } - - async handleApprovedAdminAuthRequest( - adminAuthReqResponse: AuthRequestResponse, - privateKey: ArrayBuffer, - userId: UserId, - ) { - // See verifyAndHandleApprovedAuthReq(...) for flow details - // it's flow 2 or 3 based on presence of masterPasswordHash - if (adminAuthReqResponse.masterPasswordHash) { - // Flow 2: masterPasswordHash is not null - // key is authRequestPublicKey(masterKey) + we have authRequestPublicKey(masterPasswordHash) - await this.authRequestService.setKeysAfterDecryptingSharedMasterKeyAndHash( - adminAuthReqResponse, - privateKey, - userId, - ); - } else { - // Flow 3: masterPasswordHash is null - // we can assume key is authRequestPublicKey(userKey) and we can just decrypt with userKey and proceed to vault - await this.authRequestService.setUserKeyAfterDecryptingSharedUserKey( - adminAuthReqResponse, - privateKey, - userId, - ); - } - - // clear the admin auth request from state so it cannot be used again (it's a one time use) - // TODO: this should eventually be enforced via deleting this on the server once it is used - await this.authRequestService.clearAdminAuthRequest(userId); - - this.toastService.showToast({ - variant: "success", - title: null, - message: this.i18nService.t("loginApproved"), - }); - - // Now that we have a decrypted user key in memory, we can check if we - // need to establish trust on the current device - const activeAccount = await firstValueFrom(this.accountService.activeAccount$); - await this.deviceTrustService.trustDeviceIfRequired(activeAccount.id); - - // TODO: don't forget to use auto enrollment service everywhere we trust device - - await this.handleSuccessfulLoginNavigation(); - } - - // Authentication helper - private async buildAuthRequestLoginCredentials( - requestId: string, - response: AuthRequestResponse, - ): Promise { - // if masterPasswordHash has a value, we will always receive key as authRequestPublicKey(masterKey) + authRequestPublicKey(masterPasswordHash) - // if masterPasswordHash is null, we will always receive key as authRequestPublicKey(userKey) - if (response.masterPasswordHash) { - const { masterKey, masterKeyHash } = - await this.authRequestService.decryptPubKeyEncryptedMasterKeyAndHash( - response.key, - response.masterPasswordHash, - this.authRequestKeyPair.privateKey, - ); - - return new AuthRequestLoginCredentials( - this.email, - this.authRequest.accessCode, - requestId, - null, // no userKey - masterKey, - masterKeyHash, - ); - } else { - const userKey = await this.authRequestService.decryptPubKeyEncryptedUserKey( - response.key, - this.authRequestKeyPair.privateKey, - ); - return new AuthRequestLoginCredentials( - this.email, - this.authRequest.accessCode, - requestId, - userKey, - null, // no masterKey - null, // no masterKeyHash - ); - } - } - - private async loginViaAuthRequestStrategy( - requestId: string, - authReqResponse: AuthRequestResponse, - ): Promise { - // Note: credentials change based on if the authReqResponse.key is a encryptedMasterKey or UserKey - const credentials = await this.buildAuthRequestLoginCredentials(requestId, authReqResponse); - - // Note: keys are set by AuthRequestLoginStrategy success handling - return await this.loginStrategyService.logIn(credentials); - } - - // Routing logic - private async handlePostLoginNavigation(loginResponse: AuthResult) { - if (loginResponse.requiresTwoFactor) { - if (this.onSuccessfulLoginTwoFactorNavigate != null) { - // 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.onSuccessfulLoginTwoFactorNavigate(); - } else { - // 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.twoFactorRoute]); - } - } else if (loginResponse.forcePasswordReset != ForceSetPasswordReason.None) { - if (this.onSuccessfulLoginForceResetNavigate != null) { - // 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.onSuccessfulLoginForceResetNavigate(); - } else { - // 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]); - } - } else { - await this.handleSuccessfulLoginNavigation(); - } - } - - private async handleSuccessfulLoginNavigation() { - if (this.state === State.StandardAuthRequest) { - // Only need to set remembered email on standard login with auth req flow - await this.loginEmailService.saveEmailSettings(); - } - - if (this.onSuccessfulLogin != null) { - // 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.onSuccessfulLogin(); - } - - if (this.onSuccessfulLoginNavigate != null) { - // 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.onSuccessfulLoginNavigate(); - } else { - // 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]); - } - } -} diff --git a/libs/common/src/abstractions/api.service.ts b/libs/common/src/abstractions/api.service.ts index 32cabbf7618..013b36f6358 100644 --- a/libs/common/src/abstractions/api.service.ts +++ b/libs/common/src/abstractions/api.service.ts @@ -38,7 +38,6 @@ import { ProviderUserUserDetailsResponse, } from "../admin-console/models/response/provider/provider-user.response"; import { SelectionReadOnlyResponse } from "../admin-console/models/response/selection-read-only.response"; -import { AuthRequest } from "../auth/models/request/auth.request"; import { DeviceVerificationRequest } from "../auth/models/request/device-verification.request"; import { DisableTwoFactorAuthenticatorRequest } from "../auth/models/request/disable-two-factor-authenticator.request"; import { EmailTokenRequest } from "../auth/models/request/email-token.request"; @@ -185,9 +184,6 @@ export abstract class ApiService { postUserRotateApiKey: (id: string, request: SecretVerificationRequest) => Promise; postConvertToKeyConnector: () => Promise; //passwordless - postAuthRequest: (request: AuthRequest) => Promise; - postAdminAuthRequest: (request: AuthRequest) => Promise; - getAuthResponse: (id: string, accessCode: string) => Promise; getAuthRequest: (id: string) => Promise; putAuthRequest: (id: string, request: PasswordlessAuthRequest) => Promise; getAuthRequests: () => Promise>; diff --git a/libs/common/src/services/api.service.ts b/libs/common/src/services/api.service.ts index 3d89e75cf8a..93e455ada80 100644 --- a/libs/common/src/services/api.service.ts +++ b/libs/common/src/services/api.service.ts @@ -43,7 +43,6 @@ import { } from "../admin-console/models/response/provider/provider-user.response"; import { SelectionReadOnlyResponse } from "../admin-console/models/response/selection-read-only.response"; import { TokenService } from "../auth/abstractions/token.service"; -import { AuthRequest } from "../auth/models/request/auth.request"; import { DeviceVerificationRequest } from "../auth/models/request/device-verification.request"; import { DisableTwoFactorAuthenticatorRequest } from "../auth/models/request/disable-two-factor-authenticator.request"; import { EmailTokenRequest } from "../auth/models/request/email-token.request"; @@ -275,22 +274,6 @@ export class ApiService implements ApiServiceAbstraction { } // TODO: PM-3519: Create and move to AuthRequest Api service - // TODO: PM-9724: Remove legacy auth request methods when we remove legacy LoginViaAuthRequestV1Components - async postAuthRequest(request: AuthRequest): Promise { - const r = await this.send("POST", "/auth-requests/", request, false, true); - return new AuthRequestResponse(r); - } - async postAdminAuthRequest(request: AuthRequest): Promise { - const r = await this.send("POST", "/auth-requests/admin-request", request, true, true); - return new AuthRequestResponse(r); - } - - async getAuthResponse(id: string, accessCode: string): Promise { - const path = `/auth-requests/${id}/response?code=${accessCode}`; - const r = await this.send("GET", path, null, false, true); - return new AuthRequestResponse(r); - } - async getAuthRequest(id: string): Promise { const path = `/auth-requests/${id}`; const r = await this.send("GET", path, null, true, true);