From 343fb28010a5778dc3b2862a371b0c8c5ffea679 Mon Sep 17 00:00:00 2001 From: Andreas Coroiu Date: Mon, 4 Nov 2024 13:29:07 +0100 Subject: [PATCH 01/21] chore: bump SDK to 0.1.7 (#11839) This version contains: - GPL license - Function to get SDK version --- package-lock.json | 8 ++++---- package.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index a9b978b8554..e5849c3110b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -24,7 +24,7 @@ "@angular/platform-browser": "16.2.12", "@angular/platform-browser-dynamic": "16.2.12", "@angular/router": "16.2.12", - "@bitwarden/sdk-internal": "0.1.6", + "@bitwarden/sdk-internal": "0.1.7", "@electron/fuses": "1.8.0", "@koa/multer": "3.0.2", "@koa/router": "13.1.0", @@ -4696,9 +4696,9 @@ "link": true }, "node_modules/@bitwarden/sdk-internal": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/@bitwarden/sdk-internal/-/sdk-internal-0.1.6.tgz", - "integrity": "sha512-YUOOcXnK004mAwE+vfy7AgeLYCtTyafYaXEWED3PNRaSun/a5elrAD//h2yuF9u8Dn5jg1VDkssMPpuG9+2VxA==" + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/@bitwarden/sdk-internal/-/sdk-internal-0.1.7.tgz", + "integrity": "sha512-bpcY4rMipUtNSuhMQBAIdPR/Cz1Fx501yG5Vfsp7CuG28g3eQhkIRQsc07s/HAoKlT20senWbMGdHMM0q1IAGw==" }, "node_modules/@bitwarden/vault": { "resolved": "libs/vault", diff --git a/package.json b/package.json index c5d963bef14..fc9e9870f62 100644 --- a/package.json +++ b/package.json @@ -158,7 +158,7 @@ "@angular/platform-browser": "16.2.12", "@angular/platform-browser-dynamic": "16.2.12", "@angular/router": "16.2.12", - "@bitwarden/sdk-internal": "0.1.6", + "@bitwarden/sdk-internal": "0.1.7", "@electron/fuses": "1.8.0", "@koa/multer": "3.0.2", "@koa/router": "13.1.0", From 80d36f4135869cc720b5183f81cebae94ca00180 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 4 Nov 2024 14:09:51 +0100 Subject: [PATCH 02/21] [deps] Platform: Update argon2 to v0.41.1 (#11065) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- apps/cli/package.json | 2 +- apps/desktop/src/package-lock.json | 23 +++++++++++++---------- apps/desktop/src/package.json | 2 +- package-lock.json | 25 ++++++++++++++----------- package.json | 2 +- 5 files changed, 30 insertions(+), 24 deletions(-) diff --git a/apps/cli/package.json b/apps/cli/package.json index fb9f682f961..6aa48d5d4a5 100644 --- a/apps/cli/package.json +++ b/apps/cli/package.json @@ -58,7 +58,7 @@ "dependencies": { "@koa/multer": "3.0.2", "@koa/router": "13.1.0", - "argon2": "0.40.1", + "argon2": "0.41.1", "big-integer": "1.6.52", "browser-hrtime": "1.1.8", "chalk": "4.1.2", diff --git a/apps/desktop/src/package-lock.json b/apps/desktop/src/package-lock.json index 092a8c97618..669467d3569 100644 --- a/apps/desktop/src/package-lock.json +++ b/apps/desktop/src/package-lock.json @@ -10,7 +10,7 @@ "license": "GPL-3.0", "dependencies": { "@bitwarden/desktop-napi": "file:../desktop_native/napi", - "argon2": "0.40.1" + "argon2": "0.41.1" } }, "../desktop_native/napi": { @@ -35,25 +35,28 @@ } }, "node_modules/argon2": { - "version": "0.40.1", - "resolved": "https://registry.npmjs.org/argon2/-/argon2-0.40.1.tgz", - "integrity": "sha512-DjtHDwd7pm12qeWyfihHoM8Bn5vGcgH6sKwgPqwNYroRmxlrzadHEvMyuvQxN/V8YSyRRKD5x6ito09q1e9OyA==", + "version": "0.41.1", + "resolved": "https://registry.npmjs.org/argon2/-/argon2-0.41.1.tgz", + "integrity": "sha512-dqCW8kJXke8Ik+McUcMDltrbuAWETPyU6iq+4AhxqKphWi7pChB/Zgd/Tp/o8xRLbg8ksMj46F/vph9wnxpTzQ==", "hasInstallScript": true, "license": "MIT", "dependencies": { "@phc/format": "^1.0.0", - "node-addon-api": "^7.1.0", - "node-gyp-build": "^4.8.0" + "node-addon-api": "^8.1.0", + "node-gyp-build": "^4.8.1" }, "engines": { "node": ">=16.17.0" } }, "node_modules/node-addon-api": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-7.1.1.tgz", - "integrity": "sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==", - "license": "MIT" + "version": "8.2.1", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-8.2.1.tgz", + "integrity": "sha512-vmEOvxwiH8tlOcv4SyE8RH34rI5/nWVaigUeAUPawC6f0+HoDthwI0vkMu4tbtsZrXq6QXFfrkhjofzKEs5tpA==", + "license": "MIT", + "engines": { + "node": "^18 || ^20 || >= 21" + } }, "node_modules/node-gyp-build": { "version": "4.8.2", diff --git a/apps/desktop/src/package.json b/apps/desktop/src/package.json index 5e27de5f415..bc711455185 100644 --- a/apps/desktop/src/package.json +++ b/apps/desktop/src/package.json @@ -13,6 +13,6 @@ }, "dependencies": { "@bitwarden/desktop-napi": "file:../desktop_native/napi", - "argon2": "0.40.1" + "argon2": "0.41.1" } } diff --git a/package-lock.json b/package-lock.json index e5849c3110b..b5c24a5eafd 100644 --- a/package-lock.json +++ b/package-lock.json @@ -31,7 +31,7 @@ "@microsoft/signalr": "8.0.7", "@microsoft/signalr-protocol-msgpack": "8.0.7", "@ng-select/ng-select": "11.2.0", - "argon2": "0.40.1", + "argon2": "0.41.1", "argon2-browser": "1.18.0", "big-integer": "1.6.52", "bootstrap": "4.6.0", @@ -203,7 +203,7 @@ "dependencies": { "@koa/multer": "3.0.2", "@koa/router": "13.1.0", - "argon2": "0.40.1", + "argon2": "0.41.1", "big-integer": "1.6.52", "browser-hrtime": "1.1.8", "chalk": "4.1.2", @@ -11981,15 +11981,15 @@ "license": "MIT" }, "node_modules/argon2": { - "version": "0.40.1", - "resolved": "https://registry.npmjs.org/argon2/-/argon2-0.40.1.tgz", - "integrity": "sha512-DjtHDwd7pm12qeWyfihHoM8Bn5vGcgH6sKwgPqwNYroRmxlrzadHEvMyuvQxN/V8YSyRRKD5x6ito09q1e9OyA==", + "version": "0.41.1", + "resolved": "https://registry.npmjs.org/argon2/-/argon2-0.41.1.tgz", + "integrity": "sha512-dqCW8kJXke8Ik+McUcMDltrbuAWETPyU6iq+4AhxqKphWi7pChB/Zgd/Tp/o8xRLbg8ksMj46F/vph9wnxpTzQ==", "hasInstallScript": true, "license": "MIT", "dependencies": { "@phc/format": "^1.0.0", - "node-addon-api": "^7.1.0", - "node-gyp-build": "^4.8.0" + "node-addon-api": "^8.1.0", + "node-gyp-build": "^4.8.1" }, "engines": { "node": ">=16.17.0" @@ -28588,10 +28588,13 @@ "license": "MIT" }, "node_modules/node-addon-api": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-7.1.1.tgz", - "integrity": "sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==", - "license": "MIT" + "version": "8.2.1", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-8.2.1.tgz", + "integrity": "sha512-vmEOvxwiH8tlOcv4SyE8RH34rI5/nWVaigUeAUPawC6f0+HoDthwI0vkMu4tbtsZrXq6QXFfrkhjofzKEs5tpA==", + "license": "MIT", + "engines": { + "node": "^18 || ^20 || >= 21" + } }, "node_modules/node-api-version": { "version": "0.2.0", diff --git a/package.json b/package.json index fc9e9870f62..37cd7fc120b 100644 --- a/package.json +++ b/package.json @@ -165,7 +165,7 @@ "@microsoft/signalr": "8.0.7", "@microsoft/signalr-protocol-msgpack": "8.0.7", "@ng-select/ng-select": "11.2.0", - "argon2": "0.40.1", + "argon2": "0.41.1", "argon2-browser": "1.18.0", "big-integer": "1.6.52", "bootstrap": "4.6.0", From f6755da15ba7d935aea5cbb3d0954702329df17a Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 4 Nov 2024 14:10:54 +0100 Subject: [PATCH 03/21] [deps] Platform: Update Rust crate tokio to v1.41.0 (#10848) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- apps/desktop/desktop_native/Cargo.lock | 28 +++++++-------------- apps/desktop/desktop_native/core/Cargo.toml | 2 +- 2 files changed, 10 insertions(+), 20 deletions(-) diff --git a/apps/desktop/desktop_native/Cargo.lock b/apps/desktop/desktop_native/Cargo.lock index a730ee36f87..02ebe8ec1f3 100644 --- a/apps/desktop/desktop_native/Cargo.lock +++ b/apps/desktop/desktop_native/Cargo.lock @@ -1150,13 +1150,14 @@ dependencies = [ [[package]] name = "mio" -version = "0.8.11" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c" +checksum = "80e04d1dcff3aae0704555fe5fee3bcfaf3d1fdf8a7e521d5b9d2b42acb52cec" dependencies = [ + "hermit-abi 0.3.9", "libc", "wasi", - "windows-sys 0.48.0", + "windows-sys 0.52.0", ] [[package]] @@ -1258,16 +1259,6 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" -[[package]] -name = "num_cpus" -version = "1.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" -dependencies = [ - "hermit-abi 0.3.9", - "libc", -] - [[package]] name = "num_threads" version = "0.1.7" @@ -1937,26 +1928,25 @@ dependencies = [ [[package]] name = "tokio" -version = "1.38.0" +version = "1.41.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba4f4a02a7a80d6f274636f0aa95c7e383b912d41fe721a31f29e29698585a4a" +checksum = "145f3413504347a2be84393cc8a7d2fb4d863b375909ea59f2158261aa258bbb" dependencies = [ "backtrace", "bytes", "libc", "mio", - "num_cpus", "pin-project-lite", "socket2", "tokio-macros", - "windows-sys 0.48.0", + "windows-sys 0.52.0", ] [[package]] name = "tokio-macros" -version = "2.3.0" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f5ae998a069d4b5aba8ee9dad856af7d520c3699e6159b185c2acd48155d39a" +checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752" dependencies = [ "proc-macro2", "quote", diff --git a/apps/desktop/desktop_native/core/Cargo.toml b/apps/desktop/desktop_native/core/Cargo.toml index 7df096d2494..7c9c5de1554 100644 --- a/apps/desktop/desktop_native/core/Cargo.toml +++ b/apps/desktop/desktop_native/core/Cargo.toml @@ -39,7 +39,7 @@ retry = "=2.0.0" scopeguard = "=1.2.0" sha2 = "=0.10.8" thiserror = "=1.0.61" -tokio = { version = "=1.38.0", features = ["io-util", "sync", "macros"] } +tokio = { version = "=1.41.0", features = ["io-util", "sync", "macros"] } tokio-util = "=0.7.12" typenum = "=1.17.0" From 2e6ed4a4fc7daeadaf89dbb6c5ee3471c596f416 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Garc=C3=ADa?= Date: Mon, 4 Nov 2024 14:50:05 +0100 Subject: [PATCH 04/21] [PM-14270] Use rust to access windows registry (#11413) --- .github/renovate.json | 4 +- apps/desktop/desktop_native/Cargo.lock | 32 ++++++++- apps/desktop/desktop_native/napi/Cargo.toml | 3 + apps/desktop/desktop_native/napi/index.d.ts | 4 ++ apps/desktop/desktop_native/napi/src/lib.rs | 18 +++++ .../desktop_native/napi/src/registry/dummy.rs | 9 +++ .../desktop_native/napi/src/registry/mod.rs | 4 ++ .../napi/src/registry/windows.rs | 29 ++++++++ apps/desktop/electron-builder.json | 7 -- .../desktop/src/main/native-messaging.main.ts | 70 ++++--------------- package-lock.json | 66 ----------------- package.json | 1 - 12 files changed, 113 insertions(+), 134 deletions(-) create mode 100644 apps/desktop/desktop_native/napi/src/registry/dummy.rs create mode 100644 apps/desktop/desktop_native/napi/src/registry/mod.rs create mode 100644 apps/desktop/desktop_native/napi/src/registry/windows.rs diff --git a/.github/renovate.json b/.github/renovate.json index b044212e58a..f4631804583 100644 --- a/.github/renovate.json +++ b/.github/renovate.json @@ -73,7 +73,7 @@ "reviewers": ["team:team-admin-console-dev"] }, { - "matchPackageNames": ["@types/node-ipc", "node-ipc", "qrious", "regedit"], + "matchPackageNames": ["@types/node-ipc", "node-ipc", "qrious"], "description": "Auth owned dependencies", "commitMessagePrefix": "[deps] Auth:", "reviewers": ["team:team-auth-dev"] @@ -258,5 +258,5 @@ "reviewers": ["team:team-vault-dev"] } ], - "ignoreDeps": ["@types/koa-bodyparser", "bootstrap", "node-ipc", "node", "npm", "regedit"] + "ignoreDeps": ["@types/koa-bodyparser", "bootstrap", "node-ipc", "node", "npm"] } diff --git a/apps/desktop/desktop_native/Cargo.lock b/apps/desktop/desktop_native/Cargo.lock index 02ebe8ec1f3..1f7607b0d23 100644 --- a/apps/desktop/desktop_native/Cargo.lock +++ b/apps/desktop/desktop_native/Cargo.lock @@ -546,6 +546,7 @@ dependencies = [ "napi-derive", "tokio", "tokio-util", + "windows-registry", ] [[package]] @@ -2226,7 +2227,7 @@ checksum = "d2ed2439a290666cd67ecce2b0ffaad89c2a56b976b736e6ece670297897832d" dependencies = [ "windows-implement", "windows-interface", - "windows-result", + "windows-result 0.1.2", "windows-targets 0.52.6", ] @@ -2252,6 +2253,17 @@ dependencies = [ "syn", ] +[[package]] +name = "windows-registry" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bafa604f2104cf5ae2cc2db1dee84b7e6a5d11b05f737b60def0ffdc398cbc0a" +dependencies = [ + "windows-result 0.2.0", + "windows-strings", + "windows-targets 0.52.6", +] + [[package]] name = "windows-result" version = "0.1.2" @@ -2261,6 +2273,24 @@ dependencies = [ "windows-targets 0.52.6", ] +[[package]] +name = "windows-result" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d1043d8214f791817bab27572aaa8af63732e11bf84aa21a45a78d6c317ae0e" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-strings" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "978d65aedf914c664c510d9de43c8fd85ca745eaff1ed53edf409b479e441663" +dependencies = [ + "windows-targets 0.52.6", +] + [[package]] name = "windows-sys" version = "0.48.0" diff --git a/apps/desktop/desktop_native/napi/Cargo.toml b/apps/desktop/desktop_native/napi/Cargo.toml index 787f22ef37d..6da4fcb0153 100644 --- a/apps/desktop/desktop_native/napi/Cargo.toml +++ b/apps/desktop/desktop_native/napi/Cargo.toml @@ -21,5 +21,8 @@ napi-derive = "=2.16.12" tokio = { version = "1.38.0" } tokio-util = "0.7.11" +[target.'cfg(windows)'.dependencies] +windows-registry = "=0.3.0" + [build-dependencies] napi-build = "=2.1.3" diff --git a/apps/desktop/desktop_native/napi/index.d.ts b/apps/desktop/desktop_native/napi/index.d.ts index 45191a48eb0..8e1c1381b5f 100644 --- a/apps/desktop/desktop_native/napi/index.d.ts +++ b/apps/desktop/desktop_native/napi/index.d.ts @@ -51,6 +51,10 @@ export declare namespace powermonitors { export function onLock(callback: (err: Error | null, ) => any): Promise export function isLockMonitorAvailable(): Promise } +export declare namespace windows_registry { + export function createKey(key: string, subkey: string, value: string): Promise + export function deleteKey(key: string, subkey: string): Promise +} export declare namespace ipc { export interface IpcMessage { clientId: number diff --git a/apps/desktop/desktop_native/napi/src/lib.rs b/apps/desktop/desktop_native/napi/src/lib.rs index 838eb651244..face07f2f4e 100644 --- a/apps/desktop/desktop_native/napi/src/lib.rs +++ b/apps/desktop/desktop_native/napi/src/lib.rs @@ -1,5 +1,8 @@ #[macro_use] extern crate napi_derive; + +mod registry; + #[napi] pub mod passwords { /// Fetch the stored password from the keychain. @@ -190,6 +193,21 @@ pub mod powermonitors { } +#[napi] +pub mod windows_registry { + #[napi] + pub async fn create_key(key: String, subkey: String, value: String) -> napi::Result<()> { + crate::registry::create_key(&key, &subkey, &value) + .map_err(|e| napi::Error::from_reason(e.to_string())) + } + + #[napi] + pub async fn delete_key(key: String, subkey: String) -> napi::Result<()> { + crate::registry::delete_key(&key, &subkey) + .map_err(|e| napi::Error::from_reason(e.to_string())) + } +} + #[napi] pub mod ipc { use desktop_core::ipc::server::{Message, MessageType}; diff --git a/apps/desktop/desktop_native/napi/src/registry/dummy.rs b/apps/desktop/desktop_native/napi/src/registry/dummy.rs new file mode 100644 index 00000000000..8cef50f3aaf --- /dev/null +++ b/apps/desktop/desktop_native/napi/src/registry/dummy.rs @@ -0,0 +1,9 @@ +use anyhow::{bail, Result}; + +pub fn create_key(_key: &str, _subkey: &str, _value: &str) -> Result<()> { + bail!("Not implemented") +} + +pub fn delete_key(_key: &str, _subkey: &str) -> Result<()> { + bail!("Not implemented") +} diff --git a/apps/desktop/desktop_native/napi/src/registry/mod.rs b/apps/desktop/desktop_native/napi/src/registry/mod.rs new file mode 100644 index 00000000000..68929408ec7 --- /dev/null +++ b/apps/desktop/desktop_native/napi/src/registry/mod.rs @@ -0,0 +1,4 @@ +#[cfg_attr(target_os = "windows", path = "windows.rs")] +#[cfg_attr(not(target_os = "windows"), path = "dummy.rs")] +mod internal; +pub use internal::*; diff --git a/apps/desktop/desktop_native/napi/src/registry/windows.rs b/apps/desktop/desktop_native/napi/src/registry/windows.rs new file mode 100644 index 00000000000..481dfb5dc49 --- /dev/null +++ b/apps/desktop/desktop_native/napi/src/registry/windows.rs @@ -0,0 +1,29 @@ +use anyhow::{bail, Result}; + +fn convert_key(key: &str) -> Result<&'static windows_registry::Key> { + Ok(match key.to_uppercase().as_str() { + "HKEY_CURRENT_USER" | "HKCU" => windows_registry::CURRENT_USER, + "HKEY_LOCAL_MACHINE" | "HKLM" => windows_registry::LOCAL_MACHINE, + "HKEY_CLASSES_ROOT" | "HKCR" => windows_registry::CLASSES_ROOT, + _ => bail!("Invalid key"), + }) +} + +pub fn create_key(key: &str, subkey: &str, value: &str) -> Result<()> { + let key = convert_key(key)?; + + let subkey = key.create(subkey)?; + + const DEFAULT: &str = ""; + subkey.set_string(DEFAULT, value)?; + + Ok(()) +} + +pub fn delete_key(key: &str, subkey: &str) -> Result<()> { + let key = convert_key(key)?; + + key.remove_tree(subkey)?; + + Ok(()) +} diff --git a/apps/desktop/electron-builder.json b/apps/desktop/electron-builder.json index 21f09453189..53c20b7faf0 100644 --- a/apps/desktop/electron-builder.json +++ b/apps/desktop/electron-builder.json @@ -90,13 +90,6 @@ "electronUpdaterCompatibility": ">=0.0.1", "target": ["portable", "nsis-web", "appx"], "sign": "./sign.js", - "extraResources": [ - { - "from": "../../node_modules/regedit/vbs", - "to": "regedit/vbs", - "filter": ["**/*"] - } - ], "extraFiles": [ { "from": "desktop_native/dist/desktop_proxy.${platform}-${arch}.exe", diff --git a/apps/desktop/src/main/native-messaging.main.ts b/apps/desktop/src/main/native-messaging.main.ts index e383c1e1d3a..16594792f71 100644 --- a/apps/desktop/src/main/native-messaging.main.ts +++ b/apps/desktop/src/main/native-messaging.main.ts @@ -1,12 +1,11 @@ import { existsSync, promises as fs } from "fs"; import { homedir, userInfo } from "os"; import * as path from "path"; -import * as util from "util"; import { ipcMain } from "electron"; import { LogService } from "@bitwarden/common/platform/abstractions/log.service"; -import { ipc } from "@bitwarden/desktop-napi"; +import { ipc, windows_registry } from "@bitwarden/desktop-napi"; import { isDev } from "../utils"; @@ -142,12 +141,12 @@ export class NativeMessagingMain { await this.writeManifest(path.join(destination, "chrome.json"), chromeJson); const nmhs = this.getWindowsNMHS(); - for (const [key, value] of Object.entries(nmhs)) { + for (const [name, [key, subkey]] of Object.entries(nmhs)) { let manifestPath = path.join(destination, "chrome.json"); - if (key === "Firefox") { + if (name === "Firefox") { manifestPath = path.join(destination, "firefox.json"); } - await this.createWindowsRegistry(value, manifestPath); + await windows_registry.createKey(key, subkey, manifestPath); } break; } @@ -225,8 +224,8 @@ export class NativeMessagingMain { await this.removeIfExists(path.join(this.userPath, "browsers", "chrome.json")); const nmhs = this.getWindowsNMHS(); - for (const [, value] of Object.entries(nmhs)) { - await this.deleteWindowsRegistry(value); + for (const [, [key, subkey]] of Object.entries(nmhs)) { + await windows_registry.deleteKey(key, subkey); } break; } @@ -274,11 +273,14 @@ export class NativeMessagingMain { private getWindowsNMHS() { return { - Firefox: "HKCU\\SOFTWARE\\Mozilla\\NativeMessagingHosts\\com.8bit.bitwarden", - Chrome: "HKCU\\SOFTWARE\\Google\\Chrome\\NativeMessagingHosts\\com.8bit.bitwarden", - Chromium: "HKCU\\SOFTWARE\\Chromium\\NativeMessagingHosts\\com.8bit.bitwarden", + Firefox: ["HKCU", "SOFTWARE\\Mozilla\\NativeMessagingHosts\\com.8bit.bitwarden"], + Chrome: ["HKCU", "SOFTWARE\\Google\\Chrome\\NativeMessagingHosts\\com.8bit.bitwarden"], + Chromium: ["HKCU", "SOFTWARE\\Chromium\\NativeMessagingHosts\\com.8bit.bitwarden"], // Edge uses the same registry key as Chrome as a fallback, but it's has its own separate key as well. - "Microsoft Edge": "HKCU\\SOFTWARE\\Microsoft\\Edge\\NativeMessagingHosts\\com.8bit.bitwarden", + "Microsoft Edge": [ + "HKCU", + "SOFTWARE\\Microsoft\\Edge\\NativeMessagingHosts\\com.8bit.bitwarden", + ], }; } @@ -419,52 +421,6 @@ export class NativeMessagingMain { return path.join(path.dirname(this.exePath), `desktop_proxy${ext}`); } - private getRegeditInstance() { - // eslint-disable-next-line - const regedit = require("regedit"); - regedit.setExternalVBSLocation(path.join(path.dirname(this.exePath), "resources/regedit/vbs")); - - return regedit; - } - - private async createWindowsRegistry(location: string, jsonFile: string) { - const regedit = this.getRegeditInstance(); - - const createKey = util.promisify(regedit.createKey); - const putValue = util.promisify(regedit.putValue); - - this.logService.debug(`Adding registry: ${location}`); - - await createKey(location); - - // Insert path to manifest - const obj: any = {}; - obj[location] = { - default: { - value: jsonFile, - type: "REG_DEFAULT", - }, - }; - - return putValue(obj); - } - - private async deleteWindowsRegistry(key: string) { - const regedit = this.getRegeditInstance(); - - const list = util.promisify(regedit.list); - const deleteKey = util.promisify(regedit.deleteKey); - - this.logService.debug(`Removing registry: ${key}`); - - try { - await list(key); - await deleteKey(key); - } catch { - this.logService.error(`Unable to delete registry key: ${key}`); - } - } - private homedir() { if (process.platform === "darwin") { return userInfo().homedir; diff --git a/package-lock.json b/package-lock.json index b5c24a5eafd..a3efe3d2224 100644 --- a/package-lock.json +++ b/package-lock.json @@ -166,7 +166,6 @@ "prettier": "3.3.3", "prettier-plugin-tailwindcss": "0.6.8", "process": "0.11.10", - "regedit": "3.0.3", "remark-gfm": "4.0.0", "rimraf": "6.0.1", "sass": "1.74.1", @@ -21943,13 +21942,6 @@ ], "license": "BSD-3-Clause" }, - "node_modules/if-async": { - "version": "3.7.4", - "resolved": "https://registry.npmjs.org/if-async/-/if-async-3.7.4.tgz", - "integrity": "sha512-BFEH2mZyeF6KZKaKLVPZ0wMjIiWOdjvZ7zbx8ENec0qfZhJwKFbX/4jKM5LTKyJEc/GOqUKiiJ2IFKT9yWrZqA==", - "dev": true, - "license": "MIT" - }, "node_modules/ignore": { "version": "5.3.2", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", @@ -32402,57 +32394,6 @@ "dev": true, "license": "Apache-2.0" }, - "node_modules/regedit": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/regedit/-/regedit-3.0.3.tgz", - "integrity": "sha512-SpHmMKOtiEYx0MiRRC48apBsmThoZ4svZNsYoK8leHd5bdUHV1nYb8pk8gh6Moou7/S9EDi1QsjBTpyXVQrPuQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "debug": "^4.1.0", - "if-async": "^3.7.4", - "stream-slicer": "0.0.6", - "through2": "^0.6.3" - } - }, - "node_modules/regedit/node_modules/isarray": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/regedit/node_modules/readable-stream": { - "version": "1.0.34", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", - "integrity": "sha512-ok1qVCJuRkNmvebYikljxJA/UEsKwLl2nI1OmaqAu4/UE+h0wKCHok4XkL/gvi39OacXvw59RJUOFUkDib2rHg==", - "dev": true, - "license": "MIT", - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.1", - "isarray": "0.0.1", - "string_decoder": "~0.10.x" - } - }, - "node_modules/regedit/node_modules/string_decoder": { - "version": "0.10.31", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", - "integrity": "sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/regedit/node_modules/through2": { - "version": "0.6.5", - "resolved": "https://registry.npmjs.org/through2/-/through2-0.6.5.tgz", - "integrity": "sha512-RkK/CCESdTKQZHdmKICijdKKsCRVHs5KsLZ6pACAmF/1GPUQhonHSXWNERctxEp7RmvjdNbZTL5z9V7nSCXKcg==", - "dev": true, - "license": "MIT", - "dependencies": { - "readable-stream": ">=1.0.33-1 <1.1.0-0", - "xtend": ">=4.0.0 <4.1.0-0" - } - }, "node_modules/regenerate": { "version": "1.4.2", "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", @@ -35247,13 +35188,6 @@ "dev": true, "license": "MIT" }, - "node_modules/stream-slicer": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/stream-slicer/-/stream-slicer-0.0.6.tgz", - "integrity": "sha512-QsY0LbweYE5L+e+iBQgtkM5WUIf7+kCMA/m2VULv8rEEDDnlDPsPvOHH4nli6uaZOKQEt64u65h0l/eeZo7lCw==", - "dev": true, - "license": "MIT" - }, "node_modules/streaming-json-stringify": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/streaming-json-stringify/-/streaming-json-stringify-3.1.0.tgz", diff --git a/package.json b/package.json index 37cd7fc120b..ba94a3ca45f 100644 --- a/package.json +++ b/package.json @@ -127,7 +127,6 @@ "prettier": "3.3.3", "prettier-plugin-tailwindcss": "0.6.8", "process": "0.11.10", - "regedit": "3.0.3", "remark-gfm": "4.0.0", "rimraf": "6.0.1", "sass": "1.74.1", From 2f1f9cd333bda0d5d77764dabba71b9aa06a6dae Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 4 Nov 2024 09:30:03 -0500 Subject: [PATCH 05/21] [deps] Platform: Update @types/chrome to v0.0.280 (#11314) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package-lock.json | 8 ++++---- package.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index a3efe3d2224..0b4ea535e8a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -97,7 +97,7 @@ "@storybook/manager-api": "8.2.9", "@storybook/theming": "8.2.9", "@types/argon2-browser": "1.18.4", - "@types/chrome": "0.0.272", + "@types/chrome": "0.0.280", "@types/firefox-webext-browser": "120.0.4", "@types/inquirer": "8.2.10", "@types/jest": "29.5.12", @@ -9110,9 +9110,9 @@ } }, "node_modules/@types/chrome": { - "version": "0.0.272", - "resolved": "https://registry.npmjs.org/@types/chrome/-/chrome-0.0.272.tgz", - "integrity": "sha512-9cxDmmgyhXV8gsZvlRjqaDizNjIjbV0spsR0fIEaQUoHtbl9D8VkTOLyONgiBKK+guR38x5eMO3E3avUYOXwcQ==", + "version": "0.0.280", + "resolved": "https://registry.npmjs.org/@types/chrome/-/chrome-0.0.280.tgz", + "integrity": "sha512-AotSmZrL9bcZDDmSI1D9dE7PGbhOur5L0cKxXd7IqbVizQWCY4gcvupPUVsQ4FfDj3V2tt/iOpomT9EY0s+w1g==", "dev": true, "license": "MIT", "dependencies": { diff --git a/package.json b/package.json index ba94a3ca45f..ef48d31c0a7 100644 --- a/package.json +++ b/package.json @@ -58,7 +58,7 @@ "@storybook/manager-api": "8.2.9", "@storybook/theming": "8.2.9", "@types/argon2-browser": "1.18.4", - "@types/chrome": "0.0.272", + "@types/chrome": "0.0.280", "@types/firefox-webext-browser": "120.0.4", "@types/inquirer": "8.2.10", "@types/jest": "29.5.12", From f43bf482154e0ba4ef6e0d444f6bb79366056bc2 Mon Sep 17 00:00:00 2001 From: Daniel Riera Date: Mon, 4 Nov 2024 08:40:00 -0600 Subject: [PATCH 06/21] [PM-11777] fix: TOTP not copied when autofilling passkey (#11814) * PM-11777 fix: TOTP not copied when autofilling passkey - Added totpService to overlay background constructor - Edited spec to account for totpsService - Edited fillInlineMenuCipher to copy totp to clipboard if present * add optional chaining --- .../src/autofill/background/overlay.background.spec.ts | 4 ++++ .../browser/src/autofill/background/overlay.background.ts | 8 +++++++- apps/browser/src/background/main.background.ts | 1 + 3 files changed, 12 insertions(+), 1 deletion(-) diff --git a/apps/browser/src/autofill/background/overlay.background.spec.ts b/apps/browser/src/autofill/background/overlay.background.spec.ts index 29ae35d5cef..6ec3c0a9b5a 100644 --- a/apps/browser/src/autofill/background/overlay.background.spec.ts +++ b/apps/browser/src/autofill/background/overlay.background.spec.ts @@ -32,6 +32,7 @@ import { } from "@bitwarden/common/spec"; import { UserId } from "@bitwarden/common/types/guid"; import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service"; +import { TotpService } from "@bitwarden/common/vault/abstractions/totp.service"; import { VaultSettingsService } from "@bitwarden/common/vault/abstractions/vault-settings/vault-settings.service"; import { CipherRepromptType, CipherType } from "@bitwarden/common/vault/enums"; import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view"; @@ -106,6 +107,7 @@ describe("OverlayBackground", () => { let selectedThemeMock$: BehaviorSubject; let inlineMenuFieldQualificationService: InlineMenuFieldQualificationService; let themeStateService: MockProxy; + let totpService: MockProxy; let overlayBackground: OverlayBackground; let portKeyForTabSpy: Record; let pageDetailsForTabSpy: PageDetailsForTab; @@ -184,6 +186,7 @@ describe("OverlayBackground", () => { inlineMenuFieldQualificationService = new InlineMenuFieldQualificationService(); themeStateService = mock(); themeStateService.selectedTheme$ = selectedThemeMock$; + totpService = mock(); overlayBackground = new OverlayBackground( logService, cipherService, @@ -198,6 +201,7 @@ describe("OverlayBackground", () => { fido2ActiveRequestManager, inlineMenuFieldQualificationService, themeStateService, + totpService, generatedPasswordCallbackMock, addPasswordCallbackMock, ); diff --git a/apps/browser/src/autofill/background/overlay.background.ts b/apps/browser/src/autofill/background/overlay.background.ts index a2b3e33d74f..c42d1f7e640 100644 --- a/apps/browser/src/autofill/background/overlay.background.ts +++ b/apps/browser/src/autofill/background/overlay.background.ts @@ -33,6 +33,7 @@ import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/pl import { Utils } from "@bitwarden/common/platform/misc/utils"; import { ThemeStateService } from "@bitwarden/common/platform/theming/theme-state.service"; import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service"; +import { TotpService } from "@bitwarden/common/vault/abstractions/totp.service"; import { VaultSettingsService } from "@bitwarden/common/vault/abstractions/vault-settings/vault-settings.service"; import { CipherType } from "@bitwarden/common/vault/enums"; import { buildCipherIcon } from "@bitwarden/common/vault/icon/build-cipher-icon"; @@ -217,6 +218,7 @@ export class OverlayBackground implements OverlayBackgroundInterface { private fido2ActiveRequestManager: Fido2ActiveRequestManager, private inlineMenuFieldQualificationService: InlineMenuFieldQualificationService, private themeStateService: ThemeStateService, + private totpService: TotpService, private generatePasswordCallback: () => Promise, private addPasswordCallback: (password: string) => Promise, ) { @@ -1058,7 +1060,6 @@ export class OverlayBackground implements OverlayBackgroundInterface { } const cipher = this.inlineMenuCiphers.get(inlineMenuCipherId); - if (usePasskey && cipher.login?.hasFido2Credentials) { await this.authenticatePasskeyCredential( sender, @@ -1066,6 +1067,11 @@ export class OverlayBackground implements OverlayBackgroundInterface { ); this.updateLastUsedInlineMenuCipher(inlineMenuCipherId, cipher); + if (cipher.login?.totp) { + this.platformUtilsService.copyToClipboard( + await this.totpService.getCode(cipher.login.totp), + ); + } return; } diff --git a/apps/browser/src/background/main.background.ts b/apps/browser/src/background/main.background.ts index c3ecb5d3fe7..27d83af1321 100644 --- a/apps/browser/src/background/main.background.ts +++ b/apps/browser/src/background/main.background.ts @@ -1678,6 +1678,7 @@ export default class MainBackground { this.fido2ActiveRequestManager, inlineMenuFieldQualificationService, this.themeStateService, + this.totpService, () => this.generatePassword(), (password) => this.addPasswordToHistory(password), ); From 62545aa25aa31305f9b5ab5030134f17c18cb4cb Mon Sep 17 00:00:00 2001 From: Brandon Treston Date: Mon, 4 Nov 2024 09:46:11 -0500 Subject: [PATCH 07/21] =?UTF-8?q?Revert=20"[PM-13645]=20Fix=20invite=20cou?= =?UTF-8?q?nter=20to=20check=20remaining=20number=20of=20seats=20in=20p?= =?UTF-8?q?=E2=80=A6"=20(#11843)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit 2a956744bdb8057fb33c2b8fae6db277e0bc18a7. --- .../member-dialog/member-dialog.component.html | 11 +++++------ .../member-dialog/member-dialog.component.ts | 5 ----- apps/web/src/locales/en/messages.json | 3 --- 3 files changed, 5 insertions(+), 14 deletions(-) diff --git a/apps/web/src/app/admin-console/organizations/members/components/member-dialog/member-dialog.component.html b/apps/web/src/app/admin-console/organizations/members/components/member-dialog/member-dialog.component.html index a8ecf255f33..2c5daf93c6f 100644 --- a/apps/web/src/app/admin-console/organizations/members/components/member-dialog/member-dialog.component.html +++ b/apps/web/src/app/admin-console/organizations/members/components/member-dialog/member-dialog.component.html @@ -23,15 +23,14 @@

{{ "inviteUserDesc" | i18n }}

- + {{ "email" | i18n }} - {{ - "inviteMultipleEmailDesc" | i18n: remainingSeats + {{ + "inviteMultipleEmailDesc" + | i18n + : (organization.productTierType === ProductTierType.TeamsStarter ? "10" : "20") }} - - {{ "inviteSingleEmailDesc" | i18n: remainingSeats }} -
diff --git a/apps/web/src/app/admin-console/organizations/members/components/member-dialog/member-dialog.component.ts b/apps/web/src/app/admin-console/organizations/members/components/member-dialog/member-dialog.component.ts index 4a95c9cb9cb..8df40e35fef 100644 --- a/apps/web/src/app/admin-console/organizations/members/components/member-dialog/member-dialog.component.ts +++ b/apps/web/src/app/admin-console/organizations/members/components/member-dialog/member-dialog.component.ts @@ -89,7 +89,6 @@ export class MemberDialogComponent implements OnDestroy { PermissionMode = PermissionMode; showNoMasterPasswordWarning = false; isOnSecretsManagerStandalone: boolean; - remainingSeats$: Observable; protected organization$: Observable; protected collectionAccessItems: AccessItemView[] = []; @@ -251,10 +250,6 @@ export class MemberDialogComponent implements OnDestroy { this.loading = false; }); - - this.remainingSeats$ = this.organization$.pipe( - map((organization) => organization.seats - this.params.numConfirmedMembers), - ); } private setFormValidators(organization: Organization) { diff --git a/apps/web/src/locales/en/messages.json b/apps/web/src/locales/en/messages.json index 619d2407be2..986648e5c16 100644 --- a/apps/web/src/locales/en/messages.json +++ b/apps/web/src/locales/en/messages.json @@ -3218,9 +3218,6 @@ } } }, - "inviteSingleEmailDesc": { - "message": "You have 1 invite remaining." - }, "userUsingTwoStep": { "message": "This user is using two-step login to protect their account." }, From 2d0460eb15130e8750ef2e51befb5ed647a7f8fe Mon Sep 17 00:00:00 2001 From: "bw-ghapp[bot]" <178206702+bw-ghapp[bot]@users.noreply.github.com> Date: Mon, 4 Nov 2024 15:43:54 +0000 Subject: [PATCH 08/21] Bumped client version(s) (#11850) Co-authored-by: bitwarden-devops-bot <106330231+bitwarden-devops-bot@users.noreply.github.com> --- apps/browser/package.json | 2 +- apps/browser/src/manifest.json | 2 +- apps/browser/src/manifest.v3.json | 2 +- apps/cli/package.json | 2 +- apps/desktop/package.json | 2 +- apps/desktop/src/package-lock.json | 4 ++-- apps/desktop/src/package.json | 2 +- apps/web/package.json | 2 +- package-lock.json | 8 ++++---- 9 files changed, 13 insertions(+), 13 deletions(-) diff --git a/apps/browser/package.json b/apps/browser/package.json index 6c41f6267cc..5909c802b36 100644 --- a/apps/browser/package.json +++ b/apps/browser/package.json @@ -1,6 +1,6 @@ { "name": "@bitwarden/browser", - "version": "2024.10.1", + "version": "2024.11.0", "scripts": { "build": "cross-env MANIFEST_VERSION=3 webpack", "build:mv2": "webpack", diff --git a/apps/browser/src/manifest.json b/apps/browser/src/manifest.json index 850c5c4727a..0d9a4189578 100644 --- a/apps/browser/src/manifest.json +++ b/apps/browser/src/manifest.json @@ -2,7 +2,7 @@ "manifest_version": 2, "name": "__MSG_extName__", "short_name": "__MSG_appName__", - "version": "2024.10.1", + "version": "2024.11.0", "description": "__MSG_extDesc__", "default_locale": "en", "author": "Bitwarden Inc.", diff --git a/apps/browser/src/manifest.v3.json b/apps/browser/src/manifest.v3.json index 0b89a36d700..f805b701551 100644 --- a/apps/browser/src/manifest.v3.json +++ b/apps/browser/src/manifest.v3.json @@ -3,7 +3,7 @@ "minimum_chrome_version": "102.0", "name": "__MSG_extName__", "short_name": "__MSG_appName__", - "version": "2024.10.1", + "version": "2024.11.0", "description": "__MSG_extDesc__", "default_locale": "en", "author": "Bitwarden Inc.", diff --git a/apps/cli/package.json b/apps/cli/package.json index 6aa48d5d4a5..dcba6707fdf 100644 --- a/apps/cli/package.json +++ b/apps/cli/package.json @@ -1,7 +1,7 @@ { "name": "@bitwarden/cli", "description": "A secure and free password manager for all of your devices.", - "version": "2024.10.0", + "version": "2024.11.0", "keywords": [ "bitwarden", "password", diff --git a/apps/desktop/package.json b/apps/desktop/package.json index 8c89da0e85f..c9e33b7110a 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": "2024.10.3", + "version": "2024.11.0", "keywords": [ "bitwarden", "password", diff --git a/apps/desktop/src/package-lock.json b/apps/desktop/src/package-lock.json index 669467d3569..21075252981 100644 --- a/apps/desktop/src/package-lock.json +++ b/apps/desktop/src/package-lock.json @@ -1,12 +1,12 @@ { "name": "@bitwarden/desktop", - "version": "2024.10.3", + "version": "2024.11.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@bitwarden/desktop", - "version": "2024.10.3", + "version": "2024.11.0", "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 bc711455185..3f4bb0fc0cf 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": "2024.10.3", + "version": "2024.11.0", "author": "Bitwarden Inc. (https://bitwarden.com)", "homepage": "https://bitwarden.com", "license": "GPL-3.0", diff --git a/apps/web/package.json b/apps/web/package.json index 21274fbd804..5dd0e442f2d 100644 --- a/apps/web/package.json +++ b/apps/web/package.json @@ -1,6 +1,6 @@ { "name": "@bitwarden/web-vault", - "version": "2024.10.5", + "version": "2024.11.0", "scripts": { "build:oss": "webpack", "build:bit": "webpack -c ../../bitwarden_license/bit-web/webpack.config.js", diff --git a/package-lock.json b/package-lock.json index 0b4ea535e8a..8ba595c53dc 100644 --- a/package-lock.json +++ b/package-lock.json @@ -193,11 +193,11 @@ }, "apps/browser": { "name": "@bitwarden/browser", - "version": "2024.10.1" + "version": "2024.11.0" }, "apps/cli": { "name": "@bitwarden/cli", - "version": "2024.10.0", + "version": "2024.11.0", "license": "SEE LICENSE IN LICENSE.txt", "dependencies": { "@koa/multer": "3.0.2", @@ -233,7 +233,7 @@ }, "apps/desktop": { "name": "@bitwarden/desktop", - "version": "2024.10.3", + "version": "2024.11.0", "hasInstallScript": true, "license": "GPL-3.0" }, @@ -247,7 +247,7 @@ }, "apps/web": { "name": "@bitwarden/web-vault", - "version": "2024.10.5" + "version": "2024.11.0" }, "libs/admin-console": { "name": "@bitwarden/admin-console", From d669d2003fd646060c3b376f2b132cc86d59f444 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rui=20Tom=C3=A9?= <108268980+r-tome@users.noreply.github.com> Date: Mon, 4 Nov 2024 16:19:30 +0000 Subject: [PATCH 09/21] [PM-10323] Add delete option to managed members (#11655) * Add managedByOrganization property to OrganizationUserUserDetailsResponse and OrganizationUserView * Add managedByOrganization property to OrganizationUserDetailsResponse and OrganizationUserAdminView * Add deleteOrganizationUser method to OrganizationUserApiService * Add copy strings for organization user delete dialog * Add copy string for organization user deleted toast * Add delete organization user dialog component * Add the option to delete managed organization users from the members list * Refactor delete user confirmation dialog in MembersComponent to use DialogService * Delete DeleteOrganizationUserDialogComponent * Refactor delete button in member dialog component to change the icon and tooltip text to 'Remove' * Add delete button to members dialog if the user is managed by the organization --- .../member-dialog.component.html | 10 ++++++ .../member-dialog/member-dialog.component.ts | 36 ++++++++++++++++++- .../members/members.component.html | 11 ++++++ .../members/members.component.ts | 35 ++++++++++++++++++ apps/web/src/locales/en/messages.json | 26 ++++++++++++++ .../organization-user-api.service.ts | 7 ++++ .../default-organization-user-api.service.ts | 10 ++++++ 7 files changed, 134 insertions(+), 1 deletion(-) diff --git a/apps/web/src/app/admin-console/organizations/members/components/member-dialog/member-dialog.component.html b/apps/web/src/app/admin-console/organizations/members/components/member-dialog/member-dialog.component.html index 2c5daf93c6f..b2812727473 100644 --- a/apps/web/src/app/admin-console/organizations/members/components/member-dialog/member-dialog.component.html +++ b/apps/web/src/app/admin-console/organizations/members/components/member-dialog/member-dialog.component.html @@ -264,6 +264,16 @@ + + diff --git a/apps/web/src/app/admin-console/organizations/members/members.component.ts b/apps/web/src/app/admin-console/organizations/members/members.component.ts index 394c900f8d2..e61348e3841 100644 --- a/apps/web/src/app/admin-console/organizations/members/members.component.ts +++ b/apps/web/src/app/admin-console/organizations/members/members.component.ts @@ -518,6 +518,7 @@ export class MembersComponent extends BaseMembersComponent isOnSecretsManagerStandalone: this.orgIsOnSecretsManagerStandalone, initialTab: initialTab, numConfirmedMembers: this.dataSource.confirmedUserCount, + managedByOrganization: user?.managedByOrganization, }, }); @@ -725,6 +726,40 @@ export class MembersComponent extends BaseMembersComponent return true; } + async deleteUser(user: OrganizationUserView) { + const confirmed = await this.dialogService.openSimpleDialog({ + title: { + key: "deleteOrganizationUser", + placeholders: [this.userNamePipe.transform(user)], + }, + content: { key: "deleteOrganizationUserWarning" }, + type: "warning", + acceptButtonText: { key: "delete" }, + cancelButtonText: { key: "cancel" }, + }); + + if (!confirmed) { + return false; + } + + this.actionPromise = this.organizationUserApiService.deleteOrganizationUser( + this.organization.id, + user.id, + ); + try { + await this.actionPromise; + this.toastService.showToast({ + variant: "success", + title: null, + message: this.i18nService.t("organizationUserDeleted", this.userNamePipe.transform(user)), + }); + this.dataSource.removeUser(user); + } catch (e) { + this.validationService.showError(e); + } + this.actionPromise = null; + } + private async noMasterPasswordConfirmationDialog(user: OrganizationUserView) { return this.dialogService.openSimpleDialog({ title: { diff --git a/apps/web/src/locales/en/messages.json b/apps/web/src/locales/en/messages.json index 986648e5c16..7e441ae4ba2 100644 --- a/apps/web/src/locales/en/messages.json +++ b/apps/web/src/locales/en/messages.json @@ -9554,5 +9554,31 @@ }, "single-org-revoked-user-warning": { "message": "Non-compliant members will be revoked. Administrators can restore members once they leave all other organizations." + }, + "deleteOrganizationUser": { + "message": "Delete $NAME$", + "placeholders": { + "name": { + "content": "$1", + "example": "John Doe" + }, + "description": "Title for the delete organization user dialog" + } + }, + "deleteOrganizationUserWarning": { + "message": "When a member is deleted, their Bitwarden account and individual vault data will be permanently deleted. Collection data will remain in the organization. To reinstate them they must create an account and be onboarded again.", + "description": "Warning for the delete organization user dialog" + }, + "organizationUserDeleted": { + "message": "Deleted $NAME$", + "placeholders": { + "name": { + "content": "$1", + "example": "John Doe" + } + } + }, + "organizationUserDeletedDesc": { + "message": "The user was removed from the organization and all associated user data has been deleted." } } diff --git a/libs/admin-console/src/common/organization-user/abstractions/organization-user-api.service.ts b/libs/admin-console/src/common/organization-user/abstractions/organization-user-api.service.ts index ff7f9c5df6c..42cbe1438d1 100644 --- a/libs/admin-console/src/common/organization-user/abstractions/organization-user-api.service.ts +++ b/libs/admin-console/src/common/organization-user/abstractions/organization-user-api.service.ts @@ -275,4 +275,11 @@ export abstract class OrganizationUserApiService { organizationId: string, ids: string[], ): Promise>; + + /** + * Remove an organization user's access to the organization and delete their account data + * @param organizationId - Identifier for the organization the user belongs to + * @param id - Organization user identifier + */ + abstract deleteOrganizationUser(organizationId: string, id: string): Promise; } diff --git a/libs/admin-console/src/common/organization-user/services/default-organization-user-api.service.ts b/libs/admin-console/src/common/organization-user/services/default-organization-user-api.service.ts index 6a9911e732c..d9e069dc934 100644 --- a/libs/admin-console/src/common/organization-user/services/default-organization-user-api.service.ts +++ b/libs/admin-console/src/common/organization-user/services/default-organization-user-api.service.ts @@ -359,4 +359,14 @@ export class DefaultOrganizationUserApiService implements OrganizationUserApiSer ); return new ListResponse(r, OrganizationUserBulkResponse); } + + deleteOrganizationUser(organizationId: string, id: string): Promise { + return this.apiService.send( + "DELETE", + "/organizations/" + organizationId + "/users/" + id + "/delete-account", + null, + true, + false, + ); + } } From d804a78bfbf5a6b92756cf0fd5db2deaa1bc968b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rui=20Tom=C3=A9?= <108268980+r-tome@users.noreply.github.com> Date: Mon, 4 Nov 2024 16:37:24 +0000 Subject: [PATCH 10/21] [PM-11406] Account Management: Prevent a verified user from deleting their account (#11505) * Update AccountService to include a method for setting the managedByOrganizationId * Update AccountComponent to conditionally show the purgeVault button based on a feature flag and if the user is managed by an organization * Add missing method to FakeAccountService * Remove the setAccountManagedByOrganizationId method from the AccountService abstract class. * Refactor AccountComponent to use OrganizationService to check for managing organization * Rename managesActiveUser to userIsManagedByOrganization * Hide the change email section if the user is managed by an organization * Refactor userIsManagedByOrganization property to be non-nullable in organization data and response models * Refactor organization.data.spec.ts to include non-nullable userIsManagedByOrganization property * Refactor account component to conditionally show delete account button based on user's organization management status * Add showDeleteAccount$ observable to AccountComponent --- .../app/auth/settings/account/account.component.html | 8 +++++++- .../app/auth/settings/account/account.component.ts | 11 +++++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/apps/web/src/app/auth/settings/account/account.component.html b/apps/web/src/app/auth/settings/account/account.component.html index a5e5329fce7..4055f14219c 100644 --- a/apps/web/src/app/auth/settings/account/account.component.html +++ b/apps/web/src/app/auth/settings/account/account.component.html @@ -21,7 +21,13 @@ > {{ "purgeVault" | i18n }} - diff --git a/apps/web/src/app/auth/settings/account/account.component.ts b/apps/web/src/app/auth/settings/account/account.component.ts index 51bf4276960..eed88476e27 100644 --- a/apps/web/src/app/auth/settings/account/account.component.ts +++ b/apps/web/src/app/auth/settings/account/account.component.ts @@ -23,6 +23,7 @@ export class AccountComponent implements OnInit { showChangeEmail$: Observable; showPurgeVault$: Observable; + showDeleteAccount$: Observable; constructor( private modalService: ModalService, @@ -63,6 +64,16 @@ export class AccountComponent implements OnInit { !isAccountDeprovisioningEnabled || !userIsManagedByOrganization, ), ); + + this.showDeleteAccount$ = combineLatest([ + isAccountDeprovisioningEnabled$, + userIsManagedByOrganization$, + ]).pipe( + map( + ([isAccountDeprovisioningEnabled, userIsManagedByOrganization]) => + !isAccountDeprovisioningEnabled || !userIsManagedByOrganization, + ), + ); } async deauthorizeSessions() { From c96b4f4cb263154479c3a002f32a946ded79493d Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 4 Nov 2024 11:42:34 -0500 Subject: [PATCH 11/21] [deps] Autofill: Update tldts to v6.1.58 (#11847) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- apps/cli/package.json | 2 +- package-lock.json | 18 +++++++++--------- package.json | 2 +- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/apps/cli/package.json b/apps/cli/package.json index dcba6707fdf..622c1273823 100644 --- a/apps/cli/package.json +++ b/apps/cli/package.json @@ -80,7 +80,7 @@ "papaparse": "5.4.1", "proper-lockfile": "4.1.2", "rxjs": "7.8.1", - "tldts": "6.1.56", + "tldts": "6.1.58", "zxcvbn": "4.4.2" } } diff --git a/package-lock.json b/package-lock.json index 8ba595c53dc..03ab0f9987d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -68,7 +68,7 @@ "qrious": "4.0.2", "rxjs": "7.8.1", "tabbable": "6.2.0", - "tldts": "6.1.56", + "tldts": "6.1.58", "utf-8-validate": "6.0.4", "zone.js": "0.13.3", "zxcvbn": "4.4.2" @@ -224,7 +224,7 @@ "papaparse": "5.4.1", "proper-lockfile": "4.1.2", "rxjs": "7.8.1", - "tldts": "6.1.56", + "tldts": "6.1.58", "zxcvbn": "4.4.2" }, "bin": { @@ -36366,21 +36366,21 @@ } }, "node_modules/tldts": { - "version": "6.1.56", - "resolved": "https://registry.npmjs.org/tldts/-/tldts-6.1.56.tgz", - "integrity": "sha512-2PT1oRZCxtsbLi5R2SQjE/v4vvgRggAtVcYj+3Rrcnu2nPZvu7m64+gDa/EsVSWd3QzEc0U0xN+rbEKsJC47kA==", + "version": "6.1.58", + "resolved": "https://registry.npmjs.org/tldts/-/tldts-6.1.58.tgz", + "integrity": "sha512-MQJrJhjHOYGYb8DobR6Y4AdDbd4TYkyQ+KBDVc5ODzs1cbrvPpfN1IemYi9jfipJ/vR1YWvrDli0hg1y19VRoA==", "license": "MIT", "dependencies": { - "tldts-core": "^6.1.56" + "tldts-core": "^6.1.58" }, "bin": { "tldts": "bin/cli.js" } }, "node_modules/tldts-core": { - "version": "6.1.56", - "resolved": "https://registry.npmjs.org/tldts-core/-/tldts-core-6.1.56.tgz", - "integrity": "sha512-Ihxv/Bwiyj73icTYVgBUkQ3wstlCglLoegSgl64oSrGUBX1hc7Qmf/CnrnJLaQdZrCnTaLqMYOwKMKlkfkFrxQ==", + "version": "6.1.58", + "resolved": "https://registry.npmjs.org/tldts-core/-/tldts-core-6.1.58.tgz", + "integrity": "sha512-dR936xmhBm7AeqHIhCWwK765gZ7dFyL+IqLSFAjJbFlUXGMLCb8i2PzlzaOuWBuplBTaBYseSb565nk/ZEM0Bg==", "license": "MIT" }, "node_modules/tmp": { diff --git a/package.json b/package.json index ef48d31c0a7..f73c2c48890 100644 --- a/package.json +++ b/package.json @@ -201,7 +201,7 @@ "qrious": "4.0.2", "rxjs": "7.8.1", "tabbable": "6.2.0", - "tldts": "6.1.56", + "tldts": "6.1.58", "utf-8-validate": "6.0.4", "zone.js": "0.13.3", "zxcvbn": "4.4.2" From cd79457349490ddac576734be2637cc82d07c085 Mon Sep 17 00:00:00 2001 From: Oscar Hinton Date: Mon, 4 Nov 2024 17:51:43 +0100 Subject: [PATCH 12/21] [PM-4347] Upgrade angular to 17 (#11031) Upgrade angular to 17 --- angular.json | 4 +- apps/web/src/polyfills.ts | 3 +- .../default-active-user-state.spec.ts | 3 +- .../src/platform/state/key-definition.spec.ts | 3 +- .../src/vault/models/domain/login.spec.ts | 3 +- libs/components/src/item/item.mdx | 2 +- libs/components/src/item/item.stories.ts | 18 +- package-lock.json | 11411 ++++++---------- package.json | 45 +- 9 files changed, 4304 insertions(+), 7188 deletions(-) diff --git a/angular.json b/angular.json index 1670491b6fd..7053050262e 100644 --- a/angular.json +++ b/angular.json @@ -128,10 +128,10 @@ "builder": "@angular-devkit/build-angular:dev-server", "configurations": { "production": { - "browserTarget": "test-storybook:build:production" + "buildTarget": "test-storybook:build:production" }, "development": { - "browserTarget": "test-storybook:build:development" + "buildTarget": "test-storybook:build:development" } }, "defaultConfiguration": "development" diff --git a/apps/web/src/polyfills.ts b/apps/web/src/polyfills.ts index cc26cd13ab7..33af553f786 100644 --- a/apps/web/src/polyfills.ts +++ b/apps/web/src/polyfills.ts @@ -1,10 +1,9 @@ import "core-js/stable"; -require("zone.js/dist/zone"); +import "zone.js"; if (process.env.NODE_ENV === "production") { // Production } else { // Development and test Error["stackTraceLimit"] = Infinity; - require("zone.js/dist/long-stack-trace-zone"); } diff --git a/libs/common/src/platform/state/implementations/default-active-user-state.spec.ts b/libs/common/src/platform/state/implementations/default-active-user-state.spec.ts index 99cc785f9ba..b73415d6b79 100644 --- a/libs/common/src/platform/state/implementations/default-active-user-state.spec.ts +++ b/libs/common/src/platform/state/implementations/default-active-user-state.spec.ts @@ -220,7 +220,8 @@ describe("DefaultActiveUserState", () => { it("should not emit a previous users value if that user is no longer active", async () => { const user1Data: Jsonify = { date: "2020-09-21T13:14:17.648Z", - array: ["value"], + // NOTE: `as any` is here until we migrate to Nx: https://bitwarden.atlassian.net/browse/PM-6493 + array: ["value"] as any, }; const user2Data: Jsonify = { date: "2020-09-21T13:14:17.648Z", diff --git a/libs/common/src/platform/state/key-definition.spec.ts b/libs/common/src/platform/state/key-definition.spec.ts index 4eed0384811..3406a4e9014 100644 --- a/libs/common/src/platform/state/key-definition.spec.ts +++ b/libs/common/src/platform/state/key-definition.spec.ts @@ -192,7 +192,8 @@ describe("KeyDefinition", () => { expect(arrayDefinition).toBeTruthy(); expect(arrayDefinition.deserializer).toBeTruthy(); - const deserializedValue = arrayDefinition.deserializer([false, true]); + // NOTE: `as any` is here until we migrate to Nx: https://bitwarden.atlassian.net/browse/PM-6493 + const deserializedValue = arrayDefinition.deserializer([false, true] as any); expect(deserializedValue).toBeTruthy(); expect(deserializedValue).toHaveLength(2); diff --git a/libs/common/src/vault/models/domain/login.spec.ts b/libs/common/src/vault/models/domain/login.spec.ts index e420a953e68..4f9e4546220 100644 --- a/libs/common/src/vault/models/domain/login.spec.ts +++ b/libs/common/src/vault/models/domain/login.spec.ts @@ -151,6 +151,7 @@ describe("Login DTO", () => { password: "myPassword" as EncryptedString, passwordRevisionDate: passwordRevisionDate.toISOString(), totp: "myTotp" as EncryptedString, + // NOTE: `as any` is here until we migrate to Nx: https://bitwarden.atlassian.net/browse/PM-6493 fido2Credentials: [ { credentialId: "keyId" as EncryptedString, @@ -167,7 +168,7 @@ describe("Login DTO", () => { discoverable: "discoverable" as EncryptedString, creationDate: fido2CreationDate.toISOString(), }, - ], + ] as any, }); expect(actual).toEqual({ diff --git a/libs/components/src/item/item.mdx b/libs/components/src/item/item.mdx index b5c7da80baa..ca697ebb436 100644 --- a/libs/components/src/item/item.mdx +++ b/libs/components/src/item/item.mdx @@ -71,7 +71,7 @@ The content can be a button, anchor, or static container. @@ -50,7 +52,15 @@ class="tw-grow" [formControl]="searchControl" > - diff --git a/apps/web/src/app/tools/access-intelligence/all-applications.component.ts b/apps/web/src/app/tools/access-intelligence/all-applications.component.ts index 245314673a5..1b648567df2 100644 --- a/apps/web/src/app/tools/access-intelligence/all-applications.component.ts +++ b/apps/web/src/app/tools/access-intelligence/all-applications.component.ts @@ -40,6 +40,7 @@ export class AllApplicationsComponent implements OnInit { protected loading = false; protected organization: Organization; noItemsIcon = Icons.Security; + protected markingAsCritical = false; // MOCK DATA protected mockData = applicationTableMockData; @@ -76,8 +77,18 @@ export class AllApplicationsComponent implements OnInit { .subscribe((v) => (this.dataSource.filter = v)); } + goToCreateNewLoginItem = async () => { + // TODO: implement + this.toastService.showToast({ + variant: "warning", + title: null, + message: "Not yet implemented", + }); + }; + markAppsAsCritical = async () => { // TODO: Send to API once implemented + this.markingAsCritical = true; return new Promise((resolve) => { setTimeout(() => { this.selectedIds.clear(); @@ -87,6 +98,7 @@ export class AllApplicationsComponent implements OnInit { message: this.i18nService.t("appsMarkedAsCritical"), }); resolve(true); + this.markingAsCritical = false; }, 1000); }); }; diff --git a/apps/web/src/app/tools/access-intelligence/critical-applications.component.html b/apps/web/src/app/tools/access-intelligence/critical-applications.component.html index e03988fbf9e..1c503f3d786 100644 --- a/apps/web/src/app/tools/access-intelligence/critical-applications.component.html +++ b/apps/web/src/app/tools/access-intelligence/critical-applications.component.html @@ -19,7 +19,9 @@

- + diff --git a/apps/web/src/app/tools/access-intelligence/critical-applications.component.ts b/apps/web/src/app/tools/access-intelligence/critical-applications.component.ts index 545ba14d21c..a5df519fd80 100644 --- a/apps/web/src/app/tools/access-intelligence/critical-applications.component.ts +++ b/apps/web/src/app/tools/access-intelligence/critical-applications.component.ts @@ -1,7 +1,7 @@ import { Component, DestroyRef, inject, OnInit } from "@angular/core"; import { takeUntilDestroyed } from "@angular/core/rxjs-interop"; import { FormControl } from "@angular/forms"; -import { ActivatedRoute } from "@angular/router"; +import { ActivatedRoute, Router } from "@angular/router"; import { debounceTime, map } from "rxjs"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; @@ -12,6 +12,7 @@ import { HeaderModule } from "../../layouts/header/header.module"; import { SharedModule } from "../../shared"; import { PipesModule } from "../../vault/individual-vault/pipes/pipes.module"; +import { AccessIntelligenceTabType } from "./access-intelligence.component"; import { applicationTableMockData } from "./application-table.mock"; @Component({ @@ -26,8 +27,10 @@ export class CriticalApplicationsComponent implements OnInit { protected searchControl = new FormControl("", { nonNullable: true }); private destroyRef = inject(DestroyRef); protected loading = false; + protected organizationId: string; noItemsIcon = Icons.Security; // MOCK DATA + protected mockData = applicationTableMockData; protected mockAtRiskMembersCount = 0; protected mockAtRiskAppsCount = 0; protected mockTotalMembersCount = 0; @@ -38,18 +41,26 @@ export class CriticalApplicationsComponent implements OnInit { .pipe( takeUntilDestroyed(this.destroyRef), map(async (params) => { - // const organizationId = params.get("organizationId"); + this.organizationId = params.get("organizationId"); // TODO: use organizationId to fetch data }), ) .subscribe(); } + goToAllAppsTab = async () => { + await this.router.navigate([`organizations/${this.organizationId}/access-intelligence`], { + queryParams: { tabIndex: AccessIntelligenceTabType.AllApps }, + queryParamsHandling: "merge", + }); + }; + constructor( protected i18nService: I18nService, protected activatedRoute: ActivatedRoute, + protected router: Router, ) { - this.dataSource.data = applicationTableMockData; + this.dataSource.data = []; //applicationTableMockData; this.searchControl.valueChanges .pipe(debounceTime(200), takeUntilDestroyed()) .subscribe((v) => (this.dataSource.filter = v)); From fc9c10340bb4c99f0ea225328dcc1c581c590b67 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 4 Nov 2024 21:08:36 +0100 Subject: [PATCH 15/21] [deps] Tools: Update utf-8-validate to v6.0.5 (#11848) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package-lock.json | 10 ++++++---- package.json | 2 +- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index 624bceaf25e..8994cfcd373 100644 --- a/package-lock.json +++ b/package-lock.json @@ -69,7 +69,7 @@ "rxjs": "7.8.1", "tabbable": "6.2.0", "tldts": "6.1.58", - "utf-8-validate": "6.0.4", + "utf-8-validate": "6.0.5", "zone.js": "0.14.10", "zxcvbn": "4.4.2" }, @@ -319,6 +319,7 @@ "license": "GPL-3.0" }, "libs/tools/export/vault-export/vault-export-core": { + "name": "@bitwarden/vault-export-core", "version": "0.0.0", "license": "GPL-3.0", "dependencies": { @@ -34702,10 +34703,11 @@ } }, "node_modules/utf-8-validate": { - "version": "6.0.4", - "resolved": "https://registry.npmjs.org/utf-8-validate/-/utf-8-validate-6.0.4.tgz", - "integrity": "sha512-xu9GQDeFp+eZ6LnCywXN/zBancWvOpUMzgjLPSjy4BRHSmTelvn2E0DG0o1sTiw5hkCKBHo8rwSKncfRfv2EEQ==", + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/utf-8-validate/-/utf-8-validate-6.0.5.tgz", + "integrity": "sha512-EYZR+OpIXp9Y1eG1iueg8KRsY8TuT8VNgnanZ0uA3STqhHQTLwbl+WX76/9X5OY12yQubymBpaBSmMPkSTQcKA==", "hasInstallScript": true, + "license": "MIT", "dependencies": { "node-gyp-build": "^4.3.0" }, diff --git a/package.json b/package.json index 6f66663ea1e..9b38df0c061 100644 --- a/package.json +++ b/package.json @@ -203,7 +203,7 @@ "rxjs": "7.8.1", "tabbable": "6.2.0", "tldts": "6.1.58", - "utf-8-validate": "6.0.4", + "utf-8-validate": "6.0.5", "zone.js": "0.14.10", "zxcvbn": "4.4.2" }, From 008e928d0a49289f7687e740e5bdba320b0eb54d Mon Sep 17 00:00:00 2001 From: Justin Baur <19896123+justindbaur@users.noreply.github.com> Date: Mon, 4 Nov 2024 15:10:36 -0500 Subject: [PATCH 16/21] [PM-10744] Remove Last Uses of `getBgService` (#10947) * Remove Last Uses of `getBgService` * Fix Merge Issue * Fix Merge --- .../browser/src/background/main.background.ts | 491 ++++++++---------- .../src/popup/services/services.module.ts | 105 ++-- 2 files changed, 262 insertions(+), 334 deletions(-) diff --git a/apps/browser/src/background/main.background.ts b/apps/browser/src/background/main.background.ts index 27d83af1321..fb92ebe04ae 100644 --- a/apps/browser/src/background/main.background.ts +++ b/apps/browser/src/background/main.background.ts @@ -257,12 +257,9 @@ import { BrowserPlatformUtilsService } from "../platform/services/platform-utils import { PopupViewCacheBackgroundService } from "../platform/services/popup-view-cache-background.service"; import { BrowserSdkClientFactory } from "../platform/services/sdk/browser-sdk-client-factory"; import { BackgroundTaskSchedulerService } from "../platform/services/task-scheduler/background-task-scheduler.service"; -import { ForegroundTaskSchedulerService } from "../platform/services/task-scheduler/foreground-task-scheduler.service"; import { BackgroundMemoryStorageService } from "../platform/storage/background-memory-storage.service"; import { BrowserStorageServiceProvider } from "../platform/storage/browser-storage-service.provider"; -import { ForegroundMemoryStorageService } from "../platform/storage/foreground-memory-storage.service"; import { OffscreenStorageService } from "../platform/storage/offscreen-storage.service"; -import { ForegroundSyncService } from "../platform/sync/foreground-sync.service"; import { SyncServiceListener } from "../platform/sync/sync-service.listener"; import { fromChromeRuntimeMessaging } from "../platform/utils/from-chrome-runtime-messaging"; import VaultTimeoutService from "../services/vault-timeout/vault-timeout.service"; @@ -401,7 +398,7 @@ export default class MainBackground { private popupViewCacheBackgroundService: PopupViewCacheBackgroundService; - constructor(public popupOnlyContext: boolean = false) { + constructor() { // Services const lockedCallback = async (userId?: string) => { if (this.notificationsService != null) { @@ -460,45 +457,6 @@ export default class MainBackground { this.offscreenDocumentService, ); - // Creates a session key for mv3 storage of large memory items - const sessionKey = new Lazy(async () => { - // Key already in session storage - const sessionStorage = new BrowserMemoryStorageService(); - const existingKey = await sessionStorage.get("session-key"); - if (existingKey) { - if (sessionStorage.valuesRequireDeserialization) { - return SymmetricCryptoKey.fromJSON(existingKey); - } - return existingKey; - } - - // New key - const { derivedKey } = await this.keyGenerationService.createKeyWithPurpose( - 128, - "ephemeral", - "bitwarden-ephemeral", - ); - await sessionStorage.save("session-key", derivedKey); - return derivedKey; - }); - - const mv3MemoryStorageCreator = () => { - if (this.popupOnlyContext) { - return new ForegroundMemoryStorageService(); - } - - // For local backed session storage, we expect that the encrypted data on disk will persist longer than the encryption key in memory - // and failures to decrypt because of that are completely expected. For this reason, we pass in `false` to the `EncryptServiceImplementation` - // so that MAC failures are not logged. - return new LocalBackedSessionStorageService( - sessionKey, - this.storageService, - new EncryptServiceImplementation(this.cryptoFunctionService, this.logService, false), - this.platformUtilsService, - this.logService, - ); - }; - this.secureStorageService = this.storageService; // secure storage is not supported in browsers, so we use local storage and warn users when it is used if (BrowserApi.isManifestVersion(3)) { @@ -506,18 +464,47 @@ export default class MainBackground { this.memoryStorageForStateProviders = new BrowserMemoryStorageService(); // mv3 stores to storage.session this.memoryStorageService = this.memoryStorageForStateProviders; } else { - if (popupOnlyContext) { - this.memoryStorageForStateProviders = new ForegroundMemoryStorageService(); - this.memoryStorageService = new ForegroundMemoryStorageService(); - } else { - this.memoryStorageForStateProviders = new BackgroundMemoryStorageService(); // mv2 stores to memory - this.memoryStorageService = this.memoryStorageForStateProviders; - } + this.memoryStorageForStateProviders = new BackgroundMemoryStorageService(); // mv2 stores to memory + this.memoryStorageService = this.memoryStorageForStateProviders; } - this.largeObjectMemoryStorageForStateProviders = BrowserApi.isManifestVersion(3) - ? mv3MemoryStorageCreator() // mv3 stores to local-backed session storage - : this.memoryStorageForStateProviders; // mv2 stores to the same location + if (BrowserApi.isManifestVersion(3)) { + // Creates a session key for mv3 storage of large memory items + const sessionKey = new Lazy(async () => { + // Key already in session storage + const sessionStorage = new BrowserMemoryStorageService(); + const existingKey = await sessionStorage.get("session-key"); + if (existingKey) { + if (sessionStorage.valuesRequireDeserialization) { + return SymmetricCryptoKey.fromJSON(existingKey); + } + return existingKey; + } + + // New key + const { derivedKey } = await this.keyGenerationService.createKeyWithPurpose( + 128, + "ephemeral", + "bitwarden-ephemeral", + ); + await sessionStorage.save("session-key", derivedKey); + return derivedKey; + }); + + this.largeObjectMemoryStorageForStateProviders = new LocalBackedSessionStorageService( + sessionKey, + this.storageService, + // For local backed session storage, we expect that the encrypted data on disk will persist longer than the encryption key in memory + // and failures to decrypt because of that are completely expected. For this reason, we pass in `false` to the `EncryptServiceImplementation` + // so that MAC failures are not logged. + new EncryptServiceImplementation(this.cryptoFunctionService, this.logService, false), + this.platformUtilsService, + this.logService, + ); + } else { + // mv2 stores to the same location + this.largeObjectMemoryStorageForStateProviders = this.memoryStorageForStateProviders; + } const localStorageStorageService = BrowserApi.isManifestVersion(3) ? new OffscreenStorageService(this.offscreenDocumentService) @@ -575,9 +562,10 @@ export default class MainBackground { this.derivedStateProvider, ); - this.taskSchedulerService = this.popupOnlyContext - ? new ForegroundTaskSchedulerService(this.logService, this.stateProvider) - : new BackgroundTaskSchedulerService(this.logService, this.stateProvider); + this.taskSchedulerService = new BackgroundTaskSchedulerService( + this.logService, + this.stateProvider, + ); this.taskSchedulerService.registerTaskHandler(ScheduledTaskNames.scheduleNextSyncInterval, () => this.fullSync(), ); @@ -873,26 +861,24 @@ export default class MainBackground { this.vaultSettingsService = new VaultSettingsService(this.stateProvider); - if (!this.popupOnlyContext) { - this.vaultTimeoutService = new VaultTimeoutService( - this.accountService, - this.masterPasswordService, - this.cipherService, - this.folderService, - this.collectionService, - this.platformUtilsService, - this.messagingService, - this.searchService, - this.stateService, - this.authService, - this.vaultTimeoutSettingsService, - this.stateEventRunnerService, - this.taskSchedulerService, - this.logService, - lockedCallback, - logoutCallback, - ); - } + this.vaultTimeoutService = new VaultTimeoutService( + this.accountService, + this.masterPasswordService, + this.cipherService, + this.folderService, + this.collectionService, + this.platformUtilsService, + this.messagingService, + this.searchService, + this.stateService, + this.authService, + this.vaultTimeoutSettingsService, + this.stateEventRunnerService, + this.taskSchedulerService, + this.logService, + lockedCallback, + logoutCallback, + ); this.containerService = new ContainerService(this.keyService, this.encryptService); this.sendStateProvider = new SendStateProvider(this.stateProvider); @@ -913,59 +899,41 @@ export default class MainBackground { this.providerService = new ProviderService(this.stateProvider); - if (this.popupOnlyContext) { - this.syncService = new ForegroundSyncService( - this.stateService, - this.folderService, - this.folderApiService, - this.messagingService, - this.logService, - this.cipherService, - this.collectionService, - this.apiService, - this.accountService, - this.authService, - this.sendService, - this.sendApiService, - messageListener, - this.stateProvider, - ); - } else { - this.syncService = new DefaultSyncService( - this.masterPasswordService, - this.accountService, - this.apiService, - this.domainSettingsService, - this.folderService, - this.cipherService, - this.keyService, - this.collectionService, - this.messagingService, - this.policyService, - this.sendService, - this.logService, - this.keyConnectorService, - this.stateService, - this.providerService, - this.folderApiService, - this.organizationService, - this.sendApiService, - this.userDecryptionOptionsService, - this.avatarService, - logoutCallback, - this.billingAccountProfileStateService, - this.tokenService, - this.authService, - this.stateProvider, - ); + this.syncService = new DefaultSyncService( + this.masterPasswordService, + this.accountService, + this.apiService, + this.domainSettingsService, + this.folderService, + this.cipherService, + this.keyService, + this.collectionService, + this.messagingService, + this.policyService, + this.sendService, + this.logService, + this.keyConnectorService, + this.stateService, + this.providerService, + this.folderApiService, + this.organizationService, + this.sendApiService, + this.userDecryptionOptionsService, + this.avatarService, + logoutCallback, + this.billingAccountProfileStateService, + this.tokenService, + this.authService, + this.stateProvider, + ); + + this.syncServiceListener = new SyncServiceListener( + this.syncService, + messageListener, + this.messagingService, + this.logService, + ); - this.syncServiceListener = new SyncServiceListener( - this.syncService, - messageListener, - this.messagingService, - this.logService, - ); - } this.eventUploadService = new EventUploadService( this.apiService, this.stateProvider, @@ -1112,122 +1080,128 @@ export default class MainBackground { this.isSafari = this.platformUtilsService.isSafari(); // Background - if (!this.popupOnlyContext) { - this.fido2Background = new Fido2Background( - this.logService, - this.fido2ActiveRequestManager, - this.fido2ClientService, - this.vaultSettingsService, - this.scriptInjectorService, - this.configService, - this.authService, - ); - const lockService = new DefaultLockService(this.accountService, this.vaultTimeoutService); + this.fido2Background = new Fido2Background( + this.logService, + this.fido2ActiveRequestManager, + this.fido2ClientService, + this.vaultSettingsService, + this.scriptInjectorService, + this.configService, + this.authService, + ); - this.runtimeBackground = new RuntimeBackground( - this, - this.autofillService, - this.platformUtilsService as BrowserPlatformUtilsService, - this.notificationsService, - this.autofillSettingsService, - this.processReloadService, - this.environmentService, - this.messagingService, - this.logService, - this.configService, - messageListener, - this.accountService, - lockService, - ); - this.nativeMessagingBackground = new NativeMessagingBackground( - this.keyService, - this.encryptService, - this.cryptoFunctionService, - this.runtimeBackground, - this.messagingService, - this.appIdService, - this.platformUtilsService, - this.logService, - this.authService, - this.biometricStateService, - this.accountService, - ); - this.commandsBackground = new CommandsBackground( - this, - this.platformUtilsService, - this.vaultTimeoutService, - this.authService, - () => this.generatePasswordToClipboard(), - ); - this.notificationBackground = new NotificationBackground( - this.autofillService, - this.cipherService, - this.authService, - this.policyService, - this.folderService, - this.userNotificationSettingsService, - this.domainSettingsService, - this.environmentService, - this.logService, - this.themeStateService, - this.configService, - this.accountService, - ); + const lockService = new DefaultLockService(this.accountService, this.vaultTimeoutService); - this.overlayNotificationsBackground = new OverlayNotificationsBackground( - this.logService, - this.configService, - this.notificationBackground, - ); + this.runtimeBackground = new RuntimeBackground( + this, + this.autofillService, + this.platformUtilsService as BrowserPlatformUtilsService, + this.notificationsService, + this.autofillSettingsService, + this.processReloadService, + this.environmentService, + this.messagingService, + this.logService, + this.configService, + messageListener, + this.accountService, + lockService, + ); + this.nativeMessagingBackground = new NativeMessagingBackground( + this.keyService, + this.encryptService, + this.cryptoFunctionService, + this.runtimeBackground, + this.messagingService, + this.appIdService, + this.platformUtilsService, + this.logService, + this.authService, + this.biometricStateService, + this.accountService, + ); + this.commandsBackground = new CommandsBackground( + this, + this.platformUtilsService, + this.vaultTimeoutService, + this.authService, + () => this.generatePasswordToClipboard(), + ); + this.notificationBackground = new NotificationBackground( + this.autofillService, + this.cipherService, + this.authService, + this.policyService, + this.folderService, + this.userNotificationSettingsService, + this.domainSettingsService, + this.environmentService, + this.logService, + this.themeStateService, + this.configService, + this.accountService, + ); - this.filelessImporterBackground = new FilelessImporterBackground( - this.configService, - this.authService, - this.policyService, - this.notificationBackground, - this.importService, - this.syncService, - this.scriptInjectorService, - ); + this.overlayNotificationsBackground = new OverlayNotificationsBackground( + this.logService, + this.configService, + this.notificationBackground, + ); - this.autoSubmitLoginBackground = new AutoSubmitLoginBackground( - this.logService, - this.autofillService, - this.scriptInjectorService, - this.authService, - this.configService, - this.platformUtilsService, - this.policyService, - ); + this.filelessImporterBackground = new FilelessImporterBackground( + this.configService, + this.authService, + this.policyService, + this.notificationBackground, + this.importService, + this.syncService, + this.scriptInjectorService, + ); - const contextMenuClickedHandler = new ContextMenuClickedHandler( - (options) => this.platformUtilsService.copyToClipboard(options.text), - async () => this.generatePasswordToClipboard(), - async (tab, cipher) => { - this.loginToAutoFill = cipher; - if (tab == null) { - return; - } + this.autoSubmitLoginBackground = new AutoSubmitLoginBackground( + this.logService, + this.autofillService, + this.scriptInjectorService, + this.authService, + this.configService, + this.platformUtilsService, + this.policyService, + ); - // FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling. - // eslint-disable-next-line @typescript-eslint/no-floating-promises - BrowserApi.tabSendMessage(tab, { - command: "collectPageDetails", - tab: tab, - sender: "contextMenu", - }); - }, - this.authService, - this.cipherService, - this.totpService, - this.eventCollectionService, - this.userVerificationService, - this.accountService, - ); + const contextMenuClickedHandler = new ContextMenuClickedHandler( + (options) => this.platformUtilsService.copyToClipboard(options.text), + async (_tab) => { + const options = (await this.passwordGenerationService.getOptions())?.[0] ?? {}; + const password = await this.passwordGenerationService.generatePassword(options); + this.platformUtilsService.copyToClipboard(password); + // FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling. + // eslint-disable-next-line @typescript-eslint/no-floating-promises + this.passwordGenerationService.addHistory(password); + }, + async (tab, cipher) => { + this.loginToAutoFill = cipher; + if (tab == null) { + return; + } - this.contextMenusBackground = new ContextMenusBackground(contextMenuClickedHandler); - } + // FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling. + // eslint-disable-next-line @typescript-eslint/no-floating-promises + BrowserApi.tabSendMessage(tab, { + command: "collectPageDetails", + tab: tab, + sender: "contextMenu", + }); + }, + this.authService, + this.cipherService, + this.totpService, + this.eventCollectionService, + this.userVerificationService, + this.accountService, + ); + + this.contextMenusBackground = new ContextMenusBackground(contextMenuClickedHandler); this.idleBackground = new IdleBackground( this.vaultTimeoutService, @@ -1246,29 +1220,27 @@ export default class MainBackground { this.stateProvider, ); - if (!this.popupOnlyContext) { - this.mainContextMenuHandler = new MainContextMenuHandler( - this.stateService, - this.autofillSettingsService, - this.i18nService, - this.logService, - this.billingAccountProfileStateService, - ); + this.mainContextMenuHandler = new MainContextMenuHandler( + this.stateService, + this.autofillSettingsService, + this.i18nService, + this.logService, + this.billingAccountProfileStateService, + ); - this.cipherContextMenuHandler = new CipherContextMenuHandler( - this.mainContextMenuHandler, - this.authService, + this.cipherContextMenuHandler = new CipherContextMenuHandler( + this.mainContextMenuHandler, + this.authService, + this.cipherService, + ); + + if (chrome.webRequest != null && chrome.webRequest.onAuthRequired != null) { + this.webRequestBackground = new WebRequestBackground( + this.platformUtilsService, this.cipherService, + this.authService, + chrome.webRequest, ); - - if (chrome.webRequest != null && chrome.webRequest.onAuthRequired != null) { - this.webRequestBackground = new WebRequestBackground( - this.platformUtilsService, - this.cipherService, - this.authService, - chrome.webRequest, - ); - } } this.userAutoUnlockKeyService = new UserAutoUnlockKeyService(this.keyService); @@ -1283,7 +1255,7 @@ export default class MainBackground { this.containerService.attachToGlobal(self); // Only the "true" background should run migrations - await this.stateService.init({ runMigrations: !this.popupOnlyContext }); + await this.stateService.init({ runMigrations: true }); // This is here instead of in in the InitService b/c we don't plan for // side effects to run in the Browser InitService. @@ -1305,10 +1277,6 @@ export default class MainBackground { this.popupViewCacheBackgroundService.startObservingTabChanges(); - if (this.popupOnlyContext) { - return; - } - await this.vaultTimeoutService.init(true); this.fido2Background.init(); await this.runtimeBackground.init(); @@ -1637,7 +1605,6 @@ export default class MainBackground { */ async initOverlayAndTabsBackground() { if ( - this.popupOnlyContext || this.overlayBackground || this.tabsBackground || (await firstValueFrom(this.authService.activeAccountStatus$)) === diff --git a/apps/browser/src/popup/services/services.module.ts b/apps/browser/src/popup/services/services.module.ts index 14ebfb4a175..6ef0c278dc3 100644 --- a/apps/browser/src/popup/services/services.module.ts +++ b/apps/browser/src/popup/services/services.module.ts @@ -24,8 +24,8 @@ import { LockComponentService, } from "@bitwarden/auth/angular"; import { LockService, LoginEmailService, PinServiceAbstraction } from "@bitwarden/auth/common"; +import { ApiService } from "@bitwarden/common/abstractions/api.service"; import { EventCollectionService as EventCollectionServiceAbstraction } from "@bitwarden/common/abstractions/event/event-collection.service"; -import { NotificationsService } from "@bitwarden/common/abstractions/notifications.service"; import { VaultTimeoutService } from "@bitwarden/common/abstractions/vault-timeout/vault-timeout.service"; import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction"; import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction"; @@ -92,9 +92,15 @@ import { InlineDerivedStateProvider } from "@bitwarden/common/platform/state/imp import { PrimarySecondaryStorageService } from "@bitwarden/common/platform/storage/primary-secondary-storage.service"; import { WindowStorageService } from "@bitwarden/common/platform/storage/window-storage.service"; import { SyncService } from "@bitwarden/common/platform/sync"; +import { SendApiService } from "@bitwarden/common/tools/send/services/send-api.service.abstraction"; +import { InternalSendService } from "@bitwarden/common/tools/send/services/send.service.abstraction"; import { VaultTimeoutStringType } from "@bitwarden/common/types/vault-timeout.type"; import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service"; -import { FolderService as FolderServiceAbstraction } from "@bitwarden/common/vault/abstractions/folder/folder.service.abstraction"; +import { FolderApiServiceAbstraction } from "@bitwarden/common/vault/abstractions/folder/folder-api.service.abstraction"; +import { + FolderService as FolderServiceAbstraction, + InternalFolderService, +} from "@bitwarden/common/vault/abstractions/folder/folder.service.abstraction"; import { TotpService as TotpServiceAbstraction } from "@bitwarden/common/vault/abstractions/totp.service"; import { TotpService } from "@bitwarden/common/vault/services/totp.service"; import { DialogService, ToastService } from "@bitwarden/components"; @@ -107,7 +113,6 @@ import { ExtensionAnonLayoutWrapperDataService } from "../../auth/popup/extensio import { ExtensionLoginComponentService } from "../../auth/popup/login/extension-login-component.service"; import { AutofillService as AutofillServiceAbstraction } from "../../autofill/services/abstractions/autofill.service"; import AutofillService from "../../autofill/services/autofill.service"; -import MainBackground from "../../background/main.background"; import { ForegroundBrowserBiometricsService } from "../../key-management/biometrics/foreground-browser-biometrics"; import { BrowserKeyService } from "../../key-management/browser-key.service"; import { BrowserApi } from "../../platform/browser/browser-api"; @@ -117,12 +122,12 @@ import { ChromeMessageSender } from "../../platform/messaging/chrome-message.sen /* eslint-enable no-restricted-imports */ import { OffscreenDocumentService } from "../../platform/offscreen-document/abstractions/offscreen-document"; import { DefaultOffscreenDocumentService } from "../../platform/offscreen-document/offscreen-document.service"; -import BrowserPopupUtils from "../../platform/popup/browser-popup-utils"; import { BrowserFileDownloadService } from "../../platform/popup/services/browser-file-download.service"; import { PopupViewCacheService } from "../../platform/popup/view-cache/popup-view-cache.service"; import { ScriptInjectorService } from "../../platform/services/abstractions/script-injector.service"; import { BrowserEnvironmentService } from "../../platform/services/browser-environment.service"; import BrowserLocalStorageService from "../../platform/services/browser-local-storage.service"; +import BrowserMemoryStorageService from "../../platform/services/browser-memory-storage.service"; import { BrowserScriptInjectorService } from "../../platform/services/browser-script-injector.service"; import I18nService from "../../platform/services/i18n.service"; import { ForegroundPlatformUtilsService } from "../../platform/services/platform-utils/foreground-platform-utils.service"; @@ -130,6 +135,7 @@ import { BrowserSdkClientFactory } from "../../platform/services/sdk/browser-sdk import { ForegroundTaskSchedulerService } from "../../platform/services/task-scheduler/foreground-task-scheduler.service"; import { BrowserStorageServiceProvider } from "../../platform/storage/browser-storage-service.provider"; import { ForegroundMemoryStorageService } from "../../platform/storage/foreground-memory-storage.service"; +import { ForegroundSyncService } from "../../platform/sync/foreground-sync.service"; import { fromChromeRuntimeMessaging } from "../../platform/utils/from-chrome-runtime-messaging"; import { ExtensionLockComponentService } from "../../services/extension-lock-component.service"; import { ForegroundVaultTimeoutService } from "../../services/vault-timeout/foreground-vault-timeout.service"; @@ -151,26 +157,6 @@ const DISK_BACKUP_LOCAL_STORAGE = new SafeInjectionToken< AbstractStorageService & ObservableStorageService >("DISK_BACKUP_LOCAL_STORAGE"); -const needsBackgroundInit = BrowserPopupUtils.backgroundInitializationRequired(); -const mainBackground: MainBackground = needsBackgroundInit - ? createLocalBgService() - : BrowserApi.getBackgroundPage().bitwardenMain; - -function createLocalBgService() { - const localBgService = new MainBackground(true); - // FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling. - // eslint-disable-next-line @typescript-eslint/no-floating-promises - localBgService.bootstrap(); - return localBgService; -} - -/** @deprecated This method needs to be removed as part of MV3 conversion. Please do not add more and actively try to remove usages */ -function getBgService(service: keyof MainBackground) { - return (): T => { - return mainBackground ? (mainBackground[service] as any as T) : null; - }; -} - /** * Provider definitions used in the ngModule. * Add your provider definition here using the safeProvider function as a wrapper. This will give you type safety. @@ -307,8 +293,23 @@ const safeProviders: SafeProvider[] = [ }), safeProvider({ provide: SyncService, - useFactory: getBgService("syncService"), - deps: [], + useClass: ForegroundSyncService, + deps: [ + StateService, + InternalFolderService, + FolderApiServiceAbstraction, + MessageSender, + LogService, + CipherService, + CollectionService, + ApiService, + AccountServiceAbstraction, + AuthService, + InternalSendService, + SendApiService, + MessageListener, + StateProvider, + ], }), safeProvider({ provide: DomainSettingsService, @@ -358,11 +359,6 @@ const safeProviders: SafeProvider[] = [ useClass: ForegroundVaultTimeoutService, deps: [MessagingServiceAbstraction], }), - safeProvider({ - provide: NotificationsService, - useFactory: getBgService("notificationsService"), - deps: [], - }), safeProvider({ provide: VaultFilterService, useClass: VaultFilterService, @@ -382,8 +378,8 @@ const safeProviders: SafeProvider[] = [ }), safeProvider({ provide: MEMORY_STORAGE, - useFactory: getBgService("memoryStorageService"), - deps: [], + useFactory: (memoryStorage: AbstractStorageService) => memoryStorage, + deps: [OBSERVABLE_MEMORY_STORAGE], }), safeProvider({ provide: OBSERVABLE_MEMORY_STORAGE, @@ -392,9 +388,7 @@ const safeProviders: SafeProvider[] = [ return new ForegroundMemoryStorageService(); } - return getBgService( - "memoryStorageForStateProviders", - )(); + return new BrowserMemoryStorageService(); }, deps: [], }), @@ -407,9 +401,7 @@ const safeProviders: SafeProvider[] = [ return regularMemoryStorageService; } - return getBgService( - "largeObjectMemoryStorageForStateProviders", - )(); + return new ForegroundMemoryStorageService(); }, deps: [OBSERVABLE_MEMORY_STORAGE], }), @@ -494,15 +486,7 @@ const safeProviders: SafeProvider[] = [ }), safeProvider({ provide: INTRAPROCESS_MESSAGING_SUBJECT, - useFactory: () => { - if (BrowserPopupUtils.backgroundInitializationRequired()) { - // There is no persistent main background which means we have one in memory, - // we need the same instance that our in memory background is utilizing. - return getBgService("intraprocessMessagingSubject")(); - } else { - return new Subject>>(); - } - }, + useFactory: () => new Subject>>(), deps: [], }), safeProvider({ @@ -514,23 +498,6 @@ const safeProviders: SafeProvider[] = [ ), deps: [INTRAPROCESS_MESSAGING_SUBJECT, LogService], }), - safeProvider({ - provide: INTRAPROCESS_MESSAGING_SUBJECT, - useFactory: () => { - if (needsBackgroundInit) { - // We will have created a popup within this context, in that case - // we want to make sure we have the same subject as that context so we - // can message with it. - return getBgService("intraprocessMessagingSubject")(); - } else { - // There isn't a locally created background so we will communicate with - // the true background through chrome apis, in that case, we can just create - // one for ourself. - return new Subject>>(); - } - }, - deps: [], - }), safeProvider({ provide: DISK_BACKUP_LOCAL_STORAGE, useFactory: (diskStorage: AbstractStorageService & ObservableStorageService) => @@ -572,13 +539,7 @@ const safeProviders: SafeProvider[] = [ }), safeProvider({ provide: ForegroundTaskSchedulerService, - useFactory: (logService: LogService, stateProvider: StateProvider) => { - if (needsBackgroundInit) { - return getBgService("taskSchedulerService")(); - } - - return new ForegroundTaskSchedulerService(logService, stateProvider); - }, + useClass: ForegroundTaskSchedulerService, deps: [LogService, StateProvider], }), safeProvider({ From f41365ce485fc119ba0c8a4e490186b3d4a0c985 Mon Sep 17 00:00:00 2001 From: Justin Baur <19896123+justindbaur@users.noreply.github.com> Date: Mon, 4 Nov 2024 15:11:59 -0500 Subject: [PATCH 17/21] [PM-13673] Require UserId In CompareHash Method (#11568) * Require UserId In CompareHash Method * Throw on null-ish 'masterKey' * Update Test --- .../user-verification.service.spec.ts | 12 ++-- .../user-verification.service.ts | 3 +- .../src/abstractions/key.service.ts | 10 +++- libs/key-management/src/key.service.spec.ts | 59 +++++++++++++++++++ libs/key-management/src/key.service.ts | 53 ++++++++++------- .../components/password-reprompt.component.ts | 13 +++- 6 files changed, 117 insertions(+), 33 deletions(-) diff --git a/libs/common/src/auth/services/user-verification/user-verification.service.spec.ts b/libs/common/src/auth/services/user-verification/user-verification.service.spec.ts index 02cd6056efb..1538f571cfd 100644 --- a/libs/common/src/auth/services/user-verification/user-verification.service.spec.ts +++ b/libs/common/src/auth/services/user-verification/user-verification.service.spec.ts @@ -216,7 +216,7 @@ describe("UserVerificationService", () => { }); it("returns if verification is successful", async () => { - keyService.compareAndUpdateKeyHash.mockResolvedValueOnce(true); + keyService.compareKeyHash.mockResolvedValueOnce(true); const result = await sut.verifyUserByMasterPassword( { @@ -227,7 +227,7 @@ describe("UserVerificationService", () => { "email", ); - expect(keyService.compareAndUpdateKeyHash).toHaveBeenCalled(); + expect(keyService.compareKeyHash).toHaveBeenCalled(); expect(masterPasswordService.setMasterKeyHash).toHaveBeenCalledWith( "localHash", mockUserId, @@ -240,7 +240,7 @@ describe("UserVerificationService", () => { }); it("throws if verification fails", async () => { - keyService.compareAndUpdateKeyHash.mockResolvedValueOnce(false); + keyService.compareKeyHash.mockResolvedValueOnce(false); await expect( sut.verifyUserByMasterPassword( @@ -253,7 +253,7 @@ describe("UserVerificationService", () => { ), ).rejects.toThrow("Invalid master password"); - expect(keyService.compareAndUpdateKeyHash).toHaveBeenCalled(); + expect(keyService.compareKeyHash).toHaveBeenCalled(); expect(masterPasswordService.setMasterKeyHash).not.toHaveBeenCalledWith(); expect(masterPasswordService.setMasterKey).not.toHaveBeenCalledWith(); }); @@ -285,7 +285,7 @@ describe("UserVerificationService", () => { "email", ); - expect(keyService.compareAndUpdateKeyHash).not.toHaveBeenCalled(); + expect(keyService.compareKeyHash).not.toHaveBeenCalled(); expect(masterPasswordService.setMasterKeyHash).toHaveBeenCalledWith( "localHash", mockUserId, @@ -318,7 +318,7 @@ describe("UserVerificationService", () => { ), ).rejects.toThrow("Invalid master password"); - expect(keyService.compareAndUpdateKeyHash).not.toHaveBeenCalled(); + expect(keyService.compareKeyHash).not.toHaveBeenCalled(); expect(masterPasswordService.setMasterKeyHash).not.toHaveBeenCalledWith(); expect(masterPasswordService.setMasterKey).not.toHaveBeenCalledWith(); }); diff --git a/libs/common/src/auth/services/user-verification/user-verification.service.ts b/libs/common/src/auth/services/user-verification/user-verification.service.ts index b31ba59c983..5446558a540 100644 --- a/libs/common/src/auth/services/user-verification/user-verification.service.ts +++ b/libs/common/src/auth/services/user-verification/user-verification.service.ts @@ -206,9 +206,10 @@ export class UserVerificationService implements UserVerificationServiceAbstracti let policyOptions: MasterPasswordPolicyResponse | null; // Client-side verification if (await this.hasMasterPasswordAndMasterKeyHash(userId)) { - const passwordValid = await this.keyService.compareAndUpdateKeyHash( + const passwordValid = await this.keyService.compareKeyHash( verification.secret, masterKey, + userId, ); if (!passwordValid) { throw new Error(this.i18nService.t("invalidMasterPassword")); diff --git a/libs/key-management/src/abstractions/key.service.ts b/libs/key-management/src/abstractions/key.service.ts index 55ffea9db79..0ec3aaafdc6 100644 --- a/libs/key-management/src/abstractions/key.service.ts +++ b/libs/key-management/src/abstractions/key.service.ts @@ -204,14 +204,18 @@ export abstract class KeyService { hashPurpose?: HashPurpose, ): Promise; /** - * Compares the provided master password to the stored password hash and server password hash. - * Updates the stored hash if outdated. + * Compares the provided master password to the stored password hash. * @param masterPassword The user's master password * @param key The user's master key + * @param userId The id of the user to do the operation for. * @returns True if the provided master password matches either the stored * key hash or the server key hash */ - abstract compareAndUpdateKeyHash(masterPassword: string, masterKey: MasterKey): Promise; + abstract compareKeyHash( + masterPassword: string, + masterKey: MasterKey, + userId: UserId, + ): Promise; /** * Stores the encrypted organization keys and clears any decrypted * organization keys currently in memory diff --git a/libs/key-management/src/key.service.spec.ts b/libs/key-management/src/key.service.spec.ts index 263779f59b3..2b2c6514eb4 100644 --- a/libs/key-management/src/key.service.spec.ts +++ b/libs/key-management/src/key.service.spec.ts @@ -733,4 +733,63 @@ describe("keyService", () => { }); }); }); + + describe("compareKeyHash", () => { + type TestCase = { + masterKey: MasterKey; + masterPassword: string | null; + storedMasterKeyHash: string; + mockReturnedHash: string; + expectedToMatch: boolean; + }; + + const data: TestCase[] = [ + { + masterKey: makeSymmetricCryptoKey(64), + masterPassword: "my_master_password", + storedMasterKeyHash: "bXlfaGFzaA==", + mockReturnedHash: "bXlfaGFzaA==", + expectedToMatch: true, + }, + { + masterKey: makeSymmetricCryptoKey(64), + masterPassword: null, + storedMasterKeyHash: "bXlfaGFzaA==", + mockReturnedHash: "bXlfaGFzaA==", + expectedToMatch: false, + }, + { + masterKey: makeSymmetricCryptoKey(64), + masterPassword: null, + storedMasterKeyHash: null, + mockReturnedHash: "bXlfaGFzaA==", + expectedToMatch: false, + }, + ]; + + it.each(data)( + "returns expected match value when calculated hash equals stored hash", + async ({ + masterKey, + masterPassword, + storedMasterKeyHash, + mockReturnedHash, + expectedToMatch, + }) => { + masterPasswordService.masterKeyHashSubject.next(storedMasterKeyHash); + + cryptoFunctionService.pbkdf2 + .calledWith(masterKey.key, masterPassword, "sha256", 2) + .mockResolvedValue(Utils.fromB64ToArray(mockReturnedHash)); + + const actualDidMatch = await keyService.compareKeyHash( + masterPassword, + masterKey, + mockUserId, + ); + + expect(actualDidMatch).toBe(expectedToMatch); + }, + ); + }); }); diff --git a/libs/key-management/src/key.service.ts b/libs/key-management/src/key.service.ts index b12db176cec..f2ba24ef5df 100644 --- a/libs/key-management/src/key.service.ts +++ b/libs/key-management/src/key.service.ts @@ -319,34 +319,43 @@ export class DefaultKeyService implements KeyServiceAbstraction { } // TODO: move to MasterPasswordService - async compareAndUpdateKeyHash(masterPassword: string, masterKey: MasterKey): Promise { - const userId = await firstValueFrom(this.stateProvider.activeUserId$); + async compareKeyHash( + masterPassword: string, + masterKey: MasterKey, + userId: UserId, + ): Promise { + if (masterKey == null) { + throw new Error("'masterKey' is required to be non-null."); + } + + if (masterPassword == null) { + // If they don't give us a master password, we can't hash it, and therefore + // it will never match what we have stored. + return false; + } + + // Retrieve the current password hash const storedPasswordHash = await firstValueFrom( this.masterPasswordService.masterKeyHash$(userId), ); - if (masterPassword != null && storedPasswordHash != null) { - const localKeyHash = await this.hashMasterKey( - masterPassword, - masterKey, - HashPurpose.LocalAuthorization, - ); - if (localKeyHash != null && storedPasswordHash === localKeyHash) { - return true; - } - // TODO: remove serverKeyHash check in 1-2 releases after everyone's keyHash has been updated - const serverKeyHash = await this.hashMasterKey( - masterPassword, - masterKey, - HashPurpose.ServerAuthorization, - ); - if (serverKeyHash != null && storedPasswordHash === serverKeyHash) { - await this.masterPasswordService.setMasterKeyHash(localKeyHash, userId); - return true; - } + if (storedPasswordHash == null) { + return false; } - return false; + // Hash the key for local use + const localKeyHash = await this.hashMasterKey( + masterPassword, + masterKey, + HashPurpose.LocalAuthorization, + ); + + // Check if the stored hash is already equal to the hash we create locally + if (localKeyHash == null || storedPasswordHash !== localKeyHash) { + return false; + } + + return true; } async setOrgKeys( diff --git a/libs/vault/src/components/password-reprompt.component.ts b/libs/vault/src/components/password-reprompt.component.ts index 3cbdfa1416a..21646d6e6aa 100644 --- a/libs/vault/src/components/password-reprompt.component.ts +++ b/libs/vault/src/components/password-reprompt.component.ts @@ -1,8 +1,10 @@ import { DialogRef } from "@angular/cdk/dialog"; import { Component } from "@angular/core"; import { FormBuilder, ReactiveFormsModule, Validators } from "@angular/forms"; +import { firstValueFrom, map } from "rxjs"; import { JslibModule } from "@bitwarden/angular/jslib.module"; +import { 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 { @@ -43,16 +45,25 @@ export class PasswordRepromptComponent { protected i18nService: I18nService, protected formBuilder: FormBuilder, protected dialogRef: DialogRef, + protected accountService: AccountService, ) {} submit = async () => { + const userId = await firstValueFrom(this.accountService.activeAccount$.pipe(map((a) => a?.id))); + + if (userId == null) { + throw new Error("An active user is expected while doing password reprompt."); + } + const storedMasterKey = await this.keyService.getOrDeriveMasterKey( this.formGroup.value.masterPassword, + userId, ); if ( - !(await this.keyService.compareAndUpdateKeyHash( + !(await this.keyService.compareKeyHash( this.formGroup.value.masterPassword, storedMasterKey, + userId, )) ) { this.platformUtilsService.showToast( From 0d06c499f399b50ad6cbfeea6e7c8b7c850b19cd Mon Sep 17 00:00:00 2001 From: Justin Baur <19896123+justindbaur@users.noreply.github.com> Date: Mon, 4 Nov 2024 17:54:12 -0500 Subject: [PATCH 18/21] Remove Heartbeat Code (#11585) --- apps/browser/src/platform/background.ts | 23 ----------------------- 1 file changed, 23 deletions(-) diff --git a/apps/browser/src/platform/background.ts b/apps/browser/src/platform/background.ts index a48c420e777..0cd9b3285e6 100644 --- a/apps/browser/src/platform/background.ts +++ b/apps/browser/src/platform/background.ts @@ -2,29 +2,6 @@ import { ConsoleLogService } from "@bitwarden/common/platform/services/console-l import MainBackground from "../background/main.background"; -import { BrowserApi } from "./browser/browser-api"; - const logService = new ConsoleLogService(false); -if (BrowserApi.isManifestVersion(3)) { - startHeartbeat().catch((error) => logService.error(error)); -} const bitwardenMain = ((self as any).bitwardenMain = new MainBackground()); bitwardenMain.bootstrap().catch((error) => logService.error(error)); - -/** - * Tracks when a service worker was last alive and extends the service worker - * lifetime by writing the current time to extension storage every 20 seconds. - */ -async function runHeartbeat() { - await chrome.storage.local.set({ "last-heartbeat": new Date().getTime() }); -} - -/** - * Starts the heartbeat interval which keeps the service worker alive. - */ -async function startHeartbeat() { - // Run the heartbeat once at service worker startup, then again every 20 seconds. - runHeartbeat() - .then(() => setInterval(runHeartbeat, 20 * 1000)) - .catch((error) => logService.error(error)); -} From 586edafc79ee91605651e956b00b0b599729d164 Mon Sep 17 00:00:00 2001 From: Andreas Coroiu Date: Tue, 5 Nov 2024 10:34:17 +0100 Subject: [PATCH 19/21] chore: bump SDK to 0.2.0.main-3 (#11849) --- package-lock.json | 8 ++++---- package.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index 8994cfcd373..aef1e24a3b7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -24,7 +24,7 @@ "@angular/platform-browser": "17.3.12", "@angular/platform-browser-dynamic": "17.3.12", "@angular/router": "17.3.12", - "@bitwarden/sdk-internal": "0.1.7", + "@bitwarden/sdk-internal": "0.2.0-main.3", "@electron/fuses": "1.8.0", "@koa/multer": "3.0.2", "@koa/router": "13.1.0", @@ -4128,9 +4128,9 @@ "link": true }, "node_modules/@bitwarden/sdk-internal": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/@bitwarden/sdk-internal/-/sdk-internal-0.1.7.tgz", - "integrity": "sha512-bpcY4rMipUtNSuhMQBAIdPR/Cz1Fx501yG5Vfsp7CuG28g3eQhkIRQsc07s/HAoKlT20senWbMGdHMM0q1IAGw==" + "version": "0.2.0-main.3", + "resolved": "https://registry.npmjs.org/@bitwarden/sdk-internal/-/sdk-internal-0.2.0-main.3.tgz", + "integrity": "sha512-CYp98uaVMSFp6nr/QLw+Qw8ttnVtWark/bMpw59OhwMVhrCDKmpCgcR9G4oEdVO11IuFcYZieTBmtOEPhCpGaw==" }, "node_modules/@bitwarden/vault": { "resolved": "libs/vault", diff --git a/package.json b/package.json index 9b38df0c061..84139c44a91 100644 --- a/package.json +++ b/package.json @@ -158,7 +158,7 @@ "@angular/platform-browser": "17.3.12", "@angular/platform-browser-dynamic": "17.3.12", "@angular/router": "17.3.12", - "@bitwarden/sdk-internal": "0.1.7", + "@bitwarden/sdk-internal": "0.2.0-main.3", "@electron/fuses": "1.8.0", "@koa/multer": "3.0.2", "@koa/router": "13.1.0", From af6a2f5553a765d94702fdcd1dd0e1beb5bc76c6 Mon Sep 17 00:00:00 2001 From: Oscar Hinton Date: Tue, 5 Nov 2024 10:54:38 +0100 Subject: [PATCH 20/21] [PM-13375] Gulp: Remove beta builds (#11482) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Part of the browser build script refactor effort. bitwarden.atlassian.net/browse/PM-6683 The beta logic adds a fair bit of complexity and is currently unused. Let’s remove it and we can look into re-add it after migrating to our new build system. --- .github/workflows/build-browser.yml | 11 ------ apps/browser/gulpfile.js | 56 ----------------------------- apps/browser/package.json | 3 -- 3 files changed, 70 deletions(-) diff --git a/.github/workflows/build-browser.yml b/.github/workflows/build-browser.yml index d03efae7f4f..34c69912f50 100644 --- a/.github/workflows/build-browser.yml +++ b/.github/workflows/build-browser.yml @@ -163,10 +163,6 @@ jobs: run: npm run dist:mv3 working-directory: browser-source/apps/browser - - name: Build Chrome Manifest v3 Beta - run: npm run dist:chrome:beta - working-directory: browser-source/apps/browser - - name: Upload Opera artifact uses: actions/upload-artifact@b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882 # v4.4.3 with: @@ -188,13 +184,6 @@ jobs: path: browser-source/apps/browser/dist/dist-chrome-mv3.zip if-no-files-found: error - - name: Upload Chrome MV3 Beta artifact (DO NOT USE FOR PROD) - uses: actions/upload-artifact@b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882 # v4.4.3 - with: - name: DO-NOT-USE-FOR-PROD-dist-chrome-MV3-beta-${{ env._BUILD_NUMBER }}.zip - path: browser-source/apps/browser/dist/dist-chrome-mv3-beta.zip - if-no-files-found: error - - name: Upload Firefox artifact uses: actions/upload-artifact@b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882 # v4.4.3 with: diff --git a/apps/browser/gulpfile.js b/apps/browser/gulpfile.js index 573f86efc18..ed977df4715 100644 --- a/apps/browser/gulpfile.js +++ b/apps/browser/gulpfile.js @@ -9,7 +9,6 @@ const replace = require("gulp-replace"); const manifest = require("./src/manifest.json"); const manifestVersion = parseInt(process.env.MANIFEST_VERSION || manifest.version); -const betaBuild = process.env.BETA_BUILD === "1"; const paths = { build: "./build/", @@ -17,27 +16,11 @@ const paths = { safari: "./src/safari/", }; -/** - * Converts a number to a tuple containing two Uint16's - * @param num {number} This number is expected to be a integer style number with no decimals - * - * @returns {number[]} A tuple containing two elements that are both numbers. - */ -function numToUint16s(num) { - var arr = new ArrayBuffer(4); - var view = new DataView(arr); - view.setUint32(0, num, false); - return [view.getUint16(0), view.getUint16(2)]; -} - function buildString() { var build = ""; if (process.env.MANIFEST_VERSION) { build = `-mv${process.env.MANIFEST_VERSION}`; } - if (betaBuild) { - build += "-beta"; - } if (process.env.BUILD_NUMBER && process.env.BUILD_NUMBER !== "") { build = `-${process.env.BUILD_NUMBER}`; } @@ -71,9 +54,6 @@ function distFirefox() { manifest.optional_permissions = manifest.optional_permissions.filter( (permission) => permission !== "privacy", ); - if (betaBuild) { - manifest = applyBetaLabels(manifest); - } return manifest; }); } @@ -90,9 +70,6 @@ function distOpera() { delete manifest.commands._execute_sidebar_action; } - if (betaBuild) { - manifest = applyBetaLabels(manifest); - } return manifest; }); } @@ -102,9 +79,6 @@ function distChrome() { delete manifest.applications; delete manifest.sidebar_action; delete manifest.commands._execute_sidebar_action; - if (betaBuild) { - manifest = applyBetaLabels(manifest); - } return manifest; }); } @@ -114,9 +88,6 @@ function distEdge() { delete manifest.applications; delete manifest.sidebar_action; delete manifest.commands._execute_sidebar_action; - if (betaBuild) { - manifest = applyBetaLabels(manifest); - } return manifest; }); } @@ -237,9 +208,6 @@ async function safariCopyBuild(source, dest) { delete manifest.commands._execute_sidebar_action; delete manifest.optional_permissions; manifest.permissions.push("nativeMessaging"); - if (betaBuild) { - manifest = applyBetaLabels(manifest); - } return manifest; }), ), @@ -254,30 +222,6 @@ function stdOutProc(proc) { proc.stderr.on("data", (data) => console.error(data.toString())); } -function applyBetaLabels(manifest) { - manifest.name = "Bitwarden Password Manager BETA"; - manifest.short_name = "Bitwarden BETA"; - manifest.description = "THIS EXTENSION IS FOR BETA TESTING BITWARDEN."; - if (process.env.GITHUB_RUN_ID) { - const existingVersionParts = manifest.version.split("."); // 3 parts expected 2024.4.0 - - // GITHUB_RUN_ID is a number like: 8853654662 - // which will convert to [ 4024, 3206 ] - // and a single incremented id of 8853654663 will become [ 4024, 3207 ] - const runIdParts = numToUint16s(parseInt(process.env.GITHUB_RUN_ID)); - - // Only use the first 2 parts from the given version number and base the other 2 numbers from the GITHUB_RUN_ID - // Example: 2024.4.4024.3206 - const betaVersion = `${existingVersionParts[0]}.${existingVersionParts[1]}.${runIdParts[0]}.${runIdParts[1]}`; - - manifest.version_name = `${betaVersion} beta - ${process.env.GITHUB_SHA.slice(0, 8)}`; - manifest.version = betaVersion; - } else { - manifest.version = `${manifest.version}.0`; - } - return manifest; -} - exports["dist:firefox"] = distFirefox; exports["dist:chrome"] = distChrome; exports["dist:opera"] = distOpera; diff --git a/apps/browser/package.json b/apps/browser/package.json index 5909c802b36..4a749522545 100644 --- a/apps/browser/package.json +++ b/apps/browser/package.json @@ -10,12 +10,9 @@ "build:watch:safari": "cross-env MANIFEST_VERSION=3 BROWSER=safari webpack --watch", "build:watch:mv2": "webpack --watch", "build:prod": "cross-env NODE_ENV=production NODE_OPTIONS=\"--max-old-space-size=4096\" webpack", - "build:prod:beta": "cross-env BETA_BUILD=1 NODE_ENV=production webpack", "build:prod:watch": "cross-env NODE_ENV=production webpack --watch", "dist": "npm run build:prod && gulp dist", - "dist:beta": "npm run build:prod:beta && cross-env BETA_BUILD=1 gulp dist", "dist:mv3": "cross-env MANIFEST_VERSION=3 npm run build:prod && cross-env MANIFEST_VERSION=3 gulp dist", - "dist:mv3:beta": "cross-env MANIFEST_VERSION=3 npm run build:prod:beta && cross-env MANIFEST_VERSION=3 BETA_BUILD=1 gulp dist", "dist:chrome": "npm run build:prod && gulp dist:chrome", "dist:chrome:beta": "cross-env MANIFEST_VERSION=3 npm run build:prod:beta && cross-env MANIFEST_VERSION=3 BETA_BUILD=1 gulp dist:chrome", "dist:firefox": "npm run build:prod && gulp dist:firefox", From e3e675383f5ffa236994bb423402dd9fed42e85e Mon Sep 17 00:00:00 2001 From: Oscar Hinton Date: Tue, 5 Nov 2024 11:40:47 +0100 Subject: [PATCH 21/21] Fix locale test after typescript upgrade (#11859) The TypeScript update broke locale tests, to fix this we need to define moduleResolution manually as mentioned in the TS changelog. --- scripts/tsconfig.json | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/tsconfig.json b/scripts/tsconfig.json index 018fb133932..96870175b54 100644 --- a/scripts/tsconfig.json +++ b/scripts/tsconfig.json @@ -3,6 +3,7 @@ "compilerOptions": { "outDir": "dist", "module": "NodeNext", + "moduleResolution": "NodeNext", "target": "ESNext" }, "include": ["*.ts"]