From 4c971c70c01de3bdab4ea0906abb7112461cc6a2 Mon Sep 17 00:00:00 2001 From: Bryan Cunningham Date: Thu, 11 Dec 2025 13:56:13 -0500 Subject: [PATCH 01/19] [CL-927] anon layout header actions slot (#17796) * add a slot for consumers to show user actions in anon layout header * remove commented code * ensure logo stays top aligned * switch to dashed naming * fix ngif statements * remove empty selector * remove unnecessary containers * use smaller logo on smaller screens * remove commented code from extension layout * remove dupe slot * only take extension screenshots on small screens * take screenshot at 380 * take large and small screenshot * update story to use new control flow --- ...tension-anon-layout-wrapper.component.html | 24 +++------ .../extension-anon-layout-wrapper.stories.ts | 5 ++ .../anon-layout-wrapper.component.html | 1 + .../anon-layout-wrapper.stories.ts | 14 +++++ .../anon-layout/anon-layout.component.html | 54 +++++++++++-------- .../src/anon-layout/anon-layout.stories.ts | 21 +++++++- 6 files changed, 78 insertions(+), 41 deletions(-) diff --git a/apps/browser/src/popup/components/extension-anon-layout-wrapper/extension-anon-layout-wrapper.component.html b/apps/browser/src/popup/components/extension-anon-layout-wrapper/extension-anon-layout-wrapper.component.html index dcd0496ed30..7a1815b86ed 100644 --- a/apps/browser/src/popup/components/extension-anon-layout-wrapper/extension-anon-layout-wrapper.component.html +++ b/apps/browser/src/popup/components/extension-anon-layout-wrapper/extension-anon-layout-wrapper.component.html @@ -1,31 +1,21 @@ - -
- -
- - - - - -
- +
+ + @if (showAcctSwitcher && hasLoggedInAccount) { + + } +
diff --git a/apps/browser/src/popup/components/extension-anon-layout-wrapper/extension-anon-layout-wrapper.stories.ts b/apps/browser/src/popup/components/extension-anon-layout-wrapper/extension-anon-layout-wrapper.stories.ts index 7a30e15582c..57ef285bdf5 100644 --- a/apps/browser/src/popup/components/extension-anon-layout-wrapper/extension-anon-layout-wrapper.stories.ts +++ b/apps/browser/src/popup/components/extension-anon-layout-wrapper/extension-anon-layout-wrapper.stories.ts @@ -238,6 +238,11 @@ export const DefaultContentExample: Story = { }, ], }), + parameters: { + chromatic: { + viewports: [380, 1280], + }, + }, }; // Dynamic Content Example diff --git a/libs/components/src/anon-layout/anon-layout-wrapper.component.html b/libs/components/src/anon-layout/anon-layout-wrapper.component.html index 73a3d34261b..1079329448b 100644 --- a/libs/components/src/anon-layout/anon-layout-wrapper.component.html +++ b/libs/components/src/anon-layout/anon-layout-wrapper.component.html @@ -7,6 +7,7 @@ [hideCardWrapper]="hideCardWrapper" [hideBackgroundIllustration]="hideBackgroundIllustration" > + diff --git a/libs/components/src/anon-layout/anon-layout-wrapper.stories.ts b/libs/components/src/anon-layout/anon-layout-wrapper.stories.ts index 76fcc8976c7..63181e04649 100644 --- a/libs/components/src/anon-layout/anon-layout-wrapper.stories.ts +++ b/libs/components/src/anon-layout/anon-layout-wrapper.stories.ts @@ -130,6 +130,15 @@ export class DefaultSecondaryOutletExampleComponent {} }) export class DefaultEnvSelectorOutletExampleComponent {} +// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush +// eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection +@Component({ + selector: "bit-header-actions-outlet-example-component", + template: "

Header Actions Outlet Example:
your header actions component goes here

", + standalone: false, +}) +export class DefaultHeaderActionsOutletExampleComponent {} + export const DefaultContentExample: Story = { render: (args) => ({ props: args, @@ -171,6 +180,11 @@ export const DefaultContentExample: Story = { component: DefaultEnvSelectorOutletExampleComponent, outlet: "environment-selector", }, + { + path: "", + component: DefaultHeaderActionsOutletExampleComponent, + outlet: "header-actions", + }, ], }, ], diff --git a/libs/components/src/anon-layout/anon-layout.component.html b/libs/components/src/anon-layout/anon-layout.component.html index 15f7d107542..edb73bbf588 100644 --- a/libs/components/src/anon-layout/anon-layout.component.html +++ b/libs/components/src/anon-layout/anon-layout.component.html @@ -5,13 +5,19 @@ 'tw-min-h-full': clientType === 'browser' || clientType === 'desktop', }" > - - - +
+ @if (!hideLogo()) { + + + + } +
+ +
+
@let iconInput = icon(); @@ -25,7 +31,7 @@
- + @if (title()) {

{{ title() }} @@ -34,9 +40,11 @@

{{ title() }}

-
+ } -
{{ subtitle() }}
+ @if (subtitle()) { +
{{ subtitle() }}
+ }
-
-
- {{ "accessing" | i18n }} {{ hostname }} -
- - - - -
© {{ year }} Bitwarden Inc.
-
{{ version }}
-
-
+ @if (!hideFooter()) { +
+ @if (showReadonlyHostname()) { +
{{ "accessing" | i18n }} {{ hostname }}
+ } @else { + + } + + @if (!hideYearAndVersion) { +
© {{ year }} Bitwarden Inc.
+
{{ version }}
+ } +
+ } @if (!hideBackgroundIllustration()) {
+ @if (includeHeaderActions) { +
+ +
+ }
Thin Content
@@ -116,7 +126,7 @@ export default { hideLogo: { control: "boolean" }, hideFooter: { control: "boolean" }, hideBackgroundIllustration: { control: "boolean" }, - + includeHeaderActions: { control: "boolean" }, contentLength: { control: "radio", options: ["normal", "long", "thin"], @@ -138,6 +148,7 @@ export default { hideBackgroundIllustration: false, contentLength: "normal", showSecondary: false, + includeHeaderActions: false, }, } satisfies Meta; @@ -188,6 +199,12 @@ export const SecondaryContent: Story = { }, }; +export const WithHeaderActions: Story = { + args: { + includeHeaderActions: true, + }, +}; + export const NoTitle: Story = { args: { title: undefined } }; export const NoSubtitle: Story = { args: { subtitle: undefined } }; From 22e9c6a72f948b9a26b70c4caa9bc636d6a67e43 Mon Sep 17 00:00:00 2001 From: neuronull <9162534+neuronull@users.noreply.github.com> Date: Thu, 11 Dec 2025 12:44:51 -0700 Subject: [PATCH 02/19] Re-apply desktop native debug log level debug builds and fix build workflow (#17908) * Reapply "Desktop Native compile debug builds with debug log level (#17357)" (#17815) This reverts commit 5386b58f2329eaed2acb9178560eeca9a265bb16. * Use release mode if workflow called from upstream * fix bug in build script * revert napi build command to not use --release * forward caller's args to napi * js things * shell thangs * use platform agnostic expansion * Revert "use platform agnostic expansion" This reverts commit 5ee629f822a5bccbc68817bc9b3e846eb85b1639. * powershell expansion --- .github/workflows/build-desktop.yml | 20 ++++++++++++----- apps/desktop/desktop_native/build.js | 6 ++--- apps/desktop/desktop_native/napi/package.json | 2 +- .../desktop_native/napi/scripts/build.js | 22 +++++++++++++++++++ apps/desktop/desktop_native/napi/src/lib.rs | 14 +++++++++--- 5 files changed, 52 insertions(+), 12 deletions(-) create mode 100644 apps/desktop/desktop_native/napi/scripts/build.js diff --git a/.github/workflows/build-desktop.yml b/.github/workflows/build-desktop.yml index 6978edd8b3c..efb94e44c7a 100644 --- a/.github/workflows/build-desktop.yml +++ b/.github/workflows/build-desktop.yml @@ -583,7 +583,9 @@ jobs: - name: Build Native Module if: steps.cache.outputs.cache-hit != 'true' working-directory: apps/desktop/desktop_native - run: node build.js cross-platform + env: + MODE: ${{ github.event_name == 'workflow_call' && '--release' || '' }} + run: node build.js cross-platform "$env:MODE" - name: Build run: npm run build @@ -846,7 +848,9 @@ jobs: - name: Build Native Module if: steps.cache.outputs.cache-hit != 'true' working-directory: apps/desktop/desktop_native - run: node build.js cross-platform + env: + MODE: ${{ github.event_name == 'workflow_call' && '--release' || '' }} + run: node build.js cross-platform "$env:MODE" - name: Build run: npm run build @@ -1202,7 +1206,9 @@ jobs: - name: Build Native Module if: steps.cache.outputs.cache-hit != 'true' working-directory: apps/desktop/desktop_native - run: node build.js cross-platform + env: + MODE: ${{ github.event_name == 'workflow_call' && '--release' || '' }} + run: node build.js cross-platform "$MODE" - name: Build application (dev) run: npm run build @@ -1424,7 +1430,9 @@ jobs: - name: Build Native Module if: steps.cache.outputs.cache-hit != 'true' working-directory: apps/desktop/desktop_native - run: node build.js cross-platform + env: + MODE: ${{ github.event_name == 'workflow_call' && '--release' || '' }} + run: node build.js cross-platform "$MODE" - name: Build if: steps.build-cache.outputs.cache-hit != 'true' @@ -1705,7 +1713,9 @@ jobs: - name: Build Native Module if: steps.cache.outputs.cache-hit != 'true' working-directory: apps/desktop/desktop_native - run: node build.js cross-platform + env: + MODE: ${{ github.event_name == 'workflow_call' && '--release' || '' }} + run: node build.js cross-platform "$MODE" - name: Build if: steps.build-cache.outputs.cache-hit != 'true' diff --git a/apps/desktop/desktop_native/build.js b/apps/desktop/desktop_native/build.js index e267e28a08c..54a6dba8326 100644 --- a/apps/desktop/desktop_native/build.js +++ b/apps/desktop/desktop_native/build.js @@ -113,8 +113,8 @@ if (process.platform === "linux") { platformTargets.forEach(([target, _]) => { installTarget(target); - buildNapiModule(target); - buildProxyBin(target); - buildImporterBinaries(target); + buildNapiModule(target, mode === "release"); + buildProxyBin(target, mode === "release"); + buildImporterBinaries(target, mode === "release"); buildProcessIsolation(); }); diff --git a/apps/desktop/desktop_native/napi/package.json b/apps/desktop/desktop_native/napi/package.json index 5401207c252..0717bfd53ea 100644 --- a/apps/desktop/desktop_native/napi/package.json +++ b/apps/desktop/desktop_native/napi/package.json @@ -3,7 +3,7 @@ "version": "0.1.0", "description": "", "scripts": { - "build": "napi build --platform --no-js", + "build": "node scripts/build.js", "test": "cargo test" }, "author": "", diff --git a/apps/desktop/desktop_native/napi/scripts/build.js b/apps/desktop/desktop_native/napi/scripts/build.js new file mode 100644 index 00000000000..ad24b99d2fb --- /dev/null +++ b/apps/desktop/desktop_native/napi/scripts/build.js @@ -0,0 +1,22 @@ +/* eslint-disable @typescript-eslint/no-var-requires */ +const { execSync } = require('child_process'); + +const args = process.argv.slice(2); + +const isRelease = args.includes('--release'); + +const argsString = args.join(' '); + +if (isRelease) { + console.log('Building release mode.'); + + execSync(`napi build --platform --no-js ${argsString}`, { stdio: 'inherit'}); + +} else { + console.log('Building debug mode.'); + + execSync(`napi build --platform --no-js ${argsString}`, { + stdio: 'inherit', + env: { ...process.env, RUST_LOG: 'debug' } + }); +} diff --git a/apps/desktop/desktop_native/napi/src/lib.rs b/apps/desktop/desktop_native/napi/src/lib.rs index 25dfdd08336..fe084349501 100644 --- a/apps/desktop/desktop_native/napi/src/lib.rs +++ b/apps/desktop/desktop_native/napi/src/lib.rs @@ -994,7 +994,7 @@ pub mod logging { }; use tracing::Level; use tracing_subscriber::{ - filter::{EnvFilter, LevelFilter}, + filter::EnvFilter, fmt::format::{DefaultVisitor, Writer}, layer::SubscriberExt, util::SubscriberInitExt, @@ -1082,9 +1082,17 @@ pub mod logging { pub fn init_napi_log(js_log_fn: ThreadsafeFunction>) { let _ = JS_LOGGER.0.set(js_log_fn); + // the log level hierarchy is determined by: + // - if RUST_LOG is detected at runtime + // - if RUST_LOG is provided at compile time + // - default to INFO let filter = EnvFilter::builder() - // set the default log level to INFO. - .with_default_directive(LevelFilter::INFO.into()) + .with_default_directive( + option_env!("RUST_LOG") + .unwrap_or("info") + .parse() + .expect("should provide valid log level at compile time."), + ) // parse directives from the RUST_LOG environment variable, // overriding the default directive for matching targets. .from_env_lossy(); From 4576a52fd186e4a11c24edde1a6ee99f7d3d9b09 Mon Sep 17 00:00:00 2001 From: Dave <3836813+enmande@users.noreply.github.com> Date: Thu, 11 Dec 2025 15:03:10 -0500 Subject: [PATCH 03/19] fix(token-service) [PM-15333]: Portable App Is Not Portable (#17781) * feat(token-service) [PM-15333]: Update Portable secure storage resolution to use disk. * feat(token-service) [PM-15333]: Move isWindowsPortable evaluation to preload with other platform evaluations. --- apps/desktop/src/app/services/services.module.ts | 10 +++++++++- apps/desktop/src/platform/preload.ts | 2 ++ libs/common/src/auth/services/token.service.ts | 14 +++++++++++--- 3 files changed, 22 insertions(+), 4 deletions(-) diff --git a/apps/desktop/src/app/services/services.module.ts b/apps/desktop/src/app/services/services.module.ts index e4dd144fa20..59021a556e4 100644 --- a/apps/desktop/src/app/services/services.module.ts +++ b/apps/desktop/src/app/services/services.module.ts @@ -203,8 +203,16 @@ const safeProviders: SafeProvider[] = [ // We manually override the value of SUPPORTS_SECURE_STORAGE here to avoid // the TokenService having to inject the PlatformUtilsService which introduces a // circular dependency on Desktop only. + // + // For Windows portable builds, we disable secure storage to ensure tokens are + // stored on disk (in bitwarden-appdata) rather than in Windows Credential + // Manager, making them portable across machines. This allows users to move the USB drive + // between computers while maintaining authentication. + // + // Note: Portable mode does not use secure storage for read/write/clear operations, + // preventing any collision with tokens from a regular desktop installation. provide: SUPPORTS_SECURE_STORAGE, - useValue: ELECTRON_SUPPORTS_SECURE_STORAGE, + useValue: ELECTRON_SUPPORTS_SECURE_STORAGE && !ipc.platform.isWindowsPortable, }), safeProvider({ provide: DEFAULT_VAULT_TIMEOUT, diff --git a/apps/desktop/src/platform/preload.ts b/apps/desktop/src/platform/preload.ts index a45ac753b3f..5f643242a9c 100644 --- a/apps/desktop/src/platform/preload.ts +++ b/apps/desktop/src/platform/preload.ts @@ -17,6 +17,7 @@ import { isFlatpak, isMacAppStore, isSnapStore, + isWindowsPortable, isWindowsStore, } from "../utils"; @@ -133,6 +134,7 @@ export default { isDev: isDev(), isMacAppStore: isMacAppStore(), isWindowsStore: isWindowsStore(), + isWindowsPortable: isWindowsPortable(), isFlatpak: isFlatpak(), isSnapStore: isSnapStore(), isAppImage: isAppImage(), diff --git a/libs/common/src/auth/services/token.service.ts b/libs/common/src/auth/services/token.service.ts index c02bc85f124..ce272705341 100644 --- a/libs/common/src/auth/services/token.service.ts +++ b/libs/common/src/auth/services/token.service.ts @@ -445,13 +445,15 @@ export class TokenService implements TokenServiceAbstraction { // we can't determine storage location w/out vaultTimeoutAction and vaultTimeout // but we can simply clear all locations to avoid the need to require those parameters. + // When secure storage is supported, clear the encryption key from secure storage. + // When not supported (e.g., portable builds), tokens are stored on disk and this step is skipped. if (this.platformSupportsSecureStorage) { - // Always clear the access token key when clearing the access token - // The next set of the access token will create a new access token key + // Always clear the access token key when clearing the access token. + // The next set of the access token will create a new access token key. await this.clearAccessTokenKey(userId); } - // Platform doesn't support secure storage, so use state provider implementation + // Clear tokens from disk storage (all platforms) await this.singleUserStateProvider.get(userId, ACCESS_TOKEN_DISK).update((_) => null, { shouldUpdate: (previousValue) => previousValue !== null, }); @@ -478,6 +480,9 @@ export class TokenService implements TokenServiceAbstraction { return null; } + // When platformSupportsSecureStorage=true, tokens on disk are encrypted and require + // decryption keys from secure storage. When false (e.g., portable builds), tokens are + // stored on disk. if (this.platformSupportsSecureStorage) { let accessTokenKey: AccessTokenKey; try { @@ -1118,6 +1123,9 @@ export class TokenService implements TokenServiceAbstraction { ) { return TokenStorageLocation.Memory; } else { + // Secure storage (e.g., OS credential manager) is preferred when available. + // Desktop portable builds set platformSupportsSecureStorage=false to store tokens + // on disk for portability across machines. if (useSecureStorage && this.platformSupportsSecureStorage) { return TokenStorageLocation.SecureStorage; } From 7c0337c12dc693e22cc3023961fccced6ec97fc9 Mon Sep 17 00:00:00 2001 From: Andy Pixley <3723676+pixman20@users.noreply.github.com> Date: Thu, 11 Dec 2025 16:14:57 -0500 Subject: [PATCH 04/19] [BRE-1391] Fixing desktop tar.gz to include version (#17933) --- .github/workflows/release-desktop.yml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/.github/workflows/release-desktop.yml b/.github/workflows/release-desktop.yml index 7f87a1e5628..2239cb1268f 100644 --- a/.github/workflows/release-desktop.yml +++ b/.github/workflows/release-desktop.yml @@ -98,6 +98,14 @@ jobs: working-directory: apps/desktop/artifacts run: mv "Bitwarden-${PKG_VERSION}-universal.pkg" "Bitwarden-${PKG_VERSION}-universal.pkg.archive" + - name: Rename .tar.gz to include version + env: + PKG_VERSION: ${{ steps.version.outputs.version }} + working-directory: apps/desktop/artifacts + run: | + mv "bitwarden_desktop_x64.tar.gz" "bitwarden_${PKG_VERSION}_x64.tar.gz" + mv "bitwarden_desktop_arm64.tar.gz" "bitwarden_${PKG_VERSION}_arm64.tar.gz" + - name: Create Release uses: ncipollo/release-action@b7eabc95ff50cbeeedec83973935c8f306dfcd0b # v1.20.0 if: ${{ steps.release_channel.outputs.channel == 'latest' && github.event.inputs.release_type != 'Dry Run' }} From 9f1496b21834d40025c1f5eb64ca637798ba1ba8 Mon Sep 17 00:00:00 2001 From: Github Actions Date: Thu, 11 Dec 2025 21:25:36 +0000 Subject: [PATCH 05/19] Bumped Desktop client to 2025.12.1 --- apps/desktop/package.json | 2 +- apps/desktop/src/package-lock.json | 4 ++-- apps/desktop/src/package.json | 2 +- package-lock.json | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/apps/desktop/package.json b/apps/desktop/package.json index 5e85d34cebc..97ab8585a69 100644 --- a/apps/desktop/package.json +++ b/apps/desktop/package.json @@ -1,7 +1,7 @@ { "name": "@bitwarden/desktop", "description": "A secure and free password manager for all of your devices.", - "version": "2025.12.0", + "version": "2025.12.1", "keywords": [ "bitwarden", "password", diff --git a/apps/desktop/src/package-lock.json b/apps/desktop/src/package-lock.json index 44fdb5c23b0..9d8eae15791 100644 --- a/apps/desktop/src/package-lock.json +++ b/apps/desktop/src/package-lock.json @@ -1,12 +1,12 @@ { "name": "@bitwarden/desktop", - "version": "2025.12.0", + "version": "2025.12.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@bitwarden/desktop", - "version": "2025.12.0", + "version": "2025.12.1", "license": "GPL-3.0", "dependencies": { "@bitwarden/desktop-napi": "file:../desktop_native/napi" diff --git a/apps/desktop/src/package.json b/apps/desktop/src/package.json index 4c396304f4a..2ac5d339a95 100644 --- a/apps/desktop/src/package.json +++ b/apps/desktop/src/package.json @@ -2,7 +2,7 @@ "name": "@bitwarden/desktop", "productName": "Bitwarden", "description": "A secure and free password manager for all of your devices.", - "version": "2025.12.0", + "version": "2025.12.1", "author": "Bitwarden Inc. (https://bitwarden.com)", "homepage": "https://bitwarden.com", "license": "GPL-3.0", diff --git a/package-lock.json b/package-lock.json index dc8694f77b6..3a600667ff7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -278,7 +278,7 @@ }, "apps/desktop": { "name": "@bitwarden/desktop", - "version": "2025.12.0", + "version": "2025.12.1", "hasInstallScript": true, "license": "GPL-3.0" }, From d77930428564e98a1b3809c6e64990682bdc6d6e Mon Sep 17 00:00:00 2001 From: Jordan Aasen <166539328+jaasen-livefront@users.noreply.github.com> Date: Thu, 11 Dec 2025 15:45:32 -0800 Subject: [PATCH 06/19] [PM-25388] - remove reference to android/ios icons (#17763) * remove android/ios icons as they're not in the icon lib * fix tests --- .../src/vault/icon/build-cipher-icon.spec.ts | 43 ++++++++++--------- .../src/vault/icon/build-cipher-icon.ts | 6 ++- 2 files changed, 26 insertions(+), 23 deletions(-) diff --git a/libs/common/src/vault/icon/build-cipher-icon.spec.ts b/libs/common/src/vault/icon/build-cipher-icon.spec.ts index 90ccaaec3a6..67a1151aa8e 100644 --- a/libs/common/src/vault/icon/build-cipher-icon.spec.ts +++ b/libs/common/src/vault/icon/build-cipher-icon.spec.ts @@ -13,18 +13,19 @@ describe("buildCipherIcon", () => { }, } as any as CipherView; - it.each([true, false])("handles android app URIs for showFavicon setting %s", (showFavicon) => { - setUri("androidapp://test.example"); + // @TODO Uncomment once we have Android and iOS icons https://bitwarden.atlassian.net/browse/PM-29028 + // it.each([true, false])("handles android app URIs for showFavicon setting %s", (showFavicon) => { + // setUri("androidapp://test.example"); - const iconDetails = buildCipherIcon(iconServerUrl, cipher, showFavicon); + // const iconDetails = buildCipherIcon(iconServerUrl, cipher, showFavicon); - expect(iconDetails).toEqual({ - icon: "bwi-android", - image: null, - fallbackImage: "", - imageEnabled: showFavicon, - }); - }); + // expect(iconDetails).toEqual({ + // icon: "bwi-android", + // image: null, + // fallbackImage: "", + // imageEnabled: showFavicon, + // }); + // }); it("does not mark as an android app if the protocol is not androidapp", () => { // This weird URI points to test.androidapp with a default port and path of /.example @@ -40,18 +41,18 @@ describe("buildCipherIcon", () => { }); }); - it.each([true, false])("handles ios app URIs for showFavicon setting %s", (showFavicon) => { - setUri("iosapp://test.example"); + // @TODO Uncomment once we have Android and iOS icons https://bitwarden.atlassian.net/browse/PM-29028 + // it.each([true, false])("handles ios app URIs for showFavicon setting %s", (showFavicon) => { + // setUri("iosapp://test.example"); - const iconDetails = buildCipherIcon(iconServerUrl, cipher, showFavicon); - - expect(iconDetails).toEqual({ - icon: "bwi-apple", - image: null, - fallbackImage: "", - imageEnabled: showFavicon, - }); - }); + // const iconDetails = buildCipherIcon(iconServerUrl, cipher, showFavicon); + // expect(iconDetails).toEqual({ + // icon: "bwi-apple", + // image: null, + // fallbackImage: "", + // imageEnabled: showFavicon, + // }); + // }); it("does not mark as an ios app if the protocol is not iosapp", () => { // This weird URI points to test.iosapp with a default port and path of /.example diff --git a/libs/common/src/vault/icon/build-cipher-icon.ts b/libs/common/src/vault/icon/build-cipher-icon.ts index a081511d792..77787874d8e 100644 --- a/libs/common/src/vault/icon/build-cipher-icon.ts +++ b/libs/common/src/vault/icon/build-cipher-icon.ts @@ -49,10 +49,12 @@ export function buildCipherIcon( let isWebsite = false; if (hostnameUri.indexOf("androidapp://") === 0) { - icon = "bwi-android"; + // @TODO Re-add once we have Android icon https://bitwarden.atlassian.net/browse/PM-29028 + // icon = "bwi-android"; image = null; } else if (hostnameUri.indexOf("iosapp://") === 0) { - icon = "bwi-apple"; + // @TODO Re-add once we have iOS icon https://bitwarden.atlassian.net/browse/PM-29028 + // icon = "bwi-apple"; image = null; } else if ( showFavicon && From 2c4034ec7ce54c6da8537eb05534317ac5ba33bb Mon Sep 17 00:00:00 2001 From: Jordan Aasen <166539328+jaasen-livefront@users.noreply.github.com> Date: Thu, 11 Dec 2025 15:47:26 -0800 Subject: [PATCH 07/19] update popup router cache when navigating after file upload (#17694) --- .../platform/popup/view-cache/popup-router-cache.service.ts | 4 ++-- .../vault-v2/attachments/attachments-v2.component.ts | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/browser/src/platform/popup/view-cache/popup-router-cache.service.ts b/apps/browser/src/platform/popup/view-cache/popup-router-cache.service.ts index abb7c6405c2..6e5218c9f27 100644 --- a/apps/browser/src/platform/popup/view-cache/popup-router-cache.service.ts +++ b/apps/browser/src/platform/popup/view-cache/popup-router-cache.service.ts @@ -120,8 +120,8 @@ export class PopupRouterCacheService { /** * Navigate back in history */ - async back() { - if (!BrowserPopupUtils.inPopup(window)) { + async back(updateCache = false) { + if (!updateCache && !BrowserPopupUtils.inPopup(window)) { this.location.back(); return; } diff --git a/apps/browser/src/vault/popup/components/vault-v2/attachments/attachments-v2.component.ts b/apps/browser/src/vault/popup/components/vault-v2/attachments/attachments-v2.component.ts index 295496c701f..29282d293de 100644 --- a/apps/browser/src/vault/popup/components/vault-v2/attachments/attachments-v2.component.ts +++ b/apps/browser/src/vault/popup/components/vault-v2/attachments/attachments-v2.component.ts @@ -51,6 +51,6 @@ export class AttachmentsV2Component { /** Navigate the user back to the edit screen after uploading an attachment */ async navigateBack() { - await this.popupRouterCacheService.back(); + await this.popupRouterCacheService.back(true); } } From 81350d98df070655e395acce37d1137d60aa9e3d Mon Sep 17 00:00:00 2001 From: Jordan Aasen <166539328+jaasen-livefront@users.noreply.github.com> Date: Thu, 11 Dec 2025 15:48:43 -0800 Subject: [PATCH 08/19] fix alignment in hidden/pw fields (#17877) --- libs/components/src/form-field/form-field.component.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/components/src/form-field/form-field.component.html b/libs/components/src/form-field/form-field.component.html index a4af25a2492..1ead9f82273 100644 --- a/libs/components/src/form-field/form-field.component.html +++ b/libs/components/src/form-field/form-field.component.html @@ -83,7 +83,7 @@
Date: Fri, 12 Dec 2025 10:03:31 -0500 Subject: [PATCH 10/19] feat(accounts): Add creationDate of account to AccountInfo * Add creationDate of account to AccountInfo * Added initialization of creationDate. * Removed extra changes. * Fixed tests to initialize creation date * Added helper method to abstract account initialization in tests. * More test updates. * Linting * Additional test fixes. * Fixed spec reference * Fixed imports * Linting. * Fixed browser test. * Modified tsconfig to reference spec file. * Fixed import. * Removed dependency on os. This is necessary so that the @bitwarden/common/spec lib package can be referenced in tests without node. * Revert "Removed dependency on os. This is necessary so that the @bitwarden/common/spec lib package can be referenced in tests without node." This reverts commit 669f6557b6561f65ff513c14c2b3e8a55bef4035. * Updated stories to hard-code new field. * Removed changes to tsconfig * Revert "Removed changes to tsconfig" This reverts commit b7d916e8dc70be453f7092138416ce2e3c09ed57. --- .../services/account-switcher.service.spec.ts | 16 ++-- .../notification.background.spec.ts | 12 +-- .../browser/main-context-menu-handler.spec.ts | 8 +- .../extension-anon-layout-wrapper.stories.ts | 3 + .../popup/send-v2/send-v2.component.spec.ts | 8 +- .../open-attachments.component.spec.ts | 8 +- .../commands/unlock.command.spec.ts | 8 +- .../fido2-create.component.spec.ts | 8 +- .../desktop-autotype-policy.service.spec.ts | 8 +- .../biometric-message-handler.service.spec.ts | 16 ++-- .../unified-upgrade-dialog.component.spec.ts | 8 +- .../upgrade-nav-button.component.spec.ts | 8 +- .../services/upgrade-payment.service.spec.ts | 45 ++++++----- .../pages/breach-report.component.spec.ts | 8 +- .../user-key-rotation.service.spec.ts | 8 +- .../navigation-switcher.stories.ts | 3 + .../product-switcher.stories.ts | 3 + .../services/vault-banners.service.spec.ts | 15 +++- .../guards/provider-permissions.guard.spec.ts | 8 +- .../secrets/secret.service.spec.ts | 9 ++- .../services/sm-porting-api.service.spec.ts | 9 ++- .../access-policy.service.spec.ts | 9 ++- .../src/auth/guards/auth.guard.spec.ts | 24 +++--- .../src/auth/guards/lock.guard.spec.ts | 24 +++--- ...edirect-to-vault-if-unlocked.guard.spec.ts | 8 +- .../tde-decryption-required.guard.spec.ts | 8 +- .../src/auth/guards/unauth.guard.spec.ts | 8 +- .../login-approval-dialog.component.spec.ts | 8 +- .../default-change-password.service.spec.ts | 9 ++- ...ypted-migrations-scheduler.service.spec.ts | 15 ++-- .../common/login-strategies/login.strategy.ts | 1 + .../services/accounts/lock.services.spec.ts | 26 ++++--- libs/common/spec/fake-account-service.ts | 28 +++++-- .../src/auth/abstractions/account.service.ts | 11 ++- .../src/auth/services/account.service.spec.ts | 76 ++++++++++++++++++- .../src/auth/services/account.service.ts | 5 ++ .../auth-request-answering.service.spec.ts | 11 ++- .../src/auth/services/auth.service.spec.ts | 27 ++++--- ...-enrollment.service.implementation.spec.ts | 8 +- .../services/vault-timeout.service.spec.ts | 14 ++-- ...ult-server-notifications.multiuser.spec.ts | 13 +++- ...fault-server-notifications.service.spec.ts | 21 ++++- .../default-environment.service.spec.ts | 19 +++-- .../fido2/fido2-authenticator.service.spec.ts | 9 ++- .../services/sdk/default-sdk.service.spec.ts | 7 +- .../services/sdk/register-sdk.service.spec.ts | 12 ++- .../src/platform/sync/default-sync.service.ts | 1 + libs/common/src/services/api.service.spec.ts | 8 +- .../tools/extension/extension.service.spec.ts | 14 +++- .../tools/send/services/send.service.spec.ts | 8 +- .../tools/state/user-state-subject.spec.ts | 15 ++-- ...warden-password-protected-importer.spec.ts | 15 ++-- .../master-password-lock.component.spec.ts | 8 +- .../generator-metadata-provider.spec.ts | 13 +++- .../generator-profile-provider.spec.ts | 29 ++++--- ...fault-credential-generator.service.spec.ts | 9 ++- .../send-list-filters.component.spec.ts | 9 ++- .../login-credentials-view.component.spec.ts | 8 +- .../add-edit-folder-dialog.component.spec.ts | 9 +-- tsconfig.base.json | 1 + 60 files changed, 491 insertions(+), 276 deletions(-) diff --git a/apps/browser/src/auth/popup/account-switching/services/account-switcher.service.spec.ts b/apps/browser/src/auth/popup/account-switching/services/account-switcher.service.spec.ts index 4bacd453803..f3be535f00e 100644 --- a/apps/browser/src/auth/popup/account-switching/services/account-switcher.service.spec.ts +++ b/apps/browser/src/auth/popup/account-switching/services/account-switcher.service.spec.ts @@ -15,6 +15,7 @@ import { } from "@bitwarden/common/platform/abstractions/environment.service"; import { LogService } from "@bitwarden/common/platform/abstractions/log.service"; import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service"; +import { mockAccountInfoWith } from "@bitwarden/common/spec"; import { UserId } from "@bitwarden/common/types/guid"; import { AccountSwitcherService } from "./account-switcher.service"; @@ -71,11 +72,10 @@ describe("AccountSwitcherService", () => { describe("availableAccounts$", () => { it("should return all logged in accounts and an add account option when accounts are less than 5", async () => { - const accountInfo: AccountInfo = { + const accountInfo = mockAccountInfoWith({ name: "Test User 1", email: "test1@email.com", - emailVerified: true, - }; + }); avatarService.getUserAvatarColor$.mockReturnValue(of("#cccccc")); accountsSubject.next({ ["1" as UserId]: accountInfo, ["2" as UserId]: accountInfo }); @@ -109,11 +109,10 @@ describe("AccountSwitcherService", () => { const seedAccounts: Record = {}; const seedStatuses: Record = {}; for (let i = 0; i < numberOfAccounts; i++) { - seedAccounts[`${i}` as UserId] = { + seedAccounts[`${i}` as UserId] = mockAccountInfoWith({ email: `test${i}@email.com`, - emailVerified: true, name: "Test User ${i}", - }; + }); seedStatuses[`${i}` as UserId] = AuthenticationStatus.Unlocked; } avatarService.getUserAvatarColor$.mockReturnValue(of("#cccccc")); @@ -133,11 +132,10 @@ describe("AccountSwitcherService", () => { ); it("excludes logged out accounts", async () => { - const user1AccountInfo: AccountInfo = { + const user1AccountInfo = mockAccountInfoWith({ name: "Test User 1", email: "", - emailVerified: true, - }; + }); accountsSubject.next({ ["1" as UserId]: user1AccountInfo }); authStatusSubject.next({ ["1" as UserId]: AuthenticationStatus.LoggedOut }); accountsSubject.next({ diff --git a/apps/browser/src/autofill/background/notification.background.spec.ts b/apps/browser/src/autofill/background/notification.background.spec.ts index 8df21bc66ef..ab16788ea6f 100644 --- a/apps/browser/src/autofill/background/notification.background.spec.ts +++ b/apps/browser/src/autofill/background/notification.background.spec.ts @@ -4,7 +4,7 @@ import { BehaviorSubject, firstValueFrom, of } from "rxjs"; import { CollectionService } from "@bitwarden/admin-console/common"; import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction"; import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction"; -import { AccountInfo, AccountService } from "@bitwarden/common/auth/abstractions/account.service"; +import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; import { AuthenticationStatus } from "@bitwarden/common/auth/enums/authentication-status"; import { AuthService } from "@bitwarden/common/auth/services/auth.service"; import { ExtensionCommand } from "@bitwarden/common/autofill/constants"; @@ -17,6 +17,7 @@ import { MessagingService } from "@bitwarden/common/platform/abstractions/messag import { ThemeTypes } from "@bitwarden/common/platform/enums"; import { SelfHostedEnvironment } from "@bitwarden/common/platform/services/default-environment.service"; import { ThemeStateService } from "@bitwarden/common/platform/theming/theme-state.service"; +import { mockAccountInfoWith } from "@bitwarden/common/spec"; import { UserId } from "@bitwarden/common/types/guid"; import { CipherRepromptType } from "@bitwarden/common/vault/enums/cipher-reprompt-type"; import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view"; @@ -80,11 +81,12 @@ describe("NotificationBackground", () => { const organizationService = mock(); const userId = "testId" as UserId; - const activeAccountSubject = new BehaviorSubject<{ id: UserId } & AccountInfo>({ + const activeAccountSubject = new BehaviorSubject({ id: userId, - email: "test@example.com", - emailVerified: true, - name: "Test User", + ...mockAccountInfoWith({ + email: "test@example.com", + name: "Test User", + }), }); beforeEach(() => { diff --git a/apps/browser/src/autofill/browser/main-context-menu-handler.spec.ts b/apps/browser/src/autofill/browser/main-context-menu-handler.spec.ts index 1348928b7e9..1738485f289 100644 --- a/apps/browser/src/autofill/browser/main-context-menu-handler.spec.ts +++ b/apps/browser/src/autofill/browser/main-context-menu-handler.spec.ts @@ -18,6 +18,7 @@ import { AutofillSettingsServiceAbstraction } from "@bitwarden/common/autofill/s import { BillingAccountProfileStateService } from "@bitwarden/common/billing/abstractions/account/billing-account-profile-state.service"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; import { LogService } from "@bitwarden/common/platform/abstractions/log.service"; +import { mockAccountInfoWith } from "@bitwarden/common/spec"; import { UserId } from "@bitwarden/common/types/guid"; import { CipherType } from "@bitwarden/common/vault/enums"; import { Cipher } from "@bitwarden/common/vault/models/domain/cipher"; @@ -123,9 +124,10 @@ describe("context-menu", () => { autofillSettingsService.enableContextMenu$ = of(true); accountService.activeAccount$ = of({ id: "userId" as UserId, - email: "", - emailVerified: false, - name: undefined, + ...mockAccountInfoWith({ + email: "", + name: undefined, + }), }); }); diff --git a/apps/browser/src/popup/components/extension-anon-layout-wrapper/extension-anon-layout-wrapper.stories.ts b/apps/browser/src/popup/components/extension-anon-layout-wrapper/extension-anon-layout-wrapper.stories.ts index 57ef285bdf5..8fdae06e28a 100644 --- a/apps/browser/src/popup/components/extension-anon-layout-wrapper/extension-anon-layout-wrapper.stories.ts +++ b/apps/browser/src/popup/components/extension-anon-layout-wrapper/extension-anon-layout-wrapper.stories.ts @@ -76,11 +76,14 @@ const decorators = (options: { { provide: AccountService, useValue: { + // We can't use mockAccountInfoWith() here because we can't take a dependency on @bitwarden/common/spec. + // This is because that package relies on jest dependencies that aren't available here. activeAccount$: of({ id: "test-user-id" as UserId, name: "Test User 1", email: "test@email.com", emailVerified: true, + creationDate: "2024-01-01T00:00:00.000Z", }), }, }, diff --git a/apps/browser/src/tools/popup/send-v2/send-v2.component.spec.ts b/apps/browser/src/tools/popup/send-v2/send-v2.component.spec.ts index 6d79f430a37..6e73d9811f2 100644 --- a/apps/browser/src/tools/popup/send-v2/send-v2.component.spec.ts +++ b/apps/browser/src/tools/popup/send-v2/send-v2.component.spec.ts @@ -16,6 +16,7 @@ import { EnvironmentService } from "@bitwarden/common/platform/abstractions/envi 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 { mockAccountInfoWith } from "@bitwarden/common/spec"; import { SendType } from "@bitwarden/common/tools/send/enums/send-type"; import { SendView } from "@bitwarden/common/tools/send/models/view/send.view"; import { SendApiService } from "@bitwarden/common/tools/send/services/send-api.service.abstraction"; @@ -96,9 +97,10 @@ describe("SendV2Component", () => { useValue: { activeAccount$: of({ id: "123", - email: "test@email.com", - emailVerified: true, - name: "Test User", + ...mockAccountInfoWith({ + email: "test@email.com", + name: "Test User", + }), }), }, }, diff --git a/apps/browser/src/vault/popup/components/vault-v2/attachments/open-attachments/open-attachments.component.spec.ts b/apps/browser/src/vault/popup/components/vault-v2/attachments/open-attachments/open-attachments.component.spec.ts index 459b328c44e..e9636e09873 100644 --- a/apps/browser/src/vault/popup/components/vault-v2/attachments/open-attachments/open-attachments.component.spec.ts +++ b/apps/browser/src/vault/popup/components/vault-v2/attachments/open-attachments/open-attachments.component.spec.ts @@ -11,6 +11,7 @@ import { BillingAccountProfileStateService } from "@bitwarden/common/billing/abs import { ProductTierType } from "@bitwarden/common/billing/enums"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; import { Utils } from "@bitwarden/common/platform/misc/utils"; +import { mockAccountInfoWith } from "@bitwarden/common/spec"; import { CipherId, OrganizationId, UserId } from "@bitwarden/common/types/guid"; import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service"; import { PremiumUpgradePromptService } from "@bitwarden/common/vault/abstractions/premium-upgrade-prompt.service"; @@ -60,9 +61,10 @@ describe("OpenAttachmentsComponent", () => { const accountService = { activeAccount$: of({ id: mockUserId, - email: "test@email.com", - emailVerified: true, - name: "Test User", + ...mockAccountInfoWith({ + email: "test@email.com", + name: "Test User", + }), }), }; const formStatusChange$ = new BehaviorSubject<"enabled" | "disabled">("enabled"); diff --git a/apps/cli/src/key-management/commands/unlock.command.spec.ts b/apps/cli/src/key-management/commands/unlock.command.spec.ts index 70e9a8fd232..50ef414ec37 100644 --- a/apps/cli/src/key-management/commands/unlock.command.spec.ts +++ b/apps/cli/src/key-management/commands/unlock.command.spec.ts @@ -15,6 +15,7 @@ import { ConfigService } from "@bitwarden/common/platform/abstractions/config/co import { EnvironmentService } from "@bitwarden/common/platform/abstractions/environment.service"; import { Utils } from "@bitwarden/common/platform/misc/utils"; import { SymmetricCryptoKey } from "@bitwarden/common/platform/models/domain/symmetric-crypto-key"; +import { mockAccountInfoWith } from "@bitwarden/common/spec"; import { CsprngArray } from "@bitwarden/common/types/csprng"; import { MasterKey, UserKey } from "@bitwarden/common/types/key"; import { KeyService } from "@bitwarden/key-management"; @@ -48,9 +49,10 @@ describe("UnlockCommand", () => { const mockMasterPassword = "testExample"; const activeAccount: Account = { id: "user-id" as UserId, - email: "user@example.com", - emailVerified: true, - name: "User", + ...mockAccountInfoWith({ + email: "user@example.com", + name: "User", + }), }; const mockUserKey = new SymmetricCryptoKey(new Uint8Array(64)) as UserKey; const mockSessionKey = new Uint8Array(64) as CsprngArray; diff --git a/apps/desktop/src/autofill/modal/credentials/fido2-create.component.spec.ts b/apps/desktop/src/autofill/modal/credentials/fido2-create.component.spec.ts index 778215895ee..dbef860aafe 100644 --- a/apps/desktop/src/autofill/modal/credentials/fido2-create.component.spec.ts +++ b/apps/desktop/src/autofill/modal/credentials/fido2-create.component.spec.ts @@ -7,6 +7,7 @@ import { AccountService, Account } from "@bitwarden/common/auth/abstractions/acc import { DomainSettingsService } from "@bitwarden/common/autofill/services/domain-settings.service"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; import { LogService } from "@bitwarden/common/platform/abstractions/log.service"; +import { mockAccountInfoWith } from "@bitwarden/common/spec"; import { UserId } from "@bitwarden/common/types/guid"; import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service"; import { CipherRepromptType, CipherType } from "@bitwarden/common/vault/enums"; @@ -40,9 +41,10 @@ describe("Fido2CreateComponent", () => { const activeAccountSubject = new BehaviorSubject({ id: "test-user-id" as UserId, - email: "test@example.com", - emailVerified: true, - name: "Test User", + ...mockAccountInfoWith({ + email: "test@example.com", + name: "Test User", + }), }); beforeEach(async () => { diff --git a/apps/desktop/src/autofill/services/desktop-autotype-policy.service.spec.ts b/apps/desktop/src/autofill/services/desktop-autotype-policy.service.spec.ts index 555e6ceef5b..907da2fe85c 100644 --- a/apps/desktop/src/autofill/services/desktop-autotype-policy.service.spec.ts +++ b/apps/desktop/src/autofill/services/desktop-autotype-policy.service.spec.ts @@ -10,6 +10,7 @@ import { AuthService } from "@bitwarden/common/auth/abstractions/auth.service"; import { AuthenticationStatus } from "@bitwarden/common/auth/enums/authentication-status"; import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service"; import { Account, UserId } from "@bitwarden/common/platform/models/domain/account"; +import { mockAccountInfoWith } from "@bitwarden/common/spec"; import { DesktopAutotypeDefaultSettingPolicy } from "./desktop-autotype-policy.service"; @@ -30,9 +31,10 @@ describe("DesktopAutotypeDefaultSettingPolicy", () => { beforeEach(() => { mockAccountSubject = new BehaviorSubject({ id: mockUserId, - email: "test@example.com", - emailVerified: true, - name: "Test User", + ...mockAccountInfoWith({ + email: "test@example.com", + name: "Test User", + }), }); mockFeatureFlagSubject = new BehaviorSubject(true); mockAuthStatusSubject = new BehaviorSubject( diff --git a/apps/desktop/src/services/biometric-message-handler.service.spec.ts b/apps/desktop/src/services/biometric-message-handler.service.spec.ts index 49d346bfa3a..3b343fcc0fb 100644 --- a/apps/desktop/src/services/biometric-message-handler.service.spec.ts +++ b/apps/desktop/src/services/biometric-message-handler.service.spec.ts @@ -2,7 +2,7 @@ import { NgZone } from "@angular/core"; import { mock, MockProxy } from "jest-mock-extended"; import { BehaviorSubject, filter, firstValueFrom, of, take, timeout, timer } from "rxjs"; -import { AccountInfo, AccountService } from "@bitwarden/common/auth/abstractions/account.service"; +import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; import { AuthService } from "@bitwarden/common/auth/abstractions/auth.service"; import { AuthenticationStatus } from "@bitwarden/common/auth/enums/authentication-status"; import { CryptoFunctionService } from "@bitwarden/common/key-management/crypto/abstractions/crypto-function.service"; @@ -10,7 +10,7 @@ import { EncryptService } from "@bitwarden/common/key-management/crypto/abstract import { LogService } from "@bitwarden/common/platform/abstractions/log.service"; import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service"; import { Utils } from "@bitwarden/common/platform/misc/utils"; -import { FakeAccountService } from "@bitwarden/common/spec"; +import { mockAccountInfoWith, FakeAccountService } from "@bitwarden/common/spec"; import { CsprngArray } from "@bitwarden/common/types/csprng"; import { UserId } from "@bitwarden/common/types/guid"; import { DialogService } from "@bitwarden/components"; @@ -23,17 +23,15 @@ import { BiometricMessageHandlerService } from "./biometric-message-handler.serv const SomeUser = "SomeUser" as UserId; const AnotherUser = "SomeOtherUser" as UserId; -const accounts: Record = { - [SomeUser]: { +const accounts = { + [SomeUser]: mockAccountInfoWith({ name: "some user", email: "some.user@example.com", - emailVerified: true, - }, - [AnotherUser]: { + }), + [AnotherUser]: mockAccountInfoWith({ name: "some other user", email: "some.other.user@example.com", - emailVerified: true, - }, + }), }; describe("BiometricMessageHandlerService", () => { diff --git a/apps/web/src/app/billing/individual/upgrade/unified-upgrade-dialog/unified-upgrade-dialog.component.spec.ts b/apps/web/src/app/billing/individual/upgrade/unified-upgrade-dialog/unified-upgrade-dialog.component.spec.ts index b28a7b8c4a2..6bc0efb9e96 100644 --- a/apps/web/src/app/billing/individual/upgrade/unified-upgrade-dialog/unified-upgrade-dialog.component.spec.ts +++ b/apps/web/src/app/billing/individual/upgrade/unified-upgrade-dialog/unified-upgrade-dialog.component.spec.ts @@ -10,6 +10,7 @@ import { PersonalSubscriptionPricingTierId, PersonalSubscriptionPricingTierIds, } from "@bitwarden/common/billing/types/subscription-pricing-tier"; +import { mockAccountInfoWith } from "@bitwarden/common/spec"; import { UserId } from "@bitwarden/common/types/guid"; import { DIALOG_DATA, DialogRef } from "@bitwarden/components"; @@ -63,9 +64,10 @@ describe("UnifiedUpgradeDialogComponent", () => { const mockAccount: Account = { id: "user-id" as UserId, - email: "test@example.com", - emailVerified: true, - name: "Test User", + ...mockAccountInfoWith({ + email: "test@example.com", + name: "Test User", + }), }; const defaultDialogData: UnifiedUpgradeDialogParams = { diff --git a/apps/web/src/app/billing/individual/upgrade/upgrade-nav-button/upgrade-nav-button/upgrade-nav-button.component.spec.ts b/apps/web/src/app/billing/individual/upgrade/upgrade-nav-button/upgrade-nav-button/upgrade-nav-button.component.spec.ts index 787936c102e..f5df248cbbf 100644 --- a/apps/web/src/app/billing/individual/upgrade/upgrade-nav-button/upgrade-nav-button/upgrade-nav-button.component.spec.ts +++ b/apps/web/src/app/billing/individual/upgrade/upgrade-nav-button/upgrade-nav-button/upgrade-nav-button.component.spec.ts @@ -7,6 +7,7 @@ import { ApiService } from "@bitwarden/common/abstractions/api.service"; import { Account, AccountService } from "@bitwarden/common/auth/abstractions/account.service"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; +import { mockAccountInfoWith } from "@bitwarden/common/spec"; import { UserId } from "@bitwarden/common/types/guid"; import { SyncService } from "@bitwarden/common/vault/abstractions/sync/sync.service.abstraction"; import { DialogRef, DialogService } from "@bitwarden/components"; @@ -32,9 +33,10 @@ describe("UpgradeNavButtonComponent", () => { const mockAccount: Account = { id: "user-id" as UserId, - email: "test@example.com", - emailVerified: true, - name: "Test User", + ...mockAccountInfoWith({ + email: "test@example.com", + name: "Test User", + }), }; beforeEach(async () => { diff --git a/apps/web/src/app/billing/individual/upgrade/upgrade-payment/services/upgrade-payment.service.spec.ts b/apps/web/src/app/billing/individual/upgrade/upgrade-payment/services/upgrade-payment.service.spec.ts index 9d17d62e4dc..81169d719b6 100644 --- a/apps/web/src/app/billing/individual/upgrade/upgrade-payment/services/upgrade-payment.service.spec.ts +++ b/apps/web/src/app/billing/individual/upgrade/upgrade-payment/services/upgrade-payment.service.spec.ts @@ -13,6 +13,7 @@ import { PaymentMethodType, PlanType } from "@bitwarden/common/billing/enums"; import { PersonalSubscriptionPricingTierIds } from "@bitwarden/common/billing/types/subscription-pricing-tier"; import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service"; import { SyncService } from "@bitwarden/common/platform/sync"; +import { mockAccountInfoWith } from "@bitwarden/common/spec"; import { UserId } from "@bitwarden/common/types/guid"; import { LogService } from "@bitwarden/logging"; @@ -46,11 +47,12 @@ describe("UpgradePaymentService", () => { let sut: UpgradePaymentService; - const mockAccount = { + const mockAccount: Account = { id: "user-id" as UserId, - email: "test@example.com", - emailVerified: true, - name: "Test User", + ...mockAccountInfoWith({ + email: "test@example.com", + name: "Test User", + }), }; const mockTokenizedPaymentMethod: TokenizedPaymentMethod = { @@ -151,9 +153,10 @@ describe("UpgradePaymentService", () => { const mockAccount: Account = { id: "user-id" as UserId, - email: "test@example.com", - name: "Test User", - emailVerified: true, + ...mockAccountInfoWith({ + email: "test@example.com", + name: "Test User", + }), }; const paidOrgData = { @@ -203,9 +206,10 @@ describe("UpgradePaymentService", () => { const mockAccount: Account = { id: "user-id" as UserId, - email: "test@example.com", - name: "Test User", - emailVerified: true, + ...mockAccountInfoWith({ + email: "test@example.com", + name: "Test User", + }), }; const paidOrgData = { @@ -255,9 +259,10 @@ describe("UpgradePaymentService", () => { const mockAccount: Account = { id: "user-id" as UserId, - email: "test@example.com", - name: "Test User", - emailVerified: true, + ...mockAccountInfoWith({ + email: "test@example.com", + name: "Test User", + }), }; mockAccountService.activeAccount$ = of(mockAccount); @@ -289,9 +294,10 @@ describe("UpgradePaymentService", () => { const mockAccount: Account = { id: "user-id" as UserId, - email: "test@example.com", - name: "Test User", - emailVerified: true, + ...mockAccountInfoWith({ + email: "test@example.com", + name: "Test User", + }), }; const expectedCredit = 25.5; @@ -353,9 +359,10 @@ describe("UpgradePaymentService", () => { const mockAccount: Account = { id: "user-id" as UserId, - email: "test@example.com", - name: "Test User", - emailVerified: true, + ...mockAccountInfoWith({ + email: "test@example.com", + name: "Test User", + }), }; const paidOrgData = { diff --git a/apps/web/src/app/dirt/reports/pages/breach-report.component.spec.ts b/apps/web/src/app/dirt/reports/pages/breach-report.component.spec.ts index 143dce3915e..886267e3189 100644 --- a/apps/web/src/app/dirt/reports/pages/breach-report.component.spec.ts +++ b/apps/web/src/app/dirt/reports/pages/breach-report.component.spec.ts @@ -10,6 +10,7 @@ import { AuditService } from "@bitwarden/common/abstractions/audit.service"; import { AccountInfo, AccountService } from "@bitwarden/common/auth/abstractions/account.service"; import { BreachAccountResponse } from "@bitwarden/common/dirt/models/response/breach-account.response"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; +import { mockAccountInfoWith } from "@bitwarden/common/spec"; import { UserId } from "@bitwarden/common/types/guid"; import { BreachReportComponent } from "./breach-report.component"; @@ -38,9 +39,10 @@ describe("BreachReportComponent", () => { let accountService: MockProxy; const activeAccountSubject = new BehaviorSubject<{ id: UserId } & AccountInfo>({ id: "testId" as UserId, - email: "test@example.com", - emailVerified: true, - name: "Test User", + ...mockAccountInfoWith({ + email: "test@example.com", + name: "Test User", + }), }); beforeEach(async () => { diff --git a/apps/web/src/app/key-management/key-rotation/user-key-rotation.service.spec.ts b/apps/web/src/app/key-management/key-rotation/user-key-rotation.service.spec.ts index f4b50b4a772..c0b734f17cc 100644 --- a/apps/web/src/app/key-management/key-rotation/user-key-rotation.service.spec.ts +++ b/apps/web/src/app/key-management/key-rotation/user-key-rotation.service.spec.ts @@ -30,6 +30,7 @@ import { SdkLoadService } from "@bitwarden/common/platform/abstractions/sdk/sdk- import { HashPurpose } from "@bitwarden/common/platform/enums"; import { Utils } from "@bitwarden/common/platform/misc/utils"; import { SymmetricCryptoKey } from "@bitwarden/common/platform/models/domain/symmetric-crypto-key"; +import { mockAccountInfoWith } from "@bitwarden/common/spec"; import { SendWithIdRequest } from "@bitwarden/common/tools/send/models/request/send-with-id.request"; import { SendService } from "@bitwarden/common/tools/send/services/send.service.abstraction"; import { UserId } from "@bitwarden/common/types/guid"; @@ -286,9 +287,10 @@ describe("KeyRotationService", () => { const mockUser = { id: "mockUserId" as UserId, - email: "mockEmail", - emailVerified: true, - name: "mockName", + ...mockAccountInfoWith({ + email: "mockEmail", + name: "mockName", + }), }; const mockTrustedPublicKeys = [Utils.fromUtf8ToArray("test-public-key")]; diff --git a/apps/web/src/app/layouts/product-switcher/navigation-switcher/navigation-switcher.stories.ts b/apps/web/src/app/layouts/product-switcher/navigation-switcher/navigation-switcher.stories.ts index 88132e56384..ea6e972e431 100644 --- a/apps/web/src/app/layouts/product-switcher/navigation-switcher/navigation-switcher.stories.ts +++ b/apps/web/src/app/layouts/product-switcher/navigation-switcher/navigation-switcher.stories.ts @@ -75,11 +75,14 @@ class MockSyncService implements Partial { } class MockAccountService implements Partial { + // We can't use mockAccountInfoWith() here because we can't take a dependency on @bitwarden/common/spec. + // This is because that package relies on jest dependencies that aren't available here. activeAccount$?: Observable = of({ id: "test-user-id" as UserId, name: "Test User 1", email: "test@email.com", emailVerified: true, + creationDate: "2024-01-01T00:00:00.000Z", }); } diff --git a/apps/web/src/app/layouts/product-switcher/product-switcher.stories.ts b/apps/web/src/app/layouts/product-switcher/product-switcher.stories.ts index 4581f5981e6..d412530a635 100644 --- a/apps/web/src/app/layouts/product-switcher/product-switcher.stories.ts +++ b/apps/web/src/app/layouts/product-switcher/product-switcher.stories.ts @@ -75,11 +75,14 @@ class MockSyncService implements Partial { } class MockAccountService implements Partial { + // We can't use mockAccountInfoWith() here because we can't take a dependency on @bitwarden/common/spec. + // This is because that package relies on jest dependencies that aren't available here. activeAccount$?: Observable = of({ id: "test-user-id" as UserId, name: "Test User 1", email: "test@email.com", emailVerified: true, + creationDate: "2024-01-01T00:00:00.000Z", }); } diff --git a/apps/web/src/app/vault/individual-vault/vault-banners/services/vault-banners.service.spec.ts b/apps/web/src/app/vault/individual-vault/vault-banners/services/vault-banners.service.spec.ts index 6b46cd89956..2ba9dd6fad4 100644 --- a/apps/web/src/app/vault/individual-vault/vault-banners/services/vault-banners.service.spec.ts +++ b/apps/web/src/app/vault/individual-vault/vault-banners/services/vault-banners.service.spec.ts @@ -2,14 +2,18 @@ import { TestBed } from "@angular/core/testing"; import { BehaviorSubject, firstValueFrom, take, timeout } from "rxjs"; import { AuthRequestServiceAbstraction } from "@bitwarden/auth/common"; -import { AccountInfo, AccountService } from "@bitwarden/common/auth/abstractions/account.service"; +import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; import { AuthRequestResponse } from "@bitwarden/common/auth/models/response/auth-request.response"; import { BillingAccountProfileStateService } from "@bitwarden/common/billing/abstractions/account/billing-account-profile-state.service"; import { DeviceType } from "@bitwarden/common/enums"; import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; import { Utils } from "@bitwarden/common/platform/misc/utils"; import { StateProvider } from "@bitwarden/common/platform/state"; -import { FakeStateProvider, mockAccountServiceWith } from "@bitwarden/common/spec"; +import { + FakeStateProvider, + mockAccountServiceWith, + mockAccountInfoWith, +} from "@bitwarden/common/spec"; import { UserId } from "@bitwarden/common/types/guid"; import { SyncService } from "@bitwarden/common/vault/abstractions/sync/sync.service.abstraction"; @@ -27,8 +31,11 @@ describe("VaultBannersService", () => { const fakeStateProvider = new FakeStateProvider(mockAccountServiceWith(userId)); const getEmailVerified = jest.fn().mockResolvedValue(true); const lastSync$ = new BehaviorSubject(null); - const accounts$ = new BehaviorSubject>({ - [userId]: { email: "test@bitwarden.com", emailVerified: true, name: "name" } as AccountInfo, + const accounts$ = new BehaviorSubject({ + [userId]: mockAccountInfoWith({ + email: "test@bitwarden.com", + name: "name", + }), }); const pendingAuthRequests$ = new BehaviorSubject>([]); diff --git a/bitwarden_license/bit-web/src/app/admin-console/providers/guards/provider-permissions.guard.spec.ts b/bitwarden_license/bit-web/src/app/admin-console/providers/guards/provider-permissions.guard.spec.ts index a0a881dbad7..99d54eedc29 100644 --- a/bitwarden_license/bit-web/src/app/admin-console/providers/guards/provider-permissions.guard.spec.ts +++ b/bitwarden_license/bit-web/src/app/admin-console/providers/guards/provider-permissions.guard.spec.ts @@ -10,6 +10,7 @@ import { ProviderUserType } from "@bitwarden/common/admin-console/enums"; import { Provider } from "@bitwarden/common/admin-console/models/domain/provider"; import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; +import { mockAccountInfoWith } from "@bitwarden/common/spec"; import { UserId } from "@bitwarden/common/types/guid"; import { ToastService } from "@bitwarden/components"; import { newGuid } from "@bitwarden/guid"; @@ -41,9 +42,10 @@ describe("Provider Permissions Guard", () => { accountService.activeAccount$ = of({ id: mockUserId, - email: "test@example.com", - emailVerified: true, - name: "Test User", + ...mockAccountInfoWith({ + email: "test@example.com", + name: "Test User", + }), }); route = mock({ diff --git a/bitwarden_license/bit-web/src/app/secrets-manager/secrets/secret.service.spec.ts b/bitwarden_license/bit-web/src/app/secrets-manager/secrets/secret.service.spec.ts index 056f7cfe255..606cb835ff1 100644 --- a/bitwarden_license/bit-web/src/app/secrets-manager/secrets/secret.service.spec.ts +++ b/bitwarden_license/bit-web/src/app/secrets-manager/secrets/secret.service.spec.ts @@ -6,6 +6,7 @@ import { AccountInfo, AccountService } from "@bitwarden/common/auth/abstractions import { EncryptService } from "@bitwarden/common/key-management/crypto/abstractions/encrypt.service"; import { EncString } from "@bitwarden/common/key-management/crypto/models/enc-string"; import { SymmetricCryptoKey } from "@bitwarden/common/platform/models/domain/symmetric-crypto-key"; +import { mockAccountInfoWith } from "@bitwarden/common/spec"; import { CsprngArray } from "@bitwarden/common/types/csprng"; import { OrganizationId, UserId } from "@bitwarden/common/types/guid"; import { OrgKey } from "@bitwarden/common/types/key"; @@ -37,9 +38,11 @@ describe("SecretService", () => { let accountService: MockProxy = mock(); const activeAccountSubject = new BehaviorSubject<{ id: UserId } & AccountInfo>({ id: "testId" as UserId, - email: "test@example.com", - emailVerified: true, - name: "Test User", + ...mockAccountInfoWith({ + email: "test@example.com", + name: "Test User", + emailVerified: true, + }), }); beforeEach(() => { diff --git a/bitwarden_license/bit-web/src/app/secrets-manager/settings/services/sm-porting-api.service.spec.ts b/bitwarden_license/bit-web/src/app/secrets-manager/settings/services/sm-porting-api.service.spec.ts index a4f77e6de0b..aa722e31681 100644 --- a/bitwarden_license/bit-web/src/app/secrets-manager/settings/services/sm-porting-api.service.spec.ts +++ b/bitwarden_license/bit-web/src/app/secrets-manager/settings/services/sm-porting-api.service.spec.ts @@ -7,6 +7,7 @@ import { EncryptService } from "@bitwarden/common/key-management/crypto/abstract import { EncString } from "@bitwarden/common/key-management/crypto/models/enc-string"; import { Utils } from "@bitwarden/common/platform/misc/utils"; import { SymmetricCryptoKey } from "@bitwarden/common/platform/models/domain/symmetric-crypto-key"; +import { mockAccountInfoWith } from "@bitwarden/common/spec"; import { CsprngArray } from "@bitwarden/common/types/csprng"; import { OrganizationId, UserId } from "@bitwarden/common/types/guid"; import { OrgKey } from "@bitwarden/common/types/key"; @@ -38,9 +39,11 @@ describe("SecretsManagerPortingApiService", () => { let accountService: MockProxy; const activeAccountSubject = new BehaviorSubject<{ id: UserId } & AccountInfo>({ id: "testId" as UserId, - email: "test@example.com", - emailVerified: true, - name: "Test User", + ...mockAccountInfoWith({ + email: "test@example.com", + name: "Test User", + emailVerified: true, + }), }); beforeEach(() => { diff --git a/bitwarden_license/bit-web/src/app/secrets-manager/shared/access-policies/access-policy.service.spec.ts b/bitwarden_license/bit-web/src/app/secrets-manager/shared/access-policies/access-policy.service.spec.ts index 37a0dc06837..903bfd35122 100644 --- a/bitwarden_license/bit-web/src/app/secrets-manager/shared/access-policies/access-policy.service.spec.ts +++ b/bitwarden_license/bit-web/src/app/secrets-manager/shared/access-policies/access-policy.service.spec.ts @@ -31,7 +31,7 @@ import { PeopleAccessPoliciesRequest } from "./models/requests/people-access-pol import { ProjectServiceAccountsAccessPoliciesRequest } from "./models/requests/project-service-accounts-access-policies.request"; import { ServiceAccountGrantedPoliciesRequest } from "./models/requests/service-account-granted-policies.request"; -import { trackEmissions } from "@bitwarden/common/../spec"; +import { trackEmissions, mockAccountInfoWith } from "@bitwarden/common/../spec"; const SomeCsprngArray = new Uint8Array(64) as CsprngArray; const SomeOrganization = "some organization" as OrganizationId; @@ -52,9 +52,10 @@ describe("AccessPolicyService", () => { let accountService: MockProxy; const activeAccountSubject = new BehaviorSubject<{ id: UserId } & AccountInfo>({ id: "testId" as UserId, - email: "test@example.com", - emailVerified: true, - name: "Test User", + ...mockAccountInfoWith({ + email: "test@example.com", + name: "Test User", + }), }); beforeEach(() => { diff --git a/libs/angular/src/auth/guards/auth.guard.spec.ts b/libs/angular/src/auth/guards/auth.guard.spec.ts index fccfcd58874..335e31ec4d8 100644 --- a/libs/angular/src/auth/guards/auth.guard.spec.ts +++ b/libs/angular/src/auth/guards/auth.guard.spec.ts @@ -5,11 +5,7 @@ import { MockProxy, mock } from "jest-mock-extended"; import { BehaviorSubject, of } from "rxjs"; import { EmptyComponent } from "@bitwarden/angular/platform/guard/feature-flag.guard.spec"; -import { - Account, - AccountInfo, - AccountService, -} from "@bitwarden/common/auth/abstractions/account.service"; +import { Account, AccountService } from "@bitwarden/common/auth/abstractions/account.service"; import { AuthService } from "@bitwarden/common/auth/abstractions/auth.service"; import { AuthenticationStatus } from "@bitwarden/common/auth/enums/authentication-status"; import { ForceSetPasswordReason } from "@bitwarden/common/auth/models/domain/force-set-password-reason"; @@ -18,6 +14,7 @@ import { KeyConnectorService } from "@bitwarden/common/key-management/key-connec import { MasterPasswordServiceAbstraction } from "@bitwarden/common/key-management/master-password/abstractions/master-password.service.abstraction"; import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service"; import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service"; +import { mockAccountInfoWith } from "@bitwarden/common/spec"; import { UserId } from "@bitwarden/common/types/guid"; import { authGuard } from "./auth.guard"; @@ -38,16 +35,13 @@ describe("AuthGuard", () => { const accountService: MockProxy = mock(); const activeAccountSubject = new BehaviorSubject(null); accountService.activeAccount$ = activeAccountSubject; - activeAccountSubject.next( - Object.assign( - { - name: "Test User 1", - email: "test@email.com", - emailVerified: true, - } as AccountInfo, - { id: "test-id" as UserId }, - ), - ); + activeAccountSubject.next({ + id: "test-id" as UserId, + ...mockAccountInfoWith({ + name: "Test User 1", + email: "test@email.com", + }), + }); if (featureFlag) { configService.getFeatureFlag.mockResolvedValue(true); diff --git a/libs/angular/src/auth/guards/lock.guard.spec.ts b/libs/angular/src/auth/guards/lock.guard.spec.ts index da89ee786b7..af36df06097 100644 --- a/libs/angular/src/auth/guards/lock.guard.spec.ts +++ b/libs/angular/src/auth/guards/lock.guard.spec.ts @@ -5,11 +5,7 @@ import { MockProxy, mock } from "jest-mock-extended"; import { BehaviorSubject, of } from "rxjs"; import { EmptyComponent } from "@bitwarden/angular/platform/guard/feature-flag.guard.spec"; -import { - Account, - AccountInfo, - AccountService, -} from "@bitwarden/common/auth/abstractions/account.service"; +import { Account, AccountService } from "@bitwarden/common/auth/abstractions/account.service"; import { AuthService } from "@bitwarden/common/auth/abstractions/auth.service"; import { UserVerificationService } from "@bitwarden/common/auth/abstractions/user-verification/user-verification.service.abstraction"; import { AuthenticationStatus } from "@bitwarden/common/auth/enums/authentication-status"; @@ -20,6 +16,7 @@ import { KeyConnectorDomainConfirmation } from "@bitwarden/common/key-management import { VaultTimeoutSettingsService } from "@bitwarden/common/key-management/vault-timeout"; import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service"; import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; +import { mockAccountInfoWith } from "@bitwarden/common/spec"; import { UserId } from "@bitwarden/common/types/guid"; import { KeyService } from "@bitwarden/key-management"; @@ -68,16 +65,13 @@ describe("lockGuard", () => { const accountService: MockProxy = mock(); const activeAccountSubject = new BehaviorSubject(null); accountService.activeAccount$ = activeAccountSubject; - activeAccountSubject.next( - Object.assign( - { - name: "Test User 1", - email: "test@email.com", - emailVerified: true, - } as AccountInfo, - { id: "test-id" as UserId }, - ), - ); + activeAccountSubject.next({ + id: "test-id" as UserId, + ...mockAccountInfoWith({ + name: "Test User 1", + email: "test@email.com", + }), + }); const testBed = TestBed.configureTestingModule({ imports: [ diff --git a/libs/angular/src/auth/guards/redirect-to-vault-if-unlocked/redirect-to-vault-if-unlocked.guard.spec.ts b/libs/angular/src/auth/guards/redirect-to-vault-if-unlocked/redirect-to-vault-if-unlocked.guard.spec.ts index 004499beede..6dc91fbb925 100644 --- a/libs/angular/src/auth/guards/redirect-to-vault-if-unlocked/redirect-to-vault-if-unlocked.guard.spec.ts +++ b/libs/angular/src/auth/guards/redirect-to-vault-if-unlocked/redirect-to-vault-if-unlocked.guard.spec.ts @@ -7,6 +7,7 @@ import { EmptyComponent } from "@bitwarden/angular/platform/guard/feature-flag.g import { Account, AccountService } from "@bitwarden/common/auth/abstractions/account.service"; import { AuthService } from "@bitwarden/common/auth/abstractions/auth.service"; import { AuthenticationStatus } from "@bitwarden/common/auth/enums/authentication-status"; +import { mockAccountInfoWith } from "@bitwarden/common/spec"; import { UserId } from "@bitwarden/common/types/guid"; import { redirectToVaultIfUnlockedGuard } from "./redirect-to-vault-if-unlocked.guard"; @@ -14,9 +15,10 @@ import { redirectToVaultIfUnlockedGuard } from "./redirect-to-vault-if-unlocked. describe("redirectToVaultIfUnlockedGuard", () => { const activeUser: Account = { id: "userId" as UserId, - email: "test@email.com", - emailVerified: true, - name: "Test User", + ...mockAccountInfoWith({ + email: "test@email.com", + name: "Test User", + }), }; const setup = (activeUser: Account | null, authStatus: AuthenticationStatus | null) => { diff --git a/libs/angular/src/auth/guards/tde-decryption-required.guard.spec.ts b/libs/angular/src/auth/guards/tde-decryption-required.guard.spec.ts index 4408452a2a2..17df6d1d76b 100644 --- a/libs/angular/src/auth/guards/tde-decryption-required.guard.spec.ts +++ b/libs/angular/src/auth/guards/tde-decryption-required.guard.spec.ts @@ -9,6 +9,7 @@ import { AuthService } from "@bitwarden/common/auth/abstractions/auth.service"; import { AuthenticationStatus } from "@bitwarden/common/auth/enums/authentication-status"; import { DeviceTrustServiceAbstraction } from "@bitwarden/common/key-management/device-trust/abstractions/device-trust.service.abstraction"; import { LogService } from "@bitwarden/common/platform/abstractions/log.service"; +import { mockAccountInfoWith } from "@bitwarden/common/spec"; import { UserId } from "@bitwarden/common/types/guid"; import { KeyService } from "@bitwarden/key-management"; @@ -17,9 +18,10 @@ import { tdeDecryptionRequiredGuard } from "./tde-decryption-required.guard"; describe("tdeDecryptionRequiredGuard", () => { const activeUser: Account = { id: "fake_user_id" as UserId, - email: "test@email.com", - emailVerified: true, - name: "Test User", + ...mockAccountInfoWith({ + email: "test@email.com", + name: "Test User", + }), }; const setup = ( diff --git a/libs/angular/src/auth/guards/unauth.guard.spec.ts b/libs/angular/src/auth/guards/unauth.guard.spec.ts index c696b849558..284f595f81a 100644 --- a/libs/angular/src/auth/guards/unauth.guard.spec.ts +++ b/libs/angular/src/auth/guards/unauth.guard.spec.ts @@ -10,6 +10,7 @@ import { AuthService } from "@bitwarden/common/auth/abstractions/auth.service"; import { AuthenticationStatus } from "@bitwarden/common/auth/enums/authentication-status"; import { DeviceTrustServiceAbstraction } from "@bitwarden/common/key-management/device-trust/abstractions/device-trust.service.abstraction"; import { LogService } from "@bitwarden/common/platform/abstractions/log.service"; +import { mockAccountInfoWith } from "@bitwarden/common/spec"; import { UserId } from "@bitwarden/common/types/guid"; import { KeyService } from "@bitwarden/key-management"; @@ -18,9 +19,10 @@ import { unauthGuardFn } from "./unauth.guard"; describe("UnauthGuard", () => { const activeUser: Account = { id: "fake_user_id" as UserId, - email: "test@email.com", - emailVerified: true, - name: "Test User", + ...mockAccountInfoWith({ + email: "test@email.com", + name: "Test User", + }), }; const setup = ( diff --git a/libs/angular/src/auth/login-approval/login-approval-dialog.component.spec.ts b/libs/angular/src/auth/login-approval/login-approval-dialog.component.spec.ts index b21264eb7c8..4dc7522c1b8 100644 --- a/libs/angular/src/auth/login-approval/login-approval-dialog.component.spec.ts +++ b/libs/angular/src/auth/login-approval/login-approval-dialog.component.spec.ts @@ -11,6 +11,7 @@ import { DevicesServiceAbstraction } from "@bitwarden/common/auth/abstractions/d import { AuthRequestResponse } from "@bitwarden/common/auth/models/response/auth-request.response"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; import { ValidationService } from "@bitwarden/common/platform/abstractions/validation.service"; +import { mockAccountInfoWith } from "@bitwarden/common/spec"; import { UserId } from "@bitwarden/common/types/guid"; import { DialogRef, DIALOG_DATA, ToastService } from "@bitwarden/components"; import { LogService } from "@bitwarden/logging"; @@ -48,10 +49,11 @@ describe("LoginApprovalDialogComponent", () => { validationService = mock(); accountService.activeAccount$ = of({ - email: testEmail, id: "test-user-id" as UserId, - emailVerified: true, - name: null, + ...mockAccountInfoWith({ + email: testEmail, + name: null, + }), }); await TestBed.configureTestingModule({ diff --git a/libs/angular/src/auth/password-management/change-password/default-change-password.service.spec.ts b/libs/angular/src/auth/password-management/change-password/default-change-password.service.spec.ts index d14e33c1fdc..5dfc5ffa245 100644 --- a/libs/angular/src/auth/password-management/change-password/default-change-password.service.spec.ts +++ b/libs/angular/src/auth/password-management/change-password/default-change-password.service.spec.ts @@ -8,6 +8,7 @@ import { MasterPasswordApiService } from "@bitwarden/common/auth/abstractions/ma import { EncString } from "@bitwarden/common/key-management/crypto/models/enc-string"; import { InternalMasterPasswordServiceAbstraction } from "@bitwarden/common/key-management/master-password/abstractions/master-password.service.abstraction"; import { SymmetricCryptoKey } from "@bitwarden/common/platform/models/domain/symmetric-crypto-key"; +import { mockAccountInfoWith } from "@bitwarden/common/spec"; import { UserId } from "@bitwarden/common/types/guid"; import { MasterKey, UserKey } from "@bitwarden/common/types/key"; import { KeyService, PBKDF2KdfConfig } from "@bitwarden/key-management"; @@ -26,9 +27,11 @@ describe("DefaultChangePasswordService", () => { const user: Account = { id: userId, - email: "email", - emailVerified: false, - name: "name", + ...mockAccountInfoWith({ + email: "email", + name: "name", + emailVerified: false, + }), }; const passwordInputResult: PasswordInputResult = { diff --git a/libs/angular/src/key-management/encrypted-migration/encrypted-migrations-scheduler.service.spec.ts b/libs/angular/src/key-management/encrypted-migration/encrypted-migrations-scheduler.service.spec.ts index 76cfbc0bfdd..610ec5923eb 100644 --- a/libs/angular/src/key-management/encrypted-migration/encrypted-migrations-scheduler.service.spec.ts +++ b/libs/angular/src/key-management/encrypted-migration/encrypted-migrations-scheduler.service.spec.ts @@ -2,14 +2,13 @@ import { Router } from "@angular/router"; import { mock } from "jest-mock-extended"; import { of } from "rxjs"; -import { AccountInfo } from "@bitwarden/common/auth/abstractions/account.service"; import { AuthService } from "@bitwarden/common/auth/abstractions/auth.service"; import { AuthenticationStatus } from "@bitwarden/common/auth/enums/authentication-status"; import { EncryptedMigrator } from "@bitwarden/common/key-management/encrypted-migrator/encrypted-migrator.abstraction"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; import { SingleUserState, StateProvider } from "@bitwarden/common/platform/state"; import { SyncService } from "@bitwarden/common/platform/sync"; -import { FakeAccountService } from "@bitwarden/common/spec"; +import { mockAccountInfoWith, FakeAccountService } from "@bitwarden/common/spec"; import { UserId } from "@bitwarden/common/types/guid"; import { DialogService, ToastService } from "@bitwarden/components"; import { LogService } from "@bitwarden/logging"; @@ -22,17 +21,15 @@ import { PromptMigrationPasswordComponent } from "./prompt-migration-password.co const SomeUser = "SomeUser" as UserId; const AnotherUser = "SomeOtherUser" as UserId; -const accounts: Record = { - [SomeUser]: { +const accounts = { + [SomeUser]: mockAccountInfoWith({ name: "some user", email: "some.user@example.com", - emailVerified: true, - }, - [AnotherUser]: { + }), + [AnotherUser]: mockAccountInfoWith({ name: "some other user", email: "some.other.user@example.com", - emailVerified: true, - }, + }), }; describe("DefaultEncryptedMigrationsSchedulerService", () => { diff --git a/libs/auth/src/common/login-strategies/login.strategy.ts b/libs/auth/src/common/login-strategies/login.strategy.ts index ae375c8b2f5..acb32969f08 100644 --- a/libs/auth/src/common/login-strategies/login.strategy.ts +++ b/libs/auth/src/common/login-strategies/login.strategy.ts @@ -189,6 +189,7 @@ export abstract class LoginStrategy { name: accountInformation.name, email: accountInformation.email ?? "", emailVerified: accountInformation.email_verified ?? false, + creationDate: undefined, // We don't get a creation date in the token. See https://bitwarden.atlassian.net/browse/PM-29551 for consolidation plans. }); // User env must be seeded from currently set env before switching to the account diff --git a/libs/auth/src/common/services/accounts/lock.services.spec.ts b/libs/auth/src/common/services/accounts/lock.services.spec.ts index e22a6f71581..41e3768d80b 100644 --- a/libs/auth/src/common/services/accounts/lock.services.spec.ts +++ b/libs/auth/src/common/services/accounts/lock.services.spec.ts @@ -8,7 +8,7 @@ import { InternalMasterPasswordServiceAbstraction } from "@bitwarden/common/key- import { VaultTimeoutSettingsService } from "@bitwarden/common/key-management/vault-timeout"; import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service"; import { SystemService } from "@bitwarden/common/platform/abstractions/system.service"; -import { mockAccountServiceWith } from "@bitwarden/common/spec"; +import { mockAccountServiceWith, mockAccountInfoWith } from "@bitwarden/common/spec"; import { UserId } from "@bitwarden/common/types/guid"; import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service"; import { FolderService } from "@bitwarden/common/vault/abstractions/folder/folder.service.abstraction"; @@ -79,17 +79,21 @@ describe("DefaultLockService", () => { ); it("locks the active account last", async () => { - await accountService.addAccount(mockUser2, { - name: "name2", - email: "email2@example.com", - emailVerified: false, - }); + await accountService.addAccount( + mockUser2, + mockAccountInfoWith({ + name: "name2", + email: "email2@example.com", + }), + ); - await accountService.addAccount(mockUser3, { - name: "name3", - email: "name3@example.com", - emailVerified: false, - }); + await accountService.addAccount( + mockUser3, + mockAccountInfoWith({ + name: "name3", + email: "name3@example.com", + }), + ); const lockSpy = jest.spyOn(sut, "lock").mockResolvedValue(undefined); diff --git a/libs/common/spec/fake-account-service.ts b/libs/common/spec/fake-account-service.ts index 389975dc2e1..ed8b7796966 100644 --- a/libs/common/spec/fake-account-service.ts +++ b/libs/common/spec/fake-account-service.ts @@ -6,19 +6,26 @@ import { ReplaySubject, combineLatest, map, Observable } from "rxjs"; import { Account, AccountInfo, AccountService } from "../src/auth/abstractions/account.service"; import { UserId } from "../src/types/guid"; +/** + * Creates a mock AccountInfo object with sensible defaults that can be overridden. + * Use this when you need just an AccountInfo object in tests. + */ +export function mockAccountInfoWith(info: Partial = {}): AccountInfo { + return { + name: "name", + email: "email", + emailVerified: true, + creationDate: "2024-01-01T00:00:00.000Z", + ...info, + }; +} + export function mockAccountServiceWith( userId: UserId, info: Partial = {}, activity: Record = {}, ): FakeAccountService { - const fullInfo: AccountInfo = { - ...info, - ...{ - name: "name", - email: "email", - emailVerified: true, - }, - }; + const fullInfo = mockAccountInfoWith(info); const fullActivity = { [userId]: new Date(), ...activity }; @@ -104,6 +111,10 @@ export class FakeAccountService implements AccountService { await this.mock.setAccountEmailVerified(userId, emailVerified); } + async setAccountCreationDate(userId: UserId, creationDate: string): Promise { + await this.mock.setAccountCreationDate(userId, creationDate); + } + async switchAccount(userId: UserId): Promise { const next = userId == null ? null : { id: userId, ...this.accountsSubject["_buffer"]?.[0]?.[userId] }; @@ -127,4 +138,5 @@ const loggedOutInfo: AccountInfo = { name: undefined, email: "", emailVerified: false, + creationDate: undefined, }; diff --git a/libs/common/src/auth/abstractions/account.service.ts b/libs/common/src/auth/abstractions/account.service.ts index 8b0280feb01..78822f3ebd5 100644 --- a/libs/common/src/auth/abstractions/account.service.ts +++ b/libs/common/src/auth/abstractions/account.service.ts @@ -2,14 +2,11 @@ import { Observable } from "rxjs"; import { UserId } from "../../types/guid"; -/** - * Holds information about an account for use in the AccountService - * if more information is added, be sure to update the equality method. - */ export type AccountInfo = { email: string; emailVerified: boolean; name: string | undefined; + creationDate: string | undefined; }; export type Account = { id: UserId } & AccountInfo; @@ -75,6 +72,12 @@ export abstract class AccountService { * @param emailVerified */ abstract setAccountEmailVerified(userId: UserId, emailVerified: boolean): Promise; + /** + * updates the `accounts$` observable with the creation date for the account. + * @param userId + * @param creationDate + */ + abstract setAccountCreationDate(userId: UserId, creationDate: string): Promise; /** * updates the `accounts$` observable with the new VerifyNewDeviceLogin property for the account. * @param userId diff --git a/libs/common/src/auth/services/account.service.spec.ts b/libs/common/src/auth/services/account.service.spec.ts index 3e3c878eaac..f517b61ffb6 100644 --- a/libs/common/src/auth/services/account.service.spec.ts +++ b/libs/common/src/auth/services/account.service.spec.ts @@ -6,6 +6,7 @@ import { MockProxy, mock } from "jest-mock-extended"; import { firstValueFrom } from "rxjs"; +import { mockAccountInfoWith } from "../../../spec/fake-account-service"; import { FakeGlobalState } from "../../../spec/fake-state"; import { FakeGlobalStateProvider, @@ -27,7 +28,7 @@ import { } from "./account.service"; describe("accountInfoEqual", () => { - const accountInfo: AccountInfo = { name: "name", email: "email", emailVerified: true }; + const accountInfo = mockAccountInfoWith(); it("compares nulls", () => { expect(accountInfoEqual(null, null)).toBe(true); @@ -64,6 +65,23 @@ describe("accountInfoEqual", () => { expect(accountInfoEqual(accountInfo, same)).toBe(true); expect(accountInfoEqual(accountInfo, different)).toBe(false); }); + + it("compares creationDate", () => { + const same = { ...accountInfo }; + const different = { ...accountInfo, creationDate: "2024-12-31T00:00:00.000Z" }; + + expect(accountInfoEqual(accountInfo, same)).toBe(true); + expect(accountInfoEqual(accountInfo, different)).toBe(false); + }); + + it("compares undefined creationDate", () => { + const accountWithoutCreationDate = mockAccountInfoWith({ creationDate: undefined }); + const same = { ...accountWithoutCreationDate }; + const different = { ...accountWithoutCreationDate, creationDate: "2024-01-01T00:00:00.000Z" }; + + expect(accountInfoEqual(accountWithoutCreationDate, same)).toBe(true); + expect(accountInfoEqual(accountWithoutCreationDate, different)).toBe(false); + }); }); describe("accountService", () => { @@ -76,7 +94,10 @@ describe("accountService", () => { let activeAccountIdState: FakeGlobalState; let accountActivityState: FakeGlobalState>; const userId = Utils.newGuid() as UserId; - const userInfo = { email: "email", name: "name", emailVerified: true }; + const userInfo = mockAccountInfoWith({ + email: "email", + name: "name", + }); beforeEach(() => { messagingService = mock(); @@ -253,6 +274,56 @@ describe("accountService", () => { }); }); + describe("setCreationDate", () => { + const initialState = { [userId]: userInfo }; + beforeEach(() => { + accountsState.stateSubject.next(initialState); + }); + + it("should update the account with a new creation date", async () => { + const newCreationDate = "2024-12-31T00:00:00.000Z"; + await sut.setAccountCreationDate(userId, newCreationDate); + const currentState = await firstValueFrom(accountsState.state$); + + expect(currentState).toEqual({ + [userId]: { ...userInfo, creationDate: newCreationDate }, + }); + }); + + it("should not update if the creation date is the same", async () => { + await sut.setAccountCreationDate(userId, userInfo.creationDate); + const currentState = await firstValueFrom(accountsState.state$); + + expect(currentState).toEqual(initialState); + }); + + it("should update from undefined to a defined creation date", async () => { + const accountWithoutCreationDate = mockAccountInfoWith({ + ...userInfo, + creationDate: undefined, + }); + accountsState.stateSubject.next({ [userId]: accountWithoutCreationDate }); + + const newCreationDate = "2024-06-15T12:30:00.000Z"; + await sut.setAccountCreationDate(userId, newCreationDate); + const currentState = await firstValueFrom(accountsState.state$); + + expect(currentState).toEqual({ + [userId]: { ...accountWithoutCreationDate, creationDate: newCreationDate }, + }); + }); + + it("should update to a different creation date string format", async () => { + const newCreationDate = "2023-03-15T08:45:30.123Z"; + await sut.setAccountCreationDate(userId, newCreationDate); + const currentState = await firstValueFrom(accountsState.state$); + + expect(currentState).toEqual({ + [userId]: { ...userInfo, creationDate: newCreationDate }, + }); + }); + }); + describe("setAccountVerifyNewDeviceLogin", () => { const initialState = true; beforeEach(() => { @@ -294,6 +365,7 @@ describe("accountService", () => { email: "", emailVerified: false, name: undefined, + creationDate: undefined, }, }); }); diff --git a/libs/common/src/auth/services/account.service.ts b/libs/common/src/auth/services/account.service.ts index fb4b590ce77..1b028d1eba9 100644 --- a/libs/common/src/auth/services/account.service.ts +++ b/libs/common/src/auth/services/account.service.ts @@ -62,6 +62,7 @@ const LOGGED_OUT_INFO: AccountInfo = { email: "", emailVerified: false, name: undefined, + creationDate: undefined, }; /** @@ -167,6 +168,10 @@ export class AccountServiceImplementation implements InternalAccountService { await this.setAccountInfo(userId, { emailVerified }); } + async setAccountCreationDate(userId: UserId, creationDate: string): Promise { + await this.setAccountInfo(userId, { creationDate }); + } + async clean(userId: UserId) { await this.setAccountInfo(userId, LOGGED_OUT_INFO); await this.removeAccountActivity(userId); diff --git a/libs/common/src/auth/services/auth-request-answering/auth-request-answering.service.spec.ts b/libs/common/src/auth/services/auth-request-answering/auth-request-answering.service.spec.ts index 0b12e1cb661..a44dde04f5f 100644 --- a/libs/common/src/auth/services/auth-request-answering/auth-request-answering.service.spec.ts +++ b/libs/common/src/auth/services/auth-request-answering/auth-request-answering.service.spec.ts @@ -15,6 +15,7 @@ import { SystemNotificationEvent, SystemNotificationsService, } from "@bitwarden/common/platform/system-notifications/system-notifications.service"; +import { mockAccountInfoWith } from "@bitwarden/common/spec"; import { UserId } from "@bitwarden/user-core"; import { AuthRequestAnsweringService } from "./auth-request-answering.service"; @@ -48,14 +49,16 @@ describe("AuthRequestAnsweringService", () => { // Common defaults authService.activeAccountStatus$ = of(AuthenticationStatus.Locked); - accountService.activeAccount$ = of({ - id: userId, + const accountInfo = mockAccountInfoWith({ email: "user@example.com", - emailVerified: true, name: "User", }); + accountService.activeAccount$ = of({ + id: userId, + ...accountInfo, + }); accountService.accounts$ = of({ - [userId]: { email: "user@example.com", emailVerified: true, name: "User" }, + [userId]: accountInfo, }); (masterPasswordService.forceSetPasswordReason$ as jest.Mock).mockReturnValue( of(ForceSetPasswordReason.None), diff --git a/libs/common/src/auth/services/auth.service.spec.ts b/libs/common/src/auth/services/auth.service.spec.ts index 5dcb8c372e5..c7ff55e6bb1 100644 --- a/libs/common/src/auth/services/auth.service.spec.ts +++ b/libs/common/src/auth/services/auth.service.spec.ts @@ -10,6 +10,7 @@ import { makeStaticByteArray, mockAccountServiceWith, trackEmissions, + mockAccountInfoWith, } from "../../../spec"; import { ApiService } from "../../abstractions/api.service"; import { MessagingService } from "../../platform/abstractions/messaging.service"; @@ -58,9 +59,10 @@ describe("AuthService", () => { const accountInfo = { status: AuthenticationStatus.Unlocked, id: userId, - email: "email", - emailVerified: false, - name: "name", + ...mockAccountInfoWith({ + email: "email", + name: "name", + }), }; beforeEach(() => { @@ -112,9 +114,10 @@ describe("AuthService", () => { const accountInfo2 = { status: AuthenticationStatus.Unlocked, id: Utils.newGuid() as UserId, - email: "email2", - emailVerified: false, - name: "name2", + ...mockAccountInfoWith({ + email: "email2", + name: "name2", + }), }; const emissions = trackEmissions(sut.activeAccountStatus$); @@ -131,11 +134,13 @@ describe("AuthService", () => { it("requests auth status for all known users", async () => { const userId2 = Utils.newGuid() as UserId; - await accountService.addAccount(userId2, { - email: "email2", - emailVerified: false, - name: "name2", - }); + await accountService.addAccount( + userId2, + mockAccountInfoWith({ + email: "email2", + name: "name2", + }), + ); const mockFn = jest.fn().mockReturnValue(of(AuthenticationStatus.Locked)); sut.authStatusFor$ = mockFn; diff --git a/libs/common/src/auth/services/password-reset-enrollment.service.implementation.spec.ts b/libs/common/src/auth/services/password-reset-enrollment.service.implementation.spec.ts index 7e6e0d53f57..693992d4c4a 100644 --- a/libs/common/src/auth/services/password-reset-enrollment.service.implementation.spec.ts +++ b/libs/common/src/auth/services/password-reset-enrollment.service.implementation.spec.ts @@ -8,12 +8,13 @@ import { OrganizationUserApiService } from "@bitwarden/admin-console/common"; // eslint-disable-next-line no-restricted-imports import { KeyService } from "@bitwarden/key-management"; +import { mockAccountInfoWith } from "../../../spec/fake-account-service"; import { OrganizationApiServiceAbstraction } from "../../admin-console/abstractions/organization/organization-api.service.abstraction"; import { OrganizationAutoEnrollStatusResponse } from "../../admin-console/models/response/organization-auto-enroll-status.response"; import { EncryptService } from "../../key-management/crypto/abstractions/encrypt.service"; import { I18nService } from "../../platform/abstractions/i18n.service"; import { UserId } from "../../types/guid"; -import { Account, AccountInfo, AccountService } from "../abstractions/account.service"; +import { Account, AccountService } from "../abstractions/account.service"; import { PasswordResetEnrollmentServiceImplementation } from "./password-reset-enrollment.service.implementation"; @@ -96,11 +97,10 @@ describe("PasswordResetEnrollmentServiceImplementation", () => { const encryptedKey = { encryptedString: "encryptedString" }; organizationApiService.getKeys.mockResolvedValue(orgKeyResponse as any); - const user1AccountInfo: AccountInfo = { + const user1AccountInfo = mockAccountInfoWith({ name: "Test User 1", email: "test1@email.com", - emailVerified: true, - }; + }); activeAccountSubject.next(Object.assign(user1AccountInfo, { id: "userId" as UserId })); keyService.userKey$.mockReturnValue(of({ key: "key" } as any)); diff --git a/libs/common/src/key-management/vault-timeout/services/vault-timeout.service.spec.ts b/libs/common/src/key-management/vault-timeout/services/vault-timeout.service.spec.ts index 51eec18f173..8f7f93f368c 100644 --- a/libs/common/src/key-management/vault-timeout/services/vault-timeout.service.spec.ts +++ b/libs/common/src/key-management/vault-timeout/services/vault-timeout.service.spec.ts @@ -7,7 +7,7 @@ import { BehaviorSubject, from, of } from "rxjs"; // eslint-disable-next-line no-restricted-imports import { LockService, LogoutService } from "@bitwarden/auth/common"; -import { FakeAccountService, mockAccountServiceWith } from "../../../../spec"; +import { FakeAccountService, mockAccountServiceWith, mockAccountInfoWith } from "../../../../spec"; import { AccountInfo } from "../../../auth/abstractions/account.service"; import { AuthService } from "../../../auth/abstractions/auth.service"; import { AuthenticationStatus } from "../../../auth/enums/authentication-status"; @@ -109,19 +109,19 @@ describe("VaultTimeoutService", () => { if (globalSetups?.userId) { accountService.activeAccountSubject.next({ id: globalSetups.userId as UserId, - email: null, - emailVerified: false, - name: null, + ...mockAccountInfoWith({ + email: null, + name: null, + }), }); } accountService.accounts$ = of( Object.entries(accounts).reduce( (agg, [id]) => { - agg[id] = { + agg[id] = mockAccountInfoWith({ email: "", - emailVerified: true, name: "", - }; + }); return agg; }, {} as Record, diff --git a/libs/common/src/platform/server-notifications/internal/default-server-notifications.multiuser.spec.ts b/libs/common/src/platform/server-notifications/internal/default-server-notifications.multiuser.spec.ts index cd1bf97150c..46178f62a07 100644 --- a/libs/common/src/platform/server-notifications/internal/default-server-notifications.multiuser.spec.ts +++ b/libs/common/src/platform/server-notifications/internal/default-server-notifications.multiuser.spec.ts @@ -7,6 +7,7 @@ import { InternalPolicyService } from "@bitwarden/common/admin-console/abstracti import { AuthRequestAnsweringServiceAbstraction } from "@bitwarden/common/auth/abstractions/auth-request-answering/auth-request-answering.service.abstraction"; import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum"; +import { mockAccountInfoWith } from "../../../../spec"; import { AccountService } from "../../../auth/abstractions/account.service"; import { AuthService } from "../../../auth/abstractions/auth.service"; import { AuthenticationStatus } from "../../../auth/enums/authentication-status"; @@ -163,9 +164,10 @@ describe("DefaultServerNotificationsService (multi-user)", () => { } else { activeUserAccount$.next({ id: userId, - email: "email", - name: "Test Name", - emailVerified: true, + ...mockAccountInfoWith({ + email: "email", + name: "Test Name", + }), }); } } @@ -174,7 +176,10 @@ describe("DefaultServerNotificationsService (multi-user)", () => { const currentAccounts = (userAccounts$.getValue() as Record) ?? {}; userAccounts$.next({ ...currentAccounts, - [userId]: { email: "email", name: "Test Name", emailVerified: true }, + [userId]: mockAccountInfoWith({ + email: "email", + name: "Test Name", + }), } as any); } diff --git a/libs/common/src/platform/server-notifications/internal/default-server-notifications.service.spec.ts b/libs/common/src/platform/server-notifications/internal/default-server-notifications.service.spec.ts index 4a9b0809ac9..9c84981b7f9 100644 --- a/libs/common/src/platform/server-notifications/internal/default-server-notifications.service.spec.ts +++ b/libs/common/src/platform/server-notifications/internal/default-server-notifications.service.spec.ts @@ -8,7 +8,7 @@ import { InternalPolicyService } from "@bitwarden/common/admin-console/abstracti import { PolicyType } from "@bitwarden/common/admin-console/enums"; import { AuthRequestAnsweringServiceAbstraction } from "@bitwarden/common/auth/abstractions/auth-request-answering/auth-request-answering.service.abstraction"; -import { awaitAsync } from "../../../../spec"; +import { awaitAsync, mockAccountInfoWith } from "../../../../spec"; import { Matrix } from "../../../../spec/matrix"; import { AccountService } from "../../../auth/abstractions/account.service"; import { AuthService } from "../../../auth/abstractions/auth.service"; @@ -139,11 +139,18 @@ describe("NotificationsService", () => { activeAccount.next(null); accounts.next({} as any); } else { - activeAccount.next({ id: userId, email: "email", name: "Test Name", emailVerified: true }); + const accountInfo = mockAccountInfoWith({ + email: "email", + name: "Test Name", + }); + activeAccount.next({ + id: userId, + ...accountInfo, + }); const current = (accounts.getValue() as Record) ?? {}; accounts.next({ ...current, - [userId]: { email: "email", name: "Test Name", emailVerified: true }, + [userId]: accountInfo, } as any); } } @@ -349,7 +356,13 @@ describe("NotificationsService", () => { describe("processNotification", () => { beforeEach(async () => { appIdService.getAppId.mockResolvedValue("test-app-id"); - activeAccount.next({ id: mockUser1, email: "email", name: "Test Name", emailVerified: true }); + activeAccount.next({ + id: mockUser1, + ...mockAccountInfoWith({ + email: "email", + name: "Test Name", + }), + }); }); describe("NotificationType.LogOut", () => { diff --git a/libs/common/src/platform/services/default-environment.service.spec.ts b/libs/common/src/platform/services/default-environment.service.spec.ts index 553f80f83b8..9e8a41616a3 100644 --- a/libs/common/src/platform/services/default-environment.service.spec.ts +++ b/libs/common/src/platform/services/default-environment.service.spec.ts @@ -1,6 +1,6 @@ import { firstValueFrom } from "rxjs"; -import { FakeStateProvider, awaitAsync } from "../../../spec"; +import { FakeStateProvider, awaitAsync, mockAccountInfoWith } from "../../../spec"; import { FakeAccountService } from "../../../spec/fake-account-service"; import { UserId } from "../../types/guid"; import { CloudRegion, Region } from "../abstractions/environment.service"; @@ -28,16 +28,14 @@ describe("EnvironmentService", () => { beforeEach(async () => { accountService = new FakeAccountService({ - [testUser]: { + [testUser]: mockAccountInfoWith({ name: "name", email: "email", - emailVerified: false, - }, - [alternateTestUser]: { + }), + [alternateTestUser]: mockAccountInfoWith({ name: "name", email: "email", - emailVerified: false, - }, + }), }); stateProvider = new FakeStateProvider(accountService); @@ -47,9 +45,10 @@ describe("EnvironmentService", () => { const switchUser = async (userId: UserId) => { accountService.activeAccountSubject.next({ id: userId, - email: "test@example.com", - name: `Test Name ${userId}`, - emailVerified: false, + ...mockAccountInfoWith({ + email: "test@example.com", + name: `Test Name ${userId}`, + }), }); await awaitAsync(); }; diff --git a/libs/common/src/platform/services/fido2/fido2-authenticator.service.spec.ts b/libs/common/src/platform/services/fido2/fido2-authenticator.service.spec.ts index fef64399b40..9c50bd1ab65 100644 --- a/libs/common/src/platform/services/fido2/fido2-authenticator.service.spec.ts +++ b/libs/common/src/platform/services/fido2/fido2-authenticator.service.spec.ts @@ -3,7 +3,7 @@ import { TextEncoder } from "util"; import { mock, MockProxy } from "jest-mock-extended"; import { BehaviorSubject, of } from "rxjs"; -import { mockAccountServiceWith } from "../../../../spec"; +import { mockAccountServiceWith, mockAccountInfoWith } from "../../../../spec"; import { Account } from "../../../auth/abstractions/account.service"; import { CipherId, UserId } from "../../../types/guid"; import { CipherService, EncryptionContext } from "../../../vault/abstractions/cipher.service"; @@ -40,9 +40,10 @@ describe("FidoAuthenticatorService", () => { const userId = "testId" as UserId; const activeAccountSubject = new BehaviorSubject({ id: userId, - email: "test@example.com", - emailVerified: true, - name: "Test User", + ...mockAccountInfoWith({ + email: "test@example.com", + name: "Test User", + }), }); let cipherService!: MockProxy; diff --git a/libs/common/src/platform/services/sdk/default-sdk.service.spec.ts b/libs/common/src/platform/services/sdk/default-sdk.service.spec.ts index 1286ea7b7f9..fb9c1fae77e 100644 --- a/libs/common/src/platform/services/sdk/default-sdk.service.spec.ts +++ b/libs/common/src/platform/services/sdk/default-sdk.service.spec.ts @@ -12,9 +12,9 @@ import { FakeAccountService, FakeStateProvider, mockAccountServiceWith, + mockAccountInfoWith, } from "../../../../spec"; import { ApiService } from "../../../abstractions/api.service"; -import { AccountInfo } from "../../../auth/abstractions/account.service"; import { EncryptedString } from "../../../key-management/crypto/models/enc-string"; import { UserId } from "../../../types/guid"; import { UserKey } from "../../../types/key"; @@ -92,7 +92,10 @@ describe("DefaultSdkService", () => { .calledWith(userId) .mockReturnValue(new BehaviorSubject(mock())); accountService.accounts$ = of({ - [userId]: { email: "email", emailVerified: true, name: "name" } as AccountInfo, + [userId]: mockAccountInfoWith({ + email: "email", + name: "name", + }), }); kdfConfigService.getKdfConfig$ .calledWith(userId) diff --git a/libs/common/src/platform/services/sdk/register-sdk.service.spec.ts b/libs/common/src/platform/services/sdk/register-sdk.service.spec.ts index 0a05ac8dbf4..1f4d086f729 100644 --- a/libs/common/src/platform/services/sdk/register-sdk.service.spec.ts +++ b/libs/common/src/platform/services/sdk/register-sdk.service.spec.ts @@ -8,9 +8,9 @@ import { FakeAccountService, FakeStateProvider, mockAccountServiceWith, + mockAccountInfoWith, } from "../../../../spec"; import { ApiService } from "../../../abstractions/api.service"; -import { AccountInfo } from "../../../auth/abstractions/account.service"; import { UserId } from "../../../types/guid"; import { ConfigService } from "../../abstractions/config/config.service"; import { Environment, EnvironmentService } from "../../abstractions/environment.service"; @@ -76,7 +76,10 @@ describe("DefaultRegisterSdkService", () => { .calledWith(userId) .mockReturnValue(new BehaviorSubject(mock())); accountService.accounts$ = of({ - [userId]: { email: "email", emailVerified: true, name: "name" } as AccountInfo, + [userId]: mockAccountInfoWith({ + email: "email", + name: "name", + }), }); }); @@ -125,7 +128,10 @@ describe("DefaultRegisterSdkService", () => { it("destroys the internal SDK client when the account is removed (logout)", async () => { const accounts$ = new BehaviorSubject({ - [userId]: { email: "email", emailVerified: true, name: "name" } as AccountInfo, + [userId]: mockAccountInfoWith({ + email: "email", + name: "name", + }), }); accountService.accounts$ = accounts$; diff --git a/libs/common/src/platform/sync/default-sync.service.ts b/libs/common/src/platform/sync/default-sync.service.ts index 910702bddd0..8d2ccaffa18 100644 --- a/libs/common/src/platform/sync/default-sync.service.ts +++ b/libs/common/src/platform/sync/default-sync.service.ts @@ -272,6 +272,7 @@ export class DefaultSyncService extends CoreSyncService { await this.tokenService.setSecurityStamp(response.securityStamp, response.id); await this.accountService.setAccountEmailVerified(response.id, response.emailVerified); await this.accountService.setAccountVerifyNewDeviceLogin(response.id, response.verifyDevices); + await this.accountService.setAccountCreationDate(response.id, response.creationDate); await this.billingAccountProfileStateService.setHasPremium( response.premiumPersonally, diff --git a/libs/common/src/services/api.service.spec.ts b/libs/common/src/services/api.service.spec.ts index 1fb8f86697f..9ab84ecb16b 100644 --- a/libs/common/src/services/api.service.spec.ts +++ b/libs/common/src/services/api.service.spec.ts @@ -6,6 +6,7 @@ import { ObservedValueOf, of } from "rxjs"; import { LogoutReason } from "@bitwarden/auth/common"; import { UserId } from "@bitwarden/user-core"; +import { mockAccountInfoWith } from "../../spec"; import { AccountService } from "../auth/abstractions/account.service"; import { TokenService } from "../auth/abstractions/token.service"; import { DeviceType } from "../enums"; @@ -55,9 +56,10 @@ describe("ApiService", () => { accountService.activeAccount$ = of({ id: testActiveUser, - email: "user1@example.com", - emailVerified: true, - name: "Test Name", + ...mockAccountInfoWith({ + email: "user1@example.com", + name: "Test Name", + }), } satisfies ObservedValueOf); httpOperations = mock(); diff --git a/libs/common/src/tools/extension/extension.service.spec.ts b/libs/common/src/tools/extension/extension.service.spec.ts index 9959488feca..c0dec8728fe 100644 --- a/libs/common/src/tools/extension/extension.service.spec.ts +++ b/libs/common/src/tools/extension/extension.service.spec.ts @@ -1,7 +1,12 @@ import { mock } from "jest-mock-extended"; import { BehaviorSubject, firstValueFrom } from "rxjs"; -import { FakeAccountService, FakeStateProvider, awaitAsync } from "../../../spec"; +import { + FakeAccountService, + FakeStateProvider, + awaitAsync, + mockAccountInfoWith, +} from "../../../spec"; import { Account } from "../../auth/abstractions/account.service"; import { EXTENSION_DISK, UserKeyDefinition } from "../../platform/state"; import { UserId } from "../../types/guid"; @@ -21,9 +26,10 @@ import { SimpleLogin } from "./vendor/simplelogin"; const SomeUser = "some user" as UserId; const SomeAccount = { id: SomeUser, - email: "someone@example.com", - emailVerified: true, - name: "Someone", + ...mockAccountInfoWith({ + email: "someone@example.com", + name: "Someone", + }), }; const SomeAccount$ = new BehaviorSubject(SomeAccount); diff --git a/libs/common/src/tools/send/services/send.service.spec.ts b/libs/common/src/tools/send/services/send.service.spec.ts index 96fb2f43c88..397ae905e31 100644 --- a/libs/common/src/tools/send/services/send.service.spec.ts +++ b/libs/common/src/tools/send/services/send.service.spec.ts @@ -11,6 +11,7 @@ import { FakeStateProvider, awaitAsync, mockAccountServiceWith, + mockAccountInfoWith, } from "../../../../spec"; import { KeyGenerationService } from "../../../key-management/crypto"; import { EncryptService } from "../../../key-management/crypto/abstractions/encrypt.service"; @@ -71,9 +72,10 @@ describe("SendService", () => { accountService.activeAccountSubject.next({ id: mockUserId, - email: "email", - emailVerified: false, - name: "name", + ...mockAccountInfoWith({ + email: "email", + name: "name", + }), }); // Initial encrypted state diff --git a/libs/common/src/tools/state/user-state-subject.spec.ts b/libs/common/src/tools/state/user-state-subject.spec.ts index a6d452d37fd..b88c358b6ab 100644 --- a/libs/common/src/tools/state/user-state-subject.spec.ts +++ b/libs/common/src/tools/state/user-state-subject.spec.ts @@ -6,6 +6,7 @@ import { awaitAsync, FakeAccountService, FakeStateProvider, + mockAccountInfoWith, ObservableTracker, } from "../../../spec"; import { Account } from "../../auth/abstractions/account.service"; @@ -23,17 +24,19 @@ import { UserStateSubject } from "./user-state-subject"; const SomeUser = "some user" as UserId; const SomeAccount = { id: SomeUser, - email: "someone@example.com", - emailVerified: true, - name: "Someone", + ...mockAccountInfoWith({ + email: "someone@example.com", + name: "Someone", + }), }; const SomeAccount$ = new BehaviorSubject(SomeAccount); const SomeOtherAccount = { id: "some other user" as UserId, - email: "someone@example.com", - emailVerified: true, - name: "Someone", + ...mockAccountInfoWith({ + email: "someone@example.com", + name: "Someone", + }), }; type TestType = { foo: string }; diff --git a/libs/importer/src/importers/bitwarden/bitwarden-password-protected-importer.spec.ts b/libs/importer/src/importers/bitwarden/bitwarden-password-protected-importer.spec.ts index 6e98b21977d..fdf92cac751 100644 --- a/libs/importer/src/importers/bitwarden/bitwarden-password-protected-importer.spec.ts +++ b/libs/importer/src/importers/bitwarden/bitwarden-password-protected-importer.spec.ts @@ -6,6 +6,7 @@ import { KeyGenerationService } from "@bitwarden/common/key-management/crypto"; import { EncryptService } from "@bitwarden/common/key-management/crypto/abstractions/encrypt.service"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; import { Utils } from "@bitwarden/common/platform/misc/utils"; +import { mockAccountInfoWith } from "@bitwarden/common/spec"; import { emptyGuid, OrganizationId } from "@bitwarden/common/types/guid"; import { OrgKey, UserKey } from "@bitwarden/common/types/key"; import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service"; @@ -41,9 +42,10 @@ describe("BitwardenPasswordProtectedImporter", () => { accountService.activeAccount$ = of({ id: emptyGuid as UserId, - email: "test@example.com", - emailVerified: true, - name: "Test User", + ...mockAccountInfoWith({ + email: "test@example.com", + name: "Test User", + }), }); const mockOrgId = emptyGuid as OrganizationId; @@ -96,9 +98,10 @@ describe("BitwardenPasswordProtectedImporter", () => { beforeEach(() => { accountService.activeAccount$ = of({ id: emptyGuid as UserId, - email: "test@example.com", - emailVerified: true, - name: "Test User", + ...mockAccountInfoWith({ + email: "test@example.com", + name: "Test User", + }), }); importer = new BitwardenPasswordProtectedImporter( keyService, diff --git a/libs/key-management-ui/src/lock/components/master-password-lock/master-password-lock.component.spec.ts b/libs/key-management-ui/src/lock/components/master-password-lock/master-password-lock.component.spec.ts index d40cc98df11..71287e7684c 100644 --- a/libs/key-management-ui/src/lock/components/master-password-lock/master-password-lock.component.spec.ts +++ b/libs/key-management-ui/src/lock/components/master-password-lock/master-password-lock.component.spec.ts @@ -11,6 +11,7 @@ import { MasterPasswordUnlockService } from "@bitwarden/common/key-management/ma import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; import { LogService } from "@bitwarden/common/platform/abstractions/log.service"; import { SymmetricCryptoKey } from "@bitwarden/common/platform/models/domain/symmetric-crypto-key"; +import { mockAccountInfoWith } from "@bitwarden/common/spec"; import { UserKey } from "@bitwarden/common/types/key"; import { AsyncActionsModule, @@ -39,9 +40,10 @@ describe("MasterPasswordLockComponent", () => { const mockMasterPassword = "testExample"; const activeAccount: Account = { id: "user-id" as UserId, - email: "user@example.com", - emailVerified: true, - name: "User", + ...mockAccountInfoWith({ + email: "user@example.com", + name: "User", + }), }; const mockUserKey = new SymmetricCryptoKey(new Uint8Array(64)) as UserKey; diff --git a/libs/tools/generator/core/src/providers/generator-metadata-provider.spec.ts b/libs/tools/generator/core/src/providers/generator-metadata-provider.spec.ts index 376b46cd6e8..39ff74ad901 100644 --- a/libs/tools/generator/core/src/providers/generator-metadata-provider.spec.ts +++ b/libs/tools/generator/core/src/providers/generator-metadata-provider.spec.ts @@ -25,7 +25,11 @@ import { deepFreeze } from "@bitwarden/common/tools/util"; import { UserId } from "@bitwarden/common/types/guid"; import { BitwardenClient } from "@bitwarden/sdk-internal"; -import { FakeAccountService, FakeStateProvider } from "../../../../../common/spec"; +import { + FakeAccountService, + FakeStateProvider, + mockAccountInfoWith, +} from "../../../../../common/spec"; import { Algorithm, AlgorithmsByType, CredentialAlgorithm, Type, Types } from "../metadata"; import catchall from "../metadata/email/catchall"; import plusAddress from "../metadata/email/plus-address"; @@ -40,9 +44,10 @@ import { GeneratorMetadataProvider } from "./generator-metadata-provider"; const SomeUser = "some user" as UserId; const SomeAccount = { id: SomeUser, - email: "someone@example.com", - emailVerified: true, - name: "Someone", + ...mockAccountInfoWith({ + email: "someone@example.com", + name: "Someone", + }), }; const SomeAccount$ = new BehaviorSubject(SomeAccount); diff --git a/libs/tools/generator/core/src/providers/generator-profile-provider.spec.ts b/libs/tools/generator/core/src/providers/generator-profile-provider.spec.ts index 924849b1c22..088bf543fee 100644 --- a/libs/tools/generator/core/src/providers/generator-profile-provider.spec.ts +++ b/libs/tools/generator/core/src/providers/generator-profile-provider.spec.ts @@ -15,7 +15,12 @@ import { UserStateSubjectDependencyProvider } from "@bitwarden/common/tools/stat import { StateConstraints } from "@bitwarden/common/tools/types"; import { OrganizationId, PolicyId, UserId } from "@bitwarden/common/types/guid"; -import { FakeStateProvider, FakeAccountService, awaitAsync } from "../../../../../common/spec"; +import { + FakeStateProvider, + FakeAccountService, + awaitAsync, + mockAccountInfoWith, +} from "../../../../../common/spec"; import { CoreProfileMetadata, ProfileContext } from "../metadata/profile-metadata"; import { GeneratorConstraints } from "../types"; @@ -31,21 +36,25 @@ const UnverifiedEmailUser = "UnverifiedEmailUser" as UserId; const accounts: Record = { [SomeUser]: { id: SomeUser, - name: "some user", - email: "some.user@example.com", - emailVerified: true, + ...mockAccountInfoWith({ + name: "some user", + email: "some.user@example.com", + }), }, [AnotherUser]: { id: AnotherUser, - name: "some other user", - email: "some.other.user@example.com", - emailVerified: true, + ...mockAccountInfoWith({ + name: "some other user", + email: "some.other.user@example.com", + }), }, [UnverifiedEmailUser]: { id: UnverifiedEmailUser, - name: "a user with an unverfied email", - email: "unverified@example.com", - emailVerified: false, + ...mockAccountInfoWith({ + name: "a user with an unverfied email", + email: "unverified@example.com", + emailVerified: false, + }), }, }; const accountService = new FakeAccountService(accounts); diff --git a/libs/tools/generator/core/src/services/default-credential-generator.service.spec.ts b/libs/tools/generator/core/src/services/default-credential-generator.service.spec.ts index 81e7ae6ac63..e459bb47f47 100644 --- a/libs/tools/generator/core/src/services/default-credential-generator.service.spec.ts +++ b/libs/tools/generator/core/src/services/default-credential-generator.service.spec.ts @@ -8,7 +8,7 @@ import { Vendor } from "@bitwarden/common/tools/extension/vendor/data"; import { SemanticLogger, ifEnabledSemanticLoggerProvider } from "@bitwarden/common/tools/log"; import { UserId } from "@bitwarden/common/types/guid"; -import { awaitAsync } from "../../../../../common/spec"; +import { awaitAsync, mockAccountInfoWith } from "../../../../../common/spec"; import { Algorithm, CredentialAlgorithm, @@ -56,9 +56,10 @@ describe("DefaultCredentialGeneratorService", () => { // Use a hard-coded value for mockAccount account = { id: "test-account-id" as UserId, - emailVerified: true, - email: "test@example.com", - name: "Test User", + ...mockAccountInfoWith({ + email: "test@example.com", + name: "Test User", + }), }; system = { diff --git a/libs/tools/send/send-ui/src/send-list-filters/send-list-filters.component.spec.ts b/libs/tools/send/send-ui/src/send-list-filters/send-list-filters.component.spec.ts index b832ac36caf..ca77c94898b 100644 --- a/libs/tools/send/send-ui/src/send-list-filters/send-list-filters.component.spec.ts +++ b/libs/tools/send/send-ui/src/send-list-filters/send-list-filters.component.spec.ts @@ -8,6 +8,7 @@ import { JslibModule } from "@bitwarden/angular/jslib.module"; import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; import { BillingAccountProfileStateService } from "@bitwarden/common/billing/abstractions"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; +import { mockAccountInfoWith } from "@bitwarden/common/spec"; import { UserId } from "@bitwarden/common/types/guid"; import { ChipSelectComponent } from "@bitwarden/components"; @@ -31,9 +32,11 @@ describe("SendListFiltersComponent", () => { accountService.activeAccount$ = of({ id: userId, - email: "test@email.com", - emailVerified: true, - name: "Test User", + ...mockAccountInfoWith({ + email: "test@email.com", + name: "Test User", + emailVerified: true, + }), }); billingAccountProfileStateService.hasPremiumFromAnySource$.mockReturnValue(of(true)); diff --git a/libs/vault/src/cipher-view/login-credentials/login-credentials-view.component.spec.ts b/libs/vault/src/cipher-view/login-credentials/login-credentials-view.component.spec.ts index 42144e646d4..9ff8f7c83da 100644 --- a/libs/vault/src/cipher-view/login-credentials/login-credentials-view.component.spec.ts +++ b/libs/vault/src/cipher-view/login-credentials/login-credentials-view.component.spec.ts @@ -11,6 +11,7 @@ import { EventType } from "@bitwarden/common/enums"; import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; +import { mockAccountInfoWith } from "@bitwarden/common/spec"; import { UserId } from "@bitwarden/common/types/guid"; import { PremiumUpgradePromptService } from "@bitwarden/common/vault/abstractions/premium-upgrade-prompt.service"; import { CipherType } from "@bitwarden/common/vault/enums"; @@ -34,9 +35,10 @@ describe("LoginCredentialsViewComponent", () => { const hasPremiumFromAnySource$ = new BehaviorSubject(true); const mockAccount = { id: "test-user-id" as UserId, - email: "test@example.com", - emailVerified: true, - name: "Test User", + ...mockAccountInfoWith({ + email: "test@example.com", + name: "Test User", + }), type: 0, status: 0, kdf: 0, diff --git a/libs/vault/src/components/add-edit-folder-dialog/add-edit-folder-dialog.component.spec.ts b/libs/vault/src/components/add-edit-folder-dialog/add-edit-folder-dialog.component.spec.ts index 68b0d9dfcf5..9bf53826333 100644 --- a/libs/vault/src/components/add-edit-folder-dialog/add-edit-folder-dialog.component.spec.ts +++ b/libs/vault/src/components/add-edit-folder-dialog/add-edit-folder-dialog.component.spec.ts @@ -2,9 +2,10 @@ import { ComponentFixture, TestBed } from "@angular/core/testing"; import { NoopAnimationsModule } from "@angular/platform-browser/animations"; import { BehaviorSubject } from "rxjs"; -import { AccountInfo, AccountService } from "@bitwarden/common/auth/abstractions/account.service"; +import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; import { LogService } from "@bitwarden/common/platform/abstractions/log.service"; +import { mockAccountInfoWith } from "@bitwarden/common/spec"; import { UserId } from "@bitwarden/common/types/guid"; import { FolderApiServiceAbstraction } from "@bitwarden/common/vault/abstractions/folder/folder-api.service.abstraction"; import { FolderService } from "@bitwarden/common/vault/abstractions/folder/folder.service.abstraction"; @@ -47,11 +48,7 @@ describe("AddEditFolderDialogComponent", () => { showToast.mockClear(); const userId = "" as UserId; - const accountInfo: AccountInfo = { - email: "", - emailVerified: true, - name: undefined, - }; + const accountInfo = mockAccountInfoWith(); await TestBed.configureTestingModule({ imports: [AddEditFolderDialogComponent, NoopAnimationsModule], diff --git a/tsconfig.base.json b/tsconfig.base.json index 2d105d4263d..ae4b9f5f601 100644 --- a/tsconfig.base.json +++ b/tsconfig.base.json @@ -29,6 +29,7 @@ "@bitwarden/browser/*": ["./apps/browser/src/*"], "@bitwarden/cli/*": ["./apps/cli/src/*"], "@bitwarden/client-type": ["libs/client-type/src/index.ts"], + "@bitwarden/common/spec": ["./libs/common/spec"], "@bitwarden/common/*": ["./libs/common/src/*"], "@bitwarden/components": ["./libs/components/src"], "@bitwarden/core-test-utils": ["libs/core-test-utils/src/index.ts"], From 944d324985d9b78059e6215f3cbdeaf19215e37f Mon Sep 17 00:00:00 2001 From: adudek-bw Date: Fri, 12 Dec 2025 12:38:35 -0500 Subject: [PATCH 11/19] [PM-27081] Fix chromium direct import for linux (#17894) * Fix chromium direct import for linux --- .../chromium_importer/src/chromium/platform/linux.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/desktop/desktop_native/chromium_importer/src/chromium/platform/linux.rs b/apps/desktop/desktop_native/chromium_importer/src/chromium/platform/linux.rs index f542e23129a..6fb6e6134c7 100644 --- a/apps/desktop/desktop_native/chromium_importer/src/chromium/platform/linux.rs +++ b/apps/desktop/desktop_native/chromium_importer/src/chromium/platform/linux.rs @@ -18,7 +18,7 @@ use crate::{ pub(crate) const SUPPORTED_BROWSERS: &[BrowserConfig] = &[ BrowserConfig { name: "Chrome", - data_dir: &[".config/google-chrome"], + data_dir: &[".config/google-chrome", "snap/chromium/common/chromium"], }, BrowserConfig { name: "Chromium", From 14dd732b522eff9cc69d771f413af259aca51053 Mon Sep 17 00:00:00 2001 From: Alex Dragovich <46065570+itsadrago@users.noreply.github.com> Date: Fri, 12 Dec 2025 09:43:34 -0800 Subject: [PATCH 12/19] [PM-23258] changing verbiage from import data to import items (#17123) * [PM-23258] changing verbiage from import data to import items * [PM-23258] Removing vault and data from import and export titles, navs, and buttons * [PM-23258] more verbiage changes * [PM-23258] reverting unnecessary change * [PM-23258] removing unused text from messages json files * [PM-23258] small text changes from design * [PM-23258] including secrets manager changes --- apps/browser/src/_locales/en/messages.json | 18 +++++++----------- .../export/export-browser-v2.component.html | 4 ++-- .../import/import-browser-v2.component.html | 4 ++-- .../settings/vault-settings-v2.component.html | 6 +++--- .../tools/export/export-desktop.component.html | 4 ++-- .../tools/import/import-desktop.component.html | 4 ++-- apps/desktop/src/locales/en/messages.json | 15 +++++++-------- apps/desktop/src/main/menu/menu.file.ts | 12 ++++++------ .../layouts/organization-layout.component.html | 4 ++-- .../organization-settings-routing.module.ts | 4 ++-- .../src/app/layouts/user-layout.component.html | 4 ++-- apps/web/src/app/oss-routing.module.ts | 4 ++-- .../app/tools/import/import-web.component.html | 2 +- .../app/tools/import/org-import.component.html | 2 +- .../vault-export/export-web.component.html | 2 +- .../org-vault-export.component.html | 2 +- apps/web/src/locales/en/messages.json | 15 +++------------ .../layout/navigation.component.html | 4 ++-- .../settings/porting/sm-export.component.html | 2 +- .../settings/porting/sm-export.component.ts | 2 +- .../settings/porting/sm-import.component.html | 2 +- .../settings/settings-routing.module.ts | 4 ++-- .../dialog/file-password-prompt.component.html | 2 +- .../src/components/export.component.ts | 2 +- 24 files changed, 55 insertions(+), 69 deletions(-) diff --git a/apps/browser/src/_locales/en/messages.json b/apps/browser/src/_locales/en/messages.json index 09ea964823c..36d69fb09f5 100644 --- a/apps/browser/src/_locales/en/messages.json +++ b/apps/browser/src/_locales/en/messages.json @@ -436,8 +436,8 @@ "sync": { "message": "Sync" }, - "syncVaultNow": { - "message": "Sync vault now" + "syncNow": { + "message": "Sync now" }, "lastSync": { "message": "Last sync:" @@ -455,9 +455,6 @@ "bitWebVaultApp": { "message": "Bitwarden web app" }, - "importItems": { - "message": "Import items" - }, "select": { "message": "Select" }, @@ -1325,8 +1322,11 @@ "exportFrom": { "message": "Export from" }, - "exportVault": { - "message": "Export vault" + "export": { + "message": "Export" + }, + "import": { + "message": "Import" }, "fileFormat": { "message": "File format" @@ -4215,10 +4215,6 @@ "ignore": { "message": "Ignore" }, - "importData": { - "message": "Import data", - "description": "Used for the header of the import dialog, the import button and within the file-password-prompt" - }, "importError": { "message": "Import error" }, diff --git a/apps/browser/src/tools/popup/settings/export/export-browser-v2.component.html b/apps/browser/src/tools/popup/settings/export/export-browser-v2.component.html index d6bf3a3a253..5473bbe620e 100644 --- a/apps/browser/src/tools/popup/settings/export/export-browser-v2.component.html +++ b/apps/browser/src/tools/popup/settings/export/export-browser-v2.component.html @@ -1,5 +1,5 @@ - + @@ -21,7 +21,7 @@ bitFormButton buttonType="primary" > - {{ "exportVault" | i18n }} + {{ "export" | i18n }} diff --git a/apps/browser/src/vault/popup/settings/vault-settings-v2.component.html b/apps/browser/src/vault/popup/settings/vault-settings-v2.component.html index 225640137e8..c042af8cbac 100644 --- a/apps/browser/src/vault/popup/settings/vault-settings-v2.component.html +++ b/apps/browser/src/vault/popup/settings/vault-settings-v2.component.html @@ -15,7 +15,7 @@ diff --git a/apps/desktop/src/app/tools/export/export-desktop.component.html b/apps/desktop/src/app/tools/export/export-desktop.component.html index 9aa59c5a636..a969b86b950 100644 --- a/apps/desktop/src/app/tools/export/export-desktop.component.html +++ b/apps/desktop/src/app/tools/export/export-desktop.component.html @@ -1,5 +1,5 @@ - {{ "exportVault" | i18n }} + {{ "export" | i18n }} - {{ "exportVault" | i18n }} + {{ "export" | i18n }} diff --git a/apps/web/src/app/tools/import/org-import.component.html b/apps/web/src/app/tools/import/org-import.component.html index 25efa9ec0c7..00e4a7690a2 100644 --- a/apps/web/src/app/tools/import/org-import.component.html +++ b/apps/web/src/app/tools/import/org-import.component.html @@ -16,6 +16,6 @@ bitFormButton buttonType="primary" > - {{ "importData" | i18n }} + {{ "import" | i18n }} diff --git a/apps/web/src/app/tools/vault-export/export-web.component.html b/apps/web/src/app/tools/vault-export/export-web.component.html index e3d0ca75d25..1ff34f4c988 100644 --- a/apps/web/src/app/tools/vault-export/export-web.component.html +++ b/apps/web/src/app/tools/vault-export/export-web.component.html @@ -15,6 +15,6 @@ bitFormButton buttonType="primary" > - {{ "confirmFormat" | i18n }} + {{ "export" | i18n }} diff --git a/apps/web/src/app/tools/vault-export/org-vault-export.component.html b/apps/web/src/app/tools/vault-export/org-vault-export.component.html index 01975272e76..e781a839896 100644 --- a/apps/web/src/app/tools/vault-export/org-vault-export.component.html +++ b/apps/web/src/app/tools/vault-export/org-vault-export.component.html @@ -16,6 +16,6 @@ bitFormButton buttonType="primary" > - {{ "confirmFormat" | i18n }} + {{ "export" | i18n }} diff --git a/apps/web/src/locales/en/messages.json b/apps/web/src/locales/en/messages.json index 3b0554547c5..0f8b0c1b466 100644 --- a/apps/web/src/locales/en/messages.json +++ b/apps/web/src/locales/en/messages.json @@ -1975,12 +1975,6 @@ "exportFrom": { "message": "Export from" }, - "exportVault": { - "message": "Export vault" - }, - "exportSecrets": { - "message": "Export secrets" - }, "fileFormat": { "message": "File format" }, @@ -1993,9 +1987,6 @@ "confirmMasterPassword": { "message": "Confirm master password" }, - "confirmFormat": { - "message": "Confirm format" - }, "filePassword": { "message": "File password" }, @@ -2306,6 +2297,9 @@ "tools": { "message": "Tools" }, + "import": { + "message": "Import" + }, "importData": { "message": "Import data" }, @@ -8757,9 +8751,6 @@ "server": { "message": "Server" }, - "exportData": { - "message": "Export data" - }, "exportingOrganizationSecretDataTitle": { "message": "Exporting Organization Secret Data" }, diff --git a/bitwarden_license/bit-web/src/app/secrets-manager/layout/navigation.component.html b/bitwarden_license/bit-web/src/app/secrets-manager/layout/navigation.component.html index 0ea8caef4d6..ac70e1920ee 100644 --- a/bitwarden_license/bit-web/src/app/secrets-manager/layout/navigation.component.html +++ b/bitwarden_license/bit-web/src/app/secrets-manager/layout/navigation.component.html @@ -52,12 +52,12 @@ [relativeTo]="route.parent" > diff --git a/bitwarden_license/bit-web/src/app/secrets-manager/settings/porting/sm-export.component.html b/bitwarden_license/bit-web/src/app/secrets-manager/settings/porting/sm-export.component.html index 9e1f2e01591..113c51327b2 100644 --- a/bitwarden_license/bit-web/src/app/secrets-manager/settings/porting/sm-export.component.html +++ b/bitwarden_license/bit-web/src/app/secrets-manager/settings/porting/sm-export.component.html @@ -17,6 +17,6 @@ diff --git a/bitwarden_license/bit-web/src/app/secrets-manager/settings/porting/sm-export.component.ts b/bitwarden_license/bit-web/src/app/secrets-manager/settings/porting/sm-export.component.ts index e2b66d9ffa6..5e6f81d99d6 100644 --- a/bitwarden_license/bit-web/src/app/secrets-manager/settings/porting/sm-export.component.ts +++ b/bitwarden_license/bit-web/src/app/secrets-manager/settings/porting/sm-export.component.ts @@ -124,7 +124,7 @@ export class SecretsManagerExportComponent implements OnInit, OnDestroy { const ref = openUserVerificationPrompt(this.dialogService, { data: { confirmDescription: "exportSecretsWarningDesc", - confirmButtonText: "exportSecrets", + confirmButtonText: "export", modalTitle: "confirmSecretsExport", }, }); diff --git a/bitwarden_license/bit-web/src/app/secrets-manager/settings/porting/sm-import.component.html b/bitwarden_license/bit-web/src/app/secrets-manager/settings/porting/sm-import.component.html index 353d8d8c8ed..3a663dbcbe9 100644 --- a/bitwarden_license/bit-web/src/app/secrets-manager/settings/porting/sm-import.component.html +++ b/bitwarden_license/bit-web/src/app/secrets-manager/settings/porting/sm-import.component.html @@ -36,6 +36,6 @@ {{ "acceptedFormats" | i18n }} Bitwarden (json) diff --git a/bitwarden_license/bit-web/src/app/secrets-manager/settings/settings-routing.module.ts b/bitwarden_license/bit-web/src/app/secrets-manager/settings/settings-routing.module.ts index ddc9964060e..31029d134fa 100644 --- a/bitwarden_license/bit-web/src/app/secrets-manager/settings/settings-routing.module.ts +++ b/bitwarden_license/bit-web/src/app/secrets-manager/settings/settings-routing.module.ts @@ -12,7 +12,7 @@ const routes: Routes = [ component: SecretsManagerImportComponent, canActivate: [organizationPermissionsGuard((org) => org.isAdmin)], data: { - titleId: "importData", + titleId: "import", }, }, { @@ -20,7 +20,7 @@ const routes: Routes = [ component: SecretsManagerExportComponent, canActivate: [organizationPermissionsGuard((org) => org.isAdmin)], data: { - titleId: "exportData", + titleId: "export", }, }, ]; diff --git a/libs/importer/src/components/dialog/file-password-prompt.component.html b/libs/importer/src/components/dialog/file-password-prompt.component.html index d663ec0f4d3..1c0bcdca31d 100644 --- a/libs/importer/src/components/dialog/file-password-prompt.component.html +++ b/libs/importer/src/components/dialog/file-password-prompt.component.html @@ -21,7 +21,7 @@