diff --git a/apps/browser/src/_locales/en/messages.json b/apps/browser/src/_locales/en/messages.json
index bd62b825e79..493a909f8ac 100644
--- a/apps/browser/src/_locales/en/messages.json
+++ b/apps/browser/src/_locales/en/messages.json
@@ -374,12 +374,21 @@
"other": {
"message": "Other"
},
+ "unlockMethods": {
+ "message": "Unlock options"
+ },
"unlockMethodNeededToChangeTimeoutActionDesc": {
"message": "Set up an unlock method to change your vault timeout action."
},
"unlockMethodNeeded": {
"message": "Set up an unlock method in Settings"
},
+ "sessionTimeoutHeader": {
+ "message": "Session timeout"
+ },
+ "otherOptions": {
+ "message": "Other options"
+ },
"rateExtension": {
"message": "Rate the extension"
},
@@ -3023,6 +3032,9 @@
"adminConsole": {
"message": "Admin Console"
},
+ "accountSecurity": {
+ "message": "Account security"
+ },
"errorAssigningTargetCollection": {
"message": "Error assigning target collection."
},
diff --git a/apps/browser/src/auth/popup/settings/account-security.component.html b/apps/browser/src/auth/popup/settings/account-security.component.html
new file mode 100644
index 00000000000..dff9675743f
--- /dev/null
+++ b/apps/browser/src/auth/popup/settings/account-security.component.html
@@ -0,0 +1,140 @@
+
+
+
+
+
+ {{ "accountSecurity" | i18n }}
+
+
+
+
+
+
+
+
+
+
+ {{
+ "vaultTimeoutPolicyWithActionInEffect"
+ | i18n: policy.timeout.hours : policy.timeout.minutes : (policy.action | i18n)
+ }}
+
+
+ {{ "vaultTimeoutPolicyInEffect" | i18n: policy.timeout.hours : policy.timeout.minutes }}
+
+
+ {{ "vaultTimeoutActionPolicyInEffect" | i18n: (policy.action | i18n) }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/apps/browser/src/popup/settings/settings.component.ts b/apps/browser/src/auth/popup/settings/account-security.component.ts
similarity index 83%
rename from apps/browser/src/popup/settings/settings.component.ts
rename to apps/browser/src/auth/popup/settings/account-security.component.ts
index c7e5b7dc952..88365e7b472 100644
--- a/apps/browser/src/popup/settings/settings.component.ts
+++ b/apps/browser/src/auth/popup/settings/account-security.component.ts
@@ -1,6 +1,5 @@
import { ChangeDetectorRef, Component, OnInit } from "@angular/core";
import { FormBuilder } from "@angular/forms";
-import { Router } from "@angular/router";
import {
BehaviorSubject,
combineLatest,
@@ -23,7 +22,6 @@ import { PolicyService } from "@bitwarden/common/admin-console/abstractions/poli
import { PolicyType } from "@bitwarden/common/admin-console/enums";
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
import { UserVerificationService } from "@bitwarden/common/auth/abstractions/user-verification/user-verification.service.abstraction";
-import { DeviceType } from "@bitwarden/common/enums";
import { VaultTimeoutAction } from "@bitwarden/common/enums/vault-timeout-action.enum";
import { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.service";
import { EnvironmentService } from "@bitwarden/common/platform/abstractions/environment.service";
@@ -34,35 +32,20 @@ import { StateService } from "@bitwarden/common/platform/abstractions/state.serv
import { BiometricStateService } from "@bitwarden/common/platform/biometrics/biometric-state.service";
import { DialogService } from "@bitwarden/components";
-import { SetPinComponent } from "../../auth/popup/components/set-pin.component";
-import { BiometricErrors, BiometricErrorTypes } from "../../models/biometricErrors";
-import { BrowserApi } from "../../platform/browser/browser-api";
-import { enableAccountSwitching } from "../../platform/flags";
-import BrowserPopupUtils from "../../platform/popup/browser-popup-utils";
+import { BiometricErrors, BiometricErrorTypes } from "../../../models/biometricErrors";
+import { BrowserApi } from "../../../platform/browser/browser-api";
+import { enableAccountSwitching } from "../../../platform/flags";
+import BrowserPopupUtils from "../../../platform/popup/browser-popup-utils";
+import { SetPinComponent } from "../components/set-pin.component";
-import { AboutComponent } from "./about.component";
import { AwaitDesktopDialogComponent } from "./await-desktop-dialog.component";
-const RateUrls = {
- [DeviceType.ChromeExtension]:
- "https://chromewebstore.google.com/detail/bitwarden-free-password-m/nngceckbapebfimnlniiiahkandclblb/reviews",
- [DeviceType.FirefoxExtension]:
- "https://addons.mozilla.org/en-US/firefox/addon/bitwarden-password-manager/#reviews",
- [DeviceType.OperaExtension]:
- "https://addons.opera.com/en/extensions/details/bitwarden-free-password-manager/#feedback-container",
- [DeviceType.EdgeExtension]:
- "https://microsoftedge.microsoft.com/addons/detail/jbkfoedolllekgbhcbcoahefnbanhhlh",
- [DeviceType.VivaldiExtension]:
- "https://chromewebstore.google.com/detail/bitwarden-free-password-m/nngceckbapebfimnlniiiahkandclblb/reviews",
- [DeviceType.SafariExtension]: "https://apps.apple.com/app/bitwarden/id1352778147",
-};
-
@Component({
- selector: "app-settings",
- templateUrl: "settings.component.html",
+ selector: "auth-account-security",
+ templateUrl: "account-security.component.html",
})
// eslint-disable-next-line rxjs-angular/prefer-takeuntil
-export class SettingsComponent implements OnInit {
+export class AccountSecurityComponent implements OnInit {
protected readonly VaultTimeoutAction = VaultTimeoutAction;
availableVaultTimeoutActions: VaultTimeoutAction[] = [];
@@ -95,7 +78,6 @@ export class SettingsComponent implements OnInit {
private vaultTimeoutService: VaultTimeoutService,
private vaultTimeoutSettingsService: VaultTimeoutSettingsService,
public messagingService: MessagingService,
- private router: Router,
private environmentService: EnvironmentService,
private cryptoService: CryptoService,
private stateService: StateService,
@@ -425,23 +407,6 @@ export class SettingsComponent implements OnInit {
);
}
- async lock() {
- await this.vaultTimeoutService.lock();
- }
-
- async logOut() {
- const confirmed = await this.dialogService.openSimpleDialog({
- title: { key: "logOut" },
- content: { key: "logOutConfirmation" },
- type: "info",
- });
-
- const userId = (await firstValueFrom(this.accountService.activeAccount$))?.id;
- if (confirmed) {
- this.messagingService.send("logout", { userId: userId });
- }
- }
-
async changePassword() {
const confirmed = await this.dialogService.openSimpleDialog({
title: { key: "continueToWebApp" },
@@ -468,44 +433,6 @@ export class SettingsComponent implements OnInit {
}
}
- async share() {
- const confirmed = await this.dialogService.openSimpleDialog({
- title: { key: "learnOrg" },
- content: { key: "learnOrgConfirmation" },
- type: "info",
- });
- if (confirmed) {
- // 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
- BrowserApi.createNewTab("https://bitwarden.com/help/about-organizations/");
- }
- }
-
- async webVault() {
- const env = await firstValueFrom(this.environmentService.environment$);
- const url = env.getWebVaultUrl();
- await BrowserApi.createNewTab(url);
- }
-
- async import() {
- await this.router.navigate(["/import"]);
- if (await BrowserApi.isPopupOpen()) {
- // 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
- BrowserPopupUtils.openCurrentPagePopout(window);
- }
- }
-
- export() {
- // 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(["/export"]);
- }
-
- about() {
- this.dialogService.open(AboutComponent);
- }
-
async fingerprint() {
const fingerprint = await this.cryptoService.getFingerprint(
await this.stateService.getUserId(),
@@ -518,11 +445,21 @@ export class SettingsComponent implements OnInit {
return firstValueFrom(dialogRef.closed);
}
- rate() {
- const deviceType = this.platformUtilsService.getDevice();
- // 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
- BrowserApi.createNewTab((RateUrls as any)[deviceType]);
+ async lock() {
+ await this.vaultTimeoutService.lock();
+ }
+
+ async logOut() {
+ const confirmed = await this.dialogService.openSimpleDialog({
+ title: { key: "logOut" },
+ content: { key: "logOutConfirmation" },
+ type: "info",
+ });
+
+ const userId = (await firstValueFrom(this.accountService.activeAccount$))?.id;
+ if (confirmed) {
+ this.messagingService.send("logout", { userId: userId });
+ }
}
ngOnDestroy() {
diff --git a/apps/browser/src/popup/settings/await-desktop-dialog.component.html b/apps/browser/src/auth/popup/settings/await-desktop-dialog.component.html
similarity index 100%
rename from apps/browser/src/popup/settings/await-desktop-dialog.component.html
rename to apps/browser/src/auth/popup/settings/await-desktop-dialog.component.html
diff --git a/apps/browser/src/popup/settings/await-desktop-dialog.component.ts b/apps/browser/src/auth/popup/settings/await-desktop-dialog.component.ts
similarity index 100%
rename from apps/browser/src/popup/settings/await-desktop-dialog.component.ts
rename to apps/browser/src/auth/popup/settings/await-desktop-dialog.component.ts
diff --git a/apps/browser/src/popup/settings/vault-timeout-input.component.html b/apps/browser/src/auth/popup/settings/vault-timeout-input.component.html
similarity index 100%
rename from apps/browser/src/popup/settings/vault-timeout-input.component.html
rename to apps/browser/src/auth/popup/settings/vault-timeout-input.component.html
diff --git a/apps/browser/src/popup/settings/vault-timeout-input.component.ts b/apps/browser/src/auth/popup/settings/vault-timeout-input.component.ts
similarity index 100%
rename from apps/browser/src/popup/settings/vault-timeout-input.component.ts
rename to apps/browser/src/auth/popup/settings/vault-timeout-input.component.ts
diff --git a/apps/browser/src/popup/app-routing.animations.ts b/apps/browser/src/popup/app-routing.animations.ts
index 13403545fde..e37c640bf92 100644
--- a/apps/browser/src/popup/app-routing.animations.ts
+++ b/apps/browser/src/popup/app-routing.animations.ts
@@ -174,6 +174,9 @@ export const routerTransition = trigger("routerTransition", [
transition("clone-cipher => attachments, clone-cipher => collections", inSlideLeft),
transition("attachments => clone-cipher, collections => clone-cipher", outSlideRight),
+ transition("tabs => account-security", inSlideLeft),
+ transition("account-security => tabs", outSlideRight),
+
transition("tabs => import", inSlideLeft),
transition("import => tabs", outSlideRight),
diff --git a/apps/browser/src/popup/app-routing.module.ts b/apps/browser/src/popup/app-routing.module.ts
index 0dcf496457a..059e2e605da 100644
--- a/apps/browser/src/popup/app-routing.module.ts
+++ b/apps/browser/src/popup/app-routing.module.ts
@@ -21,6 +21,7 @@ import { LoginComponent } from "../auth/popup/login.component";
import { RegisterComponent } from "../auth/popup/register.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";
import { SsoComponent } from "../auth/popup/sso.component";
import { TwoFactorOptionsComponent } from "../auth/popup/two-factor-options.component";
import { TwoFactorComponent } from "../auth/popup/two-factor.component";
@@ -35,6 +36,7 @@ import { SendGroupingsComponent } from "../tools/popup/send/send-groupings.compo
import { SendTypeComponent } from "../tools/popup/send/send-type.component";
import { ExportComponent } from "../tools/popup/settings/export.component";
import { ImportBrowserComponent } from "../tools/popup/settings/import/import-browser.component";
+import { SettingsComponent } from "../tools/popup/settings/settings.component";
import { Fido2Component } from "../vault/popup/components/fido2/fido2.component";
import { AddEditComponent } from "../vault/popup/components/vault/add-edit.component";
import { AttachmentsComponent } from "../vault/popup/components/vault/attachments.component";
@@ -53,7 +55,6 @@ import { ExcludedDomainsComponent } from "./settings/excluded-domains.component"
import { FoldersComponent } from "./settings/folders.component";
import { HelpAndFeedbackComponent } from "./settings/help-and-feedback.component";
import { OptionsComponent } from "./settings/options.component";
-import { SettingsComponent } from "./settings/settings.component";
import { SyncComponent } from "./settings/sync.component";
import { TabsV2Component } from "./tabs-v2.component";
import { TabsComponent } from "./tabs.component";
@@ -246,6 +247,12 @@ const routes: Routes = [
canActivate: [AuthGuard],
data: { state: "autofill" },
},
+ {
+ path: "account-security",
+ component: AccountSecurityComponent,
+ canActivate: [AuthGuard],
+ data: { state: "account-security" },
+ },
{
path: "folders",
component: FoldersComponent,
diff --git a/apps/browser/src/popup/app.module.ts b/apps/browser/src/popup/app.module.ts
index bed40dfddc9..40cdd297548 100644
--- a/apps/browser/src/popup/app.module.ts
+++ b/apps/browser/src/popup/app.module.ts
@@ -30,6 +30,8 @@ import { LoginComponent } from "../auth/popup/login.component";
import { RegisterComponent } from "../auth/popup/register.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";
+import { VaultTimeoutInputComponent } from "../auth/popup/settings/vault-timeout-input.component";
import { SsoComponent } from "../auth/popup/sso.component";
import { TwoFactorOptionsComponent } from "../auth/popup/two-factor-options.component";
import { TwoFactorComponent } from "../auth/popup/two-factor.component";
@@ -49,6 +51,7 @@ import { SendAddEditComponent } from "../tools/popup/send/send-add-edit.componen
import { SendGroupingsComponent } from "../tools/popup/send/send-groupings.component";
import { SendTypeComponent } from "../tools/popup/send/send-type.component";
import { ExportComponent } from "../tools/popup/settings/export.component";
+import { SettingsComponent } from "../tools/popup/settings/settings.component";
import { ActionButtonsComponent } from "../vault/popup/components/action-buttons.component";
import { CipherRowComponent } from "../vault/popup/components/cipher-row.component";
import { Fido2CipherRowComponent } from "../vault/popup/components/fido2/fido2-cipher-row.component";
@@ -77,9 +80,7 @@ import { ExcludedDomainsComponent } from "./settings/excluded-domains.component"
import { FoldersComponent } from "./settings/folders.component";
import { HelpAndFeedbackComponent } from "./settings/help-and-feedback.component";
import { OptionsComponent } from "./settings/options.component";
-import { SettingsComponent } from "./settings/settings.component";
import { SyncComponent } from "./settings/sync.component";
-import { VaultTimeoutInputComponent } from "./settings/vault-timeout-input.component";
import { TabsV2Component } from "./tabs-v2.component";
import { TabsComponent } from "./tabs.component";
@@ -156,6 +157,7 @@ import "../platform/popup/locales";
SendListComponent,
SendTypeComponent,
SetPasswordComponent,
+ AccountSecurityComponent,
SettingsComponent,
ShareComponent,
SsoComponent,
diff --git a/apps/browser/src/popup/settings/about.component.html b/apps/browser/src/tools/popup/settings/about/about.component.html
similarity index 100%
rename from apps/browser/src/popup/settings/about.component.html
rename to apps/browser/src/tools/popup/settings/about/about.component.html
diff --git a/apps/browser/src/popup/settings/about.component.ts b/apps/browser/src/tools/popup/settings/about/about.component.ts
similarity index 100%
rename from apps/browser/src/popup/settings/about.component.ts
rename to apps/browser/src/tools/popup/settings/about/about.component.ts
diff --git a/apps/browser/src/popup/settings/settings.component.html b/apps/browser/src/tools/popup/settings/settings.component.html
similarity index 55%
rename from apps/browser/src/popup/settings/settings.component.html
rename to apps/browser/src/tools/popup/settings/settings.component.html
index 98c218b0db0..0b7773019bc 100644
--- a/apps/browser/src/popup/settings/settings.component.html
+++ b/apps/browser/src/tools/popup/settings/settings.component.html
@@ -7,10 +7,18 @@
-
+
+
-
-
-
-
-
- {{
- "vaultTimeoutPolicyWithActionInEffect"
- | i18n: policy.timeout.hours : policy.timeout.minutes : (policy.action | i18n)
- }}
-
-
- {{ "vaultTimeoutPolicyInEffect" | i18n: policy.timeout.hours : policy.timeout.minutes }}
-
-
- {{ "vaultTimeoutActionPolicyInEffect" | i18n: (policy.action | i18n) }}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
@@ -145,35 +67,6 @@
-
-
-
diff --git a/apps/browser/src/tools/popup/settings/settings.component.ts b/apps/browser/src/tools/popup/settings/settings.component.ts
new file mode 100644
index 00000000000..81727c442cd
--- /dev/null
+++ b/apps/browser/src/tools/popup/settings/settings.component.ts
@@ -0,0 +1,101 @@
+import { Component, OnInit } from "@angular/core";
+import { Router } from "@angular/router";
+import { firstValueFrom, Subject } from "rxjs";
+
+import { VaultTimeoutService } from "@bitwarden/common/abstractions/vault-timeout/vault-timeout.service";
+import { DeviceType } from "@bitwarden/common/enums";
+import { EnvironmentService } from "@bitwarden/common/platform/abstractions/environment.service";
+import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
+import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service";
+import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
+import { DialogService } from "@bitwarden/components";
+
+import { BrowserApi } from "../../../platform/browser/browser-api";
+import BrowserPopupUtils from "../../../platform/popup/browser-popup-utils";
+
+import { AboutComponent } from "./about/about.component";
+
+const RateUrls = {
+ [DeviceType.ChromeExtension]:
+ "https://chromewebstore.google.com/detail/bitwarden-free-password-m/nngceckbapebfimnlniiiahkandclblb/reviews",
+ [DeviceType.FirefoxExtension]:
+ "https://addons.mozilla.org/en-US/firefox/addon/bitwarden-password-manager/#reviews",
+ [DeviceType.OperaExtension]:
+ "https://addons.opera.com/en/extensions/details/bitwarden-free-password-manager/#feedback-container",
+ [DeviceType.EdgeExtension]:
+ "https://microsoftedge.microsoft.com/addons/detail/jbkfoedolllekgbhcbcoahefnbanhhlh",
+ [DeviceType.VivaldiExtension]:
+ "https://chromewebstore.google.com/detail/bitwarden-free-password-m/nngceckbapebfimnlniiiahkandclblb/reviews",
+ [DeviceType.SafariExtension]: "https://apps.apple.com/app/bitwarden/id1352778147",
+};
+
+@Component({
+ selector: "tools-settings",
+ templateUrl: "settings.component.html",
+})
+// eslint-disable-next-line rxjs-angular/prefer-takeuntil
+export class SettingsComponent implements OnInit {
+ private destroy$ = new Subject();
+
+ constructor(
+ private platformUtilsService: PlatformUtilsService,
+ private i18nService: I18nService,
+ private vaultTimeoutService: VaultTimeoutService,
+ public messagingService: MessagingService,
+ private router: Router,
+ private environmentService: EnvironmentService,
+ private dialogService: DialogService,
+ ) {}
+
+ async ngOnInit() {}
+
+ async share() {
+ const confirmed = await this.dialogService.openSimpleDialog({
+ title: { key: "learnOrg" },
+ content: { key: "learnOrgConfirmation" },
+ type: "info",
+ });
+ if (confirmed) {
+ // 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
+ BrowserApi.createNewTab("https://bitwarden.com/help/about-organizations/");
+ }
+ }
+
+ async webVault() {
+ const env = await firstValueFrom(this.environmentService.environment$);
+ const url = env.getWebVaultUrl();
+ await BrowserApi.createNewTab(url);
+ }
+
+ async import() {
+ await this.router.navigate(["/import"]);
+ if (await BrowserApi.isPopupOpen()) {
+ // 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
+ BrowserPopupUtils.openCurrentPagePopout(window);
+ }
+ }
+
+ export() {
+ // 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(["/export"]);
+ }
+
+ about() {
+ this.dialogService.open(AboutComponent);
+ }
+
+ rate() {
+ const deviceType = this.platformUtilsService.getDevice();
+ // 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
+ BrowserApi.createNewTab((RateUrls as any)[deviceType]);
+ }
+
+ ngOnDestroy() {
+ this.destroy$.next();
+ this.destroy$.complete();
+ }
+}