mirror of
https://github.com/bitwarden/browser
synced 2026-01-03 00:53:23 +00:00
Align Desktop Native's Rust CI checks with SDK (#17261)
* clean crate deps * update lint workflow * add rustfmt.toml * apply rust fmt * missed one * fix lint of lint lol * more deps platform fixes * fix macos_provider * some more deps clean * more cleanup * add --all-targets * remove another unused dep * generate index.d.ts * fix whitespace * fix split comment in biometric * formatting comment in biometric_v2 * apply fmt
This commit is contained in:
@@ -7,35 +7,38 @@ publish = { workspace = true }
|
||||
|
||||
[dependencies]
|
||||
aes = { workspace = true }
|
||||
aes-gcm = { workspace = true }
|
||||
anyhow = { workspace = true }
|
||||
async-trait = "=0.1.88"
|
||||
base64 = { workspace = true }
|
||||
cbc = { workspace = true, features = ["alloc"] }
|
||||
dirs = { workspace = true }
|
||||
hex = { workspace = true }
|
||||
pbkdf2 = "=0.12.2"
|
||||
rand = { workspace = true }
|
||||
rusqlite = { version = "=0.37.0", features = ["bundled"] }
|
||||
serde = { workspace = true, features = ["derive"] }
|
||||
serde_json = { workspace = true }
|
||||
sha1 = "=0.10.6"
|
||||
tokio = { workspace = true, features = ["full"] }
|
||||
tracing = { workspace = true }
|
||||
|
||||
[target.'cfg(target_os = "macos")'.dependencies]
|
||||
cbc = { workspace = true, features = ["alloc"] }
|
||||
pbkdf2 = "=0.12.2"
|
||||
security-framework = { workspace = true }
|
||||
sha1 = "=0.10.6"
|
||||
|
||||
[target.'cfg(target_os = "windows")'.dependencies]
|
||||
aes-gcm = { workspace = true }
|
||||
base64 = { workspace = true }
|
||||
windows = { workspace = true, features = [
|
||||
"Win32_Security_Cryptography",
|
||||
"Win32_UI_Shell",
|
||||
"Win32_UI_WindowsAndMessaging",
|
||||
] }
|
||||
verifysign = "=0.2.4"
|
||||
tokio = { workspace = true, features = ["full"] }
|
||||
tracing = { workspace = true }
|
||||
|
||||
[target.'cfg(target_os = "linux")'.dependencies]
|
||||
cbc = { workspace = true, features = ["alloc"] }
|
||||
oo7 = { workspace = true }
|
||||
pbkdf2 = "=0.12.2"
|
||||
sha1 = "=0.10.6"
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
use std::collections::HashMap;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::sync::LazyLock;
|
||||
use std::{
|
||||
collections::HashMap,
|
||||
path::{Path, PathBuf},
|
||||
sync::LazyLock,
|
||||
};
|
||||
|
||||
use anyhow::{anyhow, Result};
|
||||
use async_trait::async_trait;
|
||||
@@ -10,11 +12,10 @@ use rusqlite::{params, Connection};
|
||||
|
||||
mod platform;
|
||||
|
||||
pub(crate) use platform::SUPPORTED_BROWSERS as PLATFORM_SUPPORTED_BROWSERS;
|
||||
#[cfg(target_os = "windows")]
|
||||
pub use platform::*;
|
||||
|
||||
pub(crate) use platform::SUPPORTED_BROWSERS as PLATFORM_SUPPORTED_BROWSERS;
|
||||
|
||||
//
|
||||
// Public API
|
||||
//
|
||||
@@ -87,14 +88,15 @@ pub async fn import_logins(
|
||||
let local_logins = get_logins(&data_dir, profile_id, "Login Data")
|
||||
.map_err(|e| anyhow!("Failed to query logins: {}", e))?;
|
||||
|
||||
// This is not available in all browsers, but there's no harm in trying. If the file doesn't exist we just get an empty vector.
|
||||
// This is not available in all browsers, but there's no harm in trying. If the file doesn't
|
||||
// exist we just get an empty vector.
|
||||
let account_logins = get_logins(&data_dir, profile_id, "Login Data For Account")
|
||||
.map_err(|e| anyhow!("Failed to query logins: {}", e))?;
|
||||
|
||||
// TODO: Do we need a better merge strategy? Maybe ignore duplicates at least?
|
||||
// TODO: Should we also ignore an error from one of the two imports? If one is successful and the other fails,
|
||||
// should we still return the successful ones? At the moment it doesn't fail for a missing file, only when
|
||||
// something goes really wrong.
|
||||
// TODO: Should we also ignore an error from one of the two imports? If one is successful and
|
||||
// the other fails, should we still return the successful ones? At the moment it
|
||||
// doesn't fail for a missing file, only when something goes really wrong.
|
||||
let all_logins = local_logins
|
||||
.into_iter()
|
||||
.chain(account_logins.into_iter())
|
||||
|
||||
@@ -4,15 +4,17 @@ use anyhow::{anyhow, Result};
|
||||
use async_trait::async_trait;
|
||||
use oo7::XDG_SCHEMA_ATTRIBUTE;
|
||||
|
||||
use crate::chromium::{BrowserConfig, CryptoService, LocalState};
|
||||
|
||||
use crate::util;
|
||||
use crate::{
|
||||
chromium::{BrowserConfig, CryptoService, LocalState},
|
||||
util,
|
||||
};
|
||||
|
||||
//
|
||||
// Public API
|
||||
//
|
||||
|
||||
// TODO: It's possible that there might be multiple possible data directories, depending on the installation method (e.g., snap, flatpak, etc.).
|
||||
// TODO: It's possible that there might be multiple possible data directories, depending on the
|
||||
// installation method (e.g., snap, flatpak, etc.).
|
||||
pub(crate) const SUPPORTED_BROWSERS: &[BrowserConfig] = &[
|
||||
BrowserConfig {
|
||||
name: "Chrome",
|
||||
|
||||
@@ -2,9 +2,10 @@ use anyhow::{anyhow, Result};
|
||||
use async_trait::async_trait;
|
||||
use security_framework::passwords::get_generic_password;
|
||||
|
||||
use crate::chromium::{BrowserConfig, CryptoService, LocalState};
|
||||
|
||||
use crate::util;
|
||||
use crate::{
|
||||
chromium::{BrowserConfig, CryptoService, LocalState},
|
||||
util,
|
||||
};
|
||||
|
||||
//
|
||||
// Public API
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use super::abe_config;
|
||||
use anyhow::{anyhow, Result};
|
||||
use std::{ffi::OsStr, os::windows::ffi::OsStrExt};
|
||||
|
||||
use anyhow::{anyhow, Result};
|
||||
use tokio::{
|
||||
io::{self, AsyncReadExt, AsyncWriteExt},
|
||||
net::windows::named_pipe::{NamedPipeServer, ServerOptions},
|
||||
@@ -14,6 +14,8 @@ use windows::{
|
||||
Win32::UI::{Shell::ShellExecuteW, WindowsAndMessaging::SW_HIDE},
|
||||
};
|
||||
|
||||
use super::abe_config;
|
||||
|
||||
const WAIT_FOR_ADMIN_MESSAGE_TIMEOUT_SECS: u64 = 30;
|
||||
|
||||
fn start_tokio_named_pipe_server<F>(
|
||||
|
||||
@@ -1,11 +1,14 @@
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
use aes_gcm::{aead::Aead, Aes256Gcm, Key, KeyInit, Nonce};
|
||||
use anyhow::{anyhow, Result};
|
||||
use async_trait::async_trait;
|
||||
use base64::{engine::general_purpose::STANDARD as BASE64_STANDARD, Engine as _};
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
use crate::chromium::{BrowserConfig, CryptoService, LocalState};
|
||||
use crate::util;
|
||||
use crate::{
|
||||
chromium::{BrowserConfig, CryptoService, LocalState},
|
||||
util,
|
||||
};
|
||||
mod abe;
|
||||
mod abe_config;
|
||||
mod crypto;
|
||||
@@ -95,7 +98,8 @@ impl CryptoService for WindowsCryptoService {
|
||||
let (version, no_prefix) =
|
||||
util::split_encrypted_string_and_validate(encrypted, &["v10", "v20"])?;
|
||||
|
||||
// v10 is already stripped; Windows Chrome uses AES-GCM: [12 bytes IV][ciphertext][16 bytes auth tag]
|
||||
// v10 is already stripped; Windows Chrome uses AES-GCM: [12 bytes IV][ciphertext][16 bytes
|
||||
// auth tag]
|
||||
const IV_SIZE: usize = 12;
|
||||
const TAG_SIZE: usize = 16;
|
||||
const MIN_LENGTH: usize = IV_SIZE + TAG_SIZE;
|
||||
@@ -242,8 +246,8 @@ fn get_dist_admin_exe_path(current_exe_full_path: &Path) -> Result<PathBuf> {
|
||||
Ok(admin_exe)
|
||||
}
|
||||
|
||||
// Try to find bitwarden_chromium_import_helper.exe in debug build folders. This might not cover all the cases.
|
||||
// Tested on `npm run electron` from apps/desktop and apps/desktop/desktop_native.
|
||||
// Try to find bitwarden_chromium_import_helper.exe in debug build folders. This might not cover all
|
||||
// the cases. Tested on `npm run electron` from apps/desktop and apps/desktop/desktop_native.
|
||||
fn get_debug_admin_exe_path() -> Result<PathBuf> {
|
||||
let current_dir = std::env::current_dir()?;
|
||||
let folder_name = current_dir
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
use anyhow::{anyhow, Result};
|
||||
use std::path::Path;
|
||||
|
||||
use anyhow::{anyhow, Result};
|
||||
use tracing::{debug, info};
|
||||
use verifysign::CodeSignVerifier;
|
||||
|
||||
|
||||
@@ -59,9 +59,9 @@ pub fn get_supported_importers<T: InstalledBrowserRetriever>(
|
||||
// Tests are cfg-gated based upon OS, and must be compiled/run on each OS for full coverage
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use std::collections::HashSet;
|
||||
|
||||
use super::*;
|
||||
use crate::chromium::{InstalledBrowserRetriever, SUPPORTED_BROWSER_MAP};
|
||||
|
||||
pub struct MockInstalledBrowserRetriever {}
|
||||
|
||||
@@ -32,7 +32,7 @@ pub(crate) fn split_encrypted_string_and_validate<'a>(
|
||||
}
|
||||
|
||||
/// Decrypt using AES-128 in CBC mode.
|
||||
#[cfg(any(target_os = "linux", target_os = "macos", test))]
|
||||
#[cfg(any(target_os = "linux", target_os = "macos"))]
|
||||
pub(crate) fn decrypt_aes_128_cbc(key: &[u8], iv: &[u8], ciphertext: &[u8]) -> Result<Vec<u8>> {
|
||||
use aes::cipher::{block_padding::Pkcs7, BlockDecryptMut, KeyIvInit};
|
||||
|
||||
@@ -41,7 +41,8 @@ pub(crate) fn decrypt_aes_128_cbc(key: &[u8], iv: &[u8], ciphertext: &[u8]) -> R
|
||||
.map_err(|e| anyhow!("Failed to decrypt: {}", e))
|
||||
}
|
||||
|
||||
/// Derives a PBKDF2 key from the static "saltysalt" salt with the given password and iteration count.
|
||||
/// Derives a PBKDF2 key from the static "saltysalt" salt with the given password and iteration
|
||||
/// count.
|
||||
#[cfg(any(target_os = "linux", target_os = "macos"))]
|
||||
pub(crate) fn derive_saltysalt(password: &[u8], iterations: u32) -> Result<Vec<u8>> {
|
||||
use pbkdf2::{hmac::Hmac, pbkdf2};
|
||||
@@ -55,27 +56,9 @@ pub(crate) fn derive_saltysalt(password: &[u8], iterations: u32) -> Result<Vec<u
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use aes::cipher::{
|
||||
block_padding::Pkcs7,
|
||||
generic_array::{sequence::GenericSequence, GenericArray},
|
||||
ArrayLength, BlockEncryptMut, KeyIvInit,
|
||||
};
|
||||
|
||||
const LENGTH16: usize = 16;
|
||||
const LENGTH10: usize = 10;
|
||||
const LENGTH0: usize = 0;
|
||||
|
||||
fn generate_vec(length: usize, offset: u8, increment: u8) -> Vec<u8> {
|
||||
(0..length).map(|i| offset + i as u8 * increment).collect()
|
||||
}
|
||||
|
||||
fn generate_generic_array<N: ArrayLength<u8>>(
|
||||
offset: u8,
|
||||
increment: u8,
|
||||
) -> GenericArray<u8, N> {
|
||||
GenericArray::generate(|i| offset + i as u8 * increment)
|
||||
}
|
||||
|
||||
fn run_split_encrypted_string_test<'a, const N: usize>(
|
||||
successfully_split: bool,
|
||||
plaintext_to_encrypt: &'a str,
|
||||
@@ -144,8 +127,28 @@ mod tests {
|
||||
run_split_encrypted_string_and_validate_test(false, "v10EncryptMe!", &[]);
|
||||
}
|
||||
|
||||
#[cfg(any(target_os = "linux", target_os = "macos"))]
|
||||
#[test]
|
||||
fn test_decrypt_aes_128_cbc() {
|
||||
use aes::cipher::{
|
||||
block_padding::Pkcs7,
|
||||
generic_array::{sequence::GenericSequence, GenericArray},
|
||||
ArrayLength, BlockEncryptMut, KeyIvInit,
|
||||
};
|
||||
|
||||
const LENGTH16: usize = 16;
|
||||
|
||||
fn generate_generic_array<N: ArrayLength<u8>>(
|
||||
offset: u8,
|
||||
increment: u8,
|
||||
) -> GenericArray<u8, N> {
|
||||
GenericArray::generate(|i| offset + i as u8 * increment)
|
||||
}
|
||||
|
||||
fn generate_vec(length: usize, offset: u8, increment: u8) -> Vec<u8> {
|
||||
(0..length).map(|i| offset + i as u8 * increment).collect()
|
||||
}
|
||||
|
||||
let offset = 0;
|
||||
let increment = 1;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user