diff --git a/libs/auth/src/angular/login-decryption-options/login-decryption-options.component.ts b/libs/auth/src/angular/login-decryption-options/login-decryption-options.component.ts index 62fbeae26b6..945e6bbaaf5 100644 --- a/libs/auth/src/angular/login-decryption-options/login-decryption-options.component.ts +++ b/libs/auth/src/angular/login-decryption-options/login-decryption-options.component.ts @@ -284,7 +284,6 @@ export class LoginDecryptionOptionsComponent implements OnInit { } protected async approveFromOtherDevice() { - this.loginEmailService.setLoginEmail(this.email); await this.router.navigate(["/login-with-device"]); } @@ -297,7 +296,6 @@ export class LoginDecryptionOptionsComponent implements OnInit { } protected async requestAdminApproval() { - this.loginEmailService.setLoginEmail(this.email); await this.router.navigate(["/admin-approval-requested"]); } diff --git a/libs/auth/src/angular/login-via-auth-request/login-via-auth-request.component.ts b/libs/auth/src/angular/login-via-auth-request/login-via-auth-request.component.ts index 0af52e02b84..5de2339bda1 100644 --- a/libs/auth/src/angular/login-via-auth-request/login-via-auth-request.component.ts +++ b/libs/auth/src/angular/login-via-auth-request/login-via-auth-request.component.ts @@ -2,7 +2,7 @@ import { CommonModule } from "@angular/common"; import { Component, OnDestroy, OnInit } from "@angular/core"; import { takeUntilDestroyed } from "@angular/core/rxjs-interop"; import { IsActiveMatchOptions, Router, RouterModule } from "@angular/router"; -import { firstValueFrom, map } from "rxjs"; +import { Observable, filter, firstValueFrom, map, merge, race, take, timer } from "rxjs"; import { JslibModule } from "@bitwarden/angular/jslib.module"; import { @@ -178,7 +178,26 @@ export class LoginViaAuthRequestComponent implements OnInit, OnDestroy { private async initStandardAuthRequestFlow(): Promise { this.flow = Flow.StandardAuthRequest; - this.email = (await firstValueFrom(this.loginEmailService.loginEmail$)) || undefined; + // For a standard flow, we can get the user's email from two different places: + // 1. The loginEmailService, which is the email that the user is trying to log in with. This is cleared + // when the user logs in successfully. We can use this when the user is using Login with Device. + // 2. With TDE Login with Another Device, the user is already logged in and we just need to get + // a decryption key, so we can use the active account's email. + const activeAccountEmail$: Observable = + this.accountService.activeAccount$.pipe(map((a) => a?.email)); + const loginEmail$: Observable = this.loginEmailService.loginEmail$; + + // Use merge as we want to get the first value from either observable. + const firstEmail$ = merge(loginEmail$, activeAccountEmail$).pipe( + filter((e): e is string => !!e), // convert null/undefined to false and filter out so we narrow type to string + take(1), // complete after first value + ); + + const emailRetrievalTimeout$ = timer(2500).pipe(map(() => undefined as undefined)); + + // Wait for either the first email or the timeout to occur so we can proceed + // neither above observable will complete, so we have to add a timeout + this.email = await firstValueFrom(race(firstEmail$, emailRetrievalTimeout$)); if (!this.email) { await this.handleMissingEmail(); diff --git a/libs/auth/src/angular/login/login.component.ts b/libs/auth/src/angular/login/login.component.ts index 4ca18b4985e..eb2bdcee291 100644 --- a/libs/auth/src/angular/login/login.component.ts +++ b/libs/auth/src/angular/login/login.component.ts @@ -539,7 +539,7 @@ export class LoginComponent implements OnInit, OnDestroy { // If we load an email into the form, we need to initialize it for the login process as well // so that other login components can use it. // We do this here as it's possible that a user doesn't edit the email field before submitting. - this.loginEmailService.setLoginEmail(storedEmail); + await this.loginEmailService.setLoginEmail(storedEmail); } else { this.formGroup.controls.rememberEmail.setValue(false); } diff --git a/libs/auth/src/angular/password-hint/password-hint.component.ts b/libs/auth/src/angular/password-hint/password-hint.component.ts index 996b4d8d92e..cf24c68e10d 100644 --- a/libs/auth/src/angular/password-hint/password-hint.component.ts +++ b/libs/auth/src/angular/password-hint/password-hint.component.ts @@ -79,7 +79,7 @@ export class PasswordHintComponent implements OnInit { }; protected async cancel() { - this.loginEmailService.setLoginEmail(this.email); + await this.loginEmailService.setLoginEmail(this.email); await this.router.navigate(["login"]); }