diff --git a/apps/browser/src/_locales/en/messages.json b/apps/browser/src/_locales/en/messages.json index ab1c6377e6a..39bc6ed9b86 100644 --- a/apps/browser/src/_locales/en/messages.json +++ b/apps/browser/src/_locales/en/messages.json @@ -1319,6 +1319,12 @@ "enterVerificationCodeApp": { "message": "Enter the 6 digit verification code from your authenticator app." }, + "authenticationTimeout": { + "message": "Authentication timeout" + }, + "authenticationSessionTimedOut": { + "message": "The authentication session timed out. Please restart the login process." + }, "enterVerificationCodeEmail": { "message": "Enter the 6 digit verification code that was emailed to $EMAIL$.", "placeholders": { diff --git a/apps/browser/src/popup/app-routing.module.ts b/apps/browser/src/popup/app-routing.module.ts index 77a720557c6..b158a83c566 100644 --- a/apps/browser/src/popup/app-routing.module.ts +++ b/apps/browser/src/popup/app-routing.module.ts @@ -6,6 +6,7 @@ import { EnvironmentSelectorRouteData, ExtensionDefaultOverlayPosition, } from "@bitwarden/angular/auth/components/environment-selector.component"; +import { TwoFactorTimeoutComponent } from "@bitwarden/angular/auth/components/two-factor-auth/two-factor-auth-expired.component"; import { unauthUiRefreshRedirect } from "@bitwarden/angular/auth/functions/unauth-ui-refresh-redirect"; import { unauthUiRefreshSwap } from "@bitwarden/angular/auth/functions/unauth-ui-refresh-route-swap"; import { @@ -38,6 +39,7 @@ import { VaultIcon, LoginDecryptionOptionsComponent, DevicesIcon, + TwoFactorTimeoutIcon, } from "@bitwarden/auth/angular"; import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum"; @@ -199,6 +201,29 @@ const routes: Routes = [ ], }, ), + { + path: "", + component: ExtensionAnonLayoutWrapperComponent, + children: [ + { + path: "2fa-timeout", + canActivate: [unauthGuardFn(unauthRouteOverrides)], + children: [ + { + path: "", + component: TwoFactorTimeoutComponent, + }, + ], + data: { + pageTitle: { + key: "authenticationTimeout", + }, + pageIcon: TwoFactorTimeoutIcon, + elevation: 1, + } satisfies RouteDataProperties & AnonLayoutWrapperData, + }, + ], + }, { path: "2fa-options", component: TwoFactorOptionsComponent, diff --git a/apps/desktop/src/app/app-routing.module.ts b/apps/desktop/src/app/app-routing.module.ts index e61335859c4..db9ece317c8 100644 --- a/apps/desktop/src/app/app-routing.module.ts +++ b/apps/desktop/src/app/app-routing.module.ts @@ -5,6 +5,7 @@ import { DesktopDefaultOverlayPosition, EnvironmentSelectorComponent, } from "@bitwarden/angular/auth/components/environment-selector.component"; +import { TwoFactorTimeoutComponent } from "@bitwarden/angular/auth/components/two-factor-auth/two-factor-auth-expired.component"; import { unauthUiRefreshSwap } from "@bitwarden/angular/auth/functions/unauth-ui-refresh-route-swap"; import { authGuard, @@ -35,6 +36,7 @@ import { VaultIcon, LoginDecryptionOptionsComponent, DevicesIcon, + TwoFactorTimeoutIcon, } from "@bitwarden/auth/angular"; import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum"; @@ -96,6 +98,22 @@ const routes: Routes = [ ], }, ), + { + path: "2fa-timeout", + component: AnonLayoutWrapperComponent, + children: [ + { + path: "", + component: TwoFactorTimeoutComponent, + }, + ], + data: { + pageIcon: TwoFactorTimeoutIcon, + pageTitle: { + key: "authenticationTimeout", + }, + } satisfies RouteDataProperties & AnonLayoutWrapperData, + }, { path: "register", component: RegisterComponent }, { path: "vault", diff --git a/apps/desktop/src/locales/en/messages.json b/apps/desktop/src/locales/en/messages.json index e9bebb8bfc0..e4c235dada9 100644 --- a/apps/desktop/src/locales/en/messages.json +++ b/apps/desktop/src/locales/en/messages.json @@ -919,6 +919,12 @@ "baseUrl": { "message": "Server URL" }, + "authenticationTimeout": { + "message": "Authentication timeout" + }, + "authenticationSessionTimedOut": { + "message": "The authentication session timed out. Please restart the login process." + }, "selfHostBaseUrl": { "message": "Self-host server URL", "description": "Label for field requesting a self-hosted integration service URL" diff --git a/apps/web/src/app/oss-routing.module.ts b/apps/web/src/app/oss-routing.module.ts index 6e2e97d8e06..8aea628ddde 100644 --- a/apps/web/src/app/oss-routing.module.ts +++ b/apps/web/src/app/oss-routing.module.ts @@ -1,6 +1,7 @@ import { NgModule } from "@angular/core"; import { Route, RouterModule, Routes } from "@angular/router"; +import { TwoFactorTimeoutComponent } from "@bitwarden/angular/auth/components/two-factor-auth/two-factor-auth-expired.component"; import { unauthUiRefreshSwap } from "@bitwarden/angular/auth/functions/unauth-ui-refresh-route-swap"; import { authGuard, @@ -26,6 +27,7 @@ import { LoginSecondaryContentComponent, LockV2Component, LockIcon, + TwoFactorTimeoutIcon, UserLockIcon, LoginViaAuthRequestComponent, DevicesIcon, @@ -507,7 +509,6 @@ const routes: Routes = [ } satisfies AnonLayoutWrapperData, }, ), - { path: "2fa", canActivate: [unauthGuardFn()], @@ -527,6 +528,28 @@ const routes: Routes = [ }, } satisfies RouteDataProperties & AnonLayoutWrapperData, }, + { + path: "2fa-timeout", + canActivate: [unauthGuardFn()], + children: [ + { + path: "", + component: TwoFactorTimeoutComponent, + }, + { + path: "", + component: EnvironmentSelectorComponent, + outlet: "environment-selector", + }, + ], + data: { + pageIcon: TwoFactorTimeoutIcon, + pageTitle: { + key: "authenticationTimeout", + }, + titleId: "authenticationTimeout", + } satisfies RouteDataProperties & AnonLayoutWrapperData, + }, { path: "recover-2fa", canActivate: [unauthGuardFn()], diff --git a/apps/web/src/locales/en/messages.json b/apps/web/src/locales/en/messages.json index 7025e194786..cab0e703a7d 100644 --- a/apps/web/src/locales/en/messages.json +++ b/apps/web/src/locales/en/messages.json @@ -1137,6 +1137,12 @@ "logInToBitwarden": { "message": "Log in to Bitwarden" }, + "authenticationTimeout": { + "message": "Authentication timeout" + }, + "authenticationSessionTimedOut": { + "message": "The authentication session timed out. Please restart the login process." + }, "verifyIdentity": { "message": "Verify your Identity" }, diff --git a/libs/angular/src/auth/components/two-factor-auth/two-factor-auth-expired.component.ts b/libs/angular/src/auth/components/two-factor-auth/two-factor-auth-expired.component.ts new file mode 100644 index 00000000000..faa08cf073b --- /dev/null +++ b/libs/angular/src/auth/components/two-factor-auth/two-factor-auth-expired.component.ts @@ -0,0 +1,25 @@ +import { CommonModule } from "@angular/common"; +import { Component } from "@angular/core"; +import { RouterModule } from "@angular/router"; + +import { JslibModule } from "@bitwarden/angular/jslib.module"; +import { ButtonModule } from "@bitwarden/components"; + +/** + * This component is used to display a message to the user that their authentication session has expired. + * It provides a button to navigate to the login page. + */ +@Component({ + selector: "app-two-factor-expired", + standalone: true, + imports: [CommonModule, JslibModule, ButtonModule, RouterModule], + template: ` +
+ {{ "authenticationSessionTimedOut" | i18n }} +
+ + {{ "logIn" | i18n }} + + `, +}) +export class TwoFactorTimeoutComponent {} diff --git a/libs/angular/src/auth/components/two-factor.component.spec.ts b/libs/angular/src/auth/components/two-factor.component.spec.ts index e21d119adf8..5a1903d6671 100644 --- a/libs/angular/src/auth/components/two-factor.component.spec.ts +++ b/libs/angular/src/auth/components/two-factor.component.spec.ts @@ -86,9 +86,12 @@ describe("TwoFactorComponent", () => { }; let selectedUserDecryptionOptions: BehaviorSubject