mirror of
https://github.com/bitwarden/browser
synced 2025-12-06 00:13:28 +00:00
[PM-22788] Add Autotype Crate and Windowing Functions (#15317)
* [PM-22783] Add initial feature flag and settings toggle for autotype MVP * [PM-22783] Undo Cargo.lock changes * [PM-22783] Disable console.log block * [PM-22783] Lint fix * [PM-22783] Small updates * [PM-22783] Build fix * [PM-22783] Use combineLatest in updating the desktop autotype service * [PM-22783] Check if the user is on Windows * [PM-22783] Undo access selector html change, linting keeps removing this * [PM-22783] Fix failing test * [PM-22788] Add initial desktop native autotype crate based on spike ticket investigation * [PM-22788] cargo fmt * [PM-22783] Update autotypeEnabled to be stored in service * [PM-22783] Add todo comments * [PM-22783] Add SlimConfigService and MainDesktopAutotypeService * [PM-22783] Small fixes * [PM-22788] Add get_foreground_window_title() and cleanup * [PM-22788] Add comment * [PM-22788] Lint and cross platform build fixes * [PM-22788] Update windows.rs in autotype_internal * [PM-22788] Update windows.rs and dummy.rs in autotype_internal * [PM-22788] cargo fmt * [PM-22788] Edit napi result types * [PM-22788] Edit napi result types again * [PM-22788] Add autofill as a codeowner of the desktop_native/autotype directory * [PM-22788] Refactor autotype code * [PM-22788] Move autotype dependency out of windows only due to abstraction change * [PM-22788] Fix lint errors * [PM-22788] Updates based on PR comments * [PM-22788] cargo fmt
This commit is contained in:
1
.github/CODEOWNERS
vendored
1
.github/CODEOWNERS
vendored
@@ -134,6 +134,7 @@ libs/common/src/autofill @bitwarden/team-autofill-dev
|
||||
apps/desktop/macos/autofill-extension @bitwarden/team-autofill-dev
|
||||
apps/desktop/src/app/components/fido2placeholder.component.ts @bitwarden/team-autofill-dev
|
||||
apps/desktop/desktop_native/windows_plugin_authenticator @bitwarden/team-autofill-dev
|
||||
apps/desktop/desktop_native/autotype @bitwarden/team-autofill-dev
|
||||
# DuckDuckGo integration
|
||||
apps/desktop/native-messaging-test-runner @bitwarden/team-autofill-dev
|
||||
apps/desktop/src/services/duckduckgo-message-handler.service.ts @bitwarden/team-autofill-dev
|
||||
|
||||
29
apps/desktop/desktop_native/Cargo.lock
generated
29
apps/desktop/desktop_native/Cargo.lock
generated
@@ -349,6 +349,14 @@ version = "1.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26"
|
||||
|
||||
[[package]]
|
||||
name = "autotype"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"windows 0.61.1",
|
||||
"windows-core 0.61.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "backtrace"
|
||||
version = "0.3.75"
|
||||
@@ -912,6 +920,7 @@ name = "desktop_napi"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"autotype",
|
||||
"base64",
|
||||
"desktop_core",
|
||||
"hex",
|
||||
@@ -3677,7 +3686,7 @@ dependencies = [
|
||||
"windows-implement 0.60.0",
|
||||
"windows-interface 0.59.1",
|
||||
"windows-link",
|
||||
"windows-result 0.3.2",
|
||||
"windows-result 0.3.4",
|
||||
"windows-strings",
|
||||
]
|
||||
|
||||
@@ -3737,9 +3746,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "windows-link"
|
||||
version = "0.1.1"
|
||||
version = "0.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "76840935b766e1b0a05c0066835fb9ec80071d4c09a16f6bd5f7e655e3c14c38"
|
||||
checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a"
|
||||
|
||||
[[package]]
|
||||
name = "windows-numerics"
|
||||
@@ -3753,12 +3762,12 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "windows-registry"
|
||||
version = "0.5.1"
|
||||
version = "0.5.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ad1da3e436dc7653dfdf3da67332e22bff09bb0e28b0239e1624499c7830842e"
|
||||
checksum = "5b8a9ed28765efc97bbc954883f4e6796c33a06546ebafacbabee9696967499e"
|
||||
dependencies = [
|
||||
"windows-link",
|
||||
"windows-result 0.3.2",
|
||||
"windows-result 0.3.4",
|
||||
"windows-strings",
|
||||
]
|
||||
|
||||
@@ -3773,18 +3782,18 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "windows-result"
|
||||
version = "0.3.2"
|
||||
version = "0.3.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c64fd11a4fd95df68efcfee5f44a294fe71b8bc6a91993e2791938abcc712252"
|
||||
checksum = "56f42bd332cc6c8eac5af113fc0c1fd6a8fd2aa08a0119358686e5160d0586c6"
|
||||
dependencies = [
|
||||
"windows-link",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-strings"
|
||||
version = "0.4.0"
|
||||
version = "0.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7a2ba9642430ee452d5a7aa78d72907ebe8cfda358e8cb7918a2050581322f97"
|
||||
checksum = "56e6c93f3a0c3b36176cb1327a4958a0353d5d166c2a35cb268ace15e91d3b57"
|
||||
dependencies = [
|
||||
"windows-link",
|
||||
]
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[workspace]
|
||||
resolver = "2"
|
||||
members = ["napi", "core", "proxy", "macos_provider", "windows_plugin_authenticator"]
|
||||
members = ["napi", "core", "proxy", "macos_provider", "windows_plugin_authenticator", "autotype"]
|
||||
|
||||
[workspace.package]
|
||||
version = "0.0.0"
|
||||
@@ -60,7 +60,7 @@ widestring = "=1.2.0"
|
||||
windows = "=0.61.1"
|
||||
windows-core = "=0.61.0"
|
||||
windows-future = "=0.2.0"
|
||||
windows-registry = "=0.5.1"
|
||||
windows-registry = "=0.5.3"
|
||||
zbus = "=5.5.0"
|
||||
zbus_polkit = "=5.0.0"
|
||||
zeroizing-alloc = "=0.1.0"
|
||||
|
||||
10
apps/desktop/desktop_native/autotype/Cargo.toml
Normal file
10
apps/desktop/desktop_native/autotype/Cargo.toml
Normal file
@@ -0,0 +1,10 @@
|
||||
[package]
|
||||
name = "autotype"
|
||||
version.workspace = true
|
||||
license.workspace = true
|
||||
edition.workspace = true
|
||||
publish.workspace = true
|
||||
|
||||
[target.'cfg(windows)'.dependencies]
|
||||
windows = { workspace = true, features = ["Win32_UI_Input_KeyboardAndMouse", "Win32_UI_WindowsAndMessaging"] }
|
||||
windows-core = { workspace = true }
|
||||
12
apps/desktop/desktop_native/autotype/src/lib.rs
Normal file
12
apps/desktop/desktop_native/autotype/src/lib.rs
Normal file
@@ -0,0 +1,12 @@
|
||||
#[cfg_attr(target_os = "linux", path = "linux.rs")]
|
||||
#[cfg_attr(target_os = "macos", path = "macos.rs")]
|
||||
#[cfg_attr(target_os = "windows", path = "windows.rs")]
|
||||
mod windowing;
|
||||
|
||||
/// Gets the title bar string for the foreground window.
|
||||
///
|
||||
/// TODO: The error handling will be improved in a future PR: PM-23615
|
||||
#[allow(clippy::result_unit_err)]
|
||||
pub fn get_foreground_window_title() -> std::result::Result<String, ()> {
|
||||
windowing::get_foreground_window_title()
|
||||
}
|
||||
3
apps/desktop/desktop_native/autotype/src/linux.rs
Normal file
3
apps/desktop/desktop_native/autotype/src/linux.rs
Normal file
@@ -0,0 +1,3 @@
|
||||
pub fn get_foreground_window_title() -> std::result::Result<String, ()> {
|
||||
todo!("Bitwarden does not yet support Linux autotype");
|
||||
}
|
||||
3
apps/desktop/desktop_native/autotype/src/macos.rs
Normal file
3
apps/desktop/desktop_native/autotype/src/macos.rs
Normal file
@@ -0,0 +1,3 @@
|
||||
pub fn get_foreground_window_title() -> std::result::Result<String, ()> {
|
||||
todo!("Bitwarden does not yet support Mac OS autotype");
|
||||
}
|
||||
75
apps/desktop/desktop_native/autotype/src/windows.rs
Normal file
75
apps/desktop/desktop_native/autotype/src/windows.rs
Normal file
@@ -0,0 +1,75 @@
|
||||
use std::ffi::OsString;
|
||||
use std::os::windows::ffi::OsStringExt;
|
||||
|
||||
use windows::Win32::Foundation::HWND;
|
||||
use windows::Win32::UI::WindowsAndMessaging::{
|
||||
GetForegroundWindow, GetWindowTextLengthW, GetWindowTextW,
|
||||
};
|
||||
|
||||
/// Gets the title bar string for the foreground window.
|
||||
pub fn get_foreground_window_title() -> std::result::Result<String, ()> {
|
||||
let Ok(window_handle) = get_foreground_window() else {
|
||||
return Err(());
|
||||
};
|
||||
let Ok(Some(window_title)) = get_window_title(window_handle) else {
|
||||
return Err(());
|
||||
};
|
||||
|
||||
Ok(window_title)
|
||||
}
|
||||
|
||||
/// Gets the foreground window handle.
|
||||
///
|
||||
/// https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getforegroundwindow
|
||||
fn get_foreground_window() -> Result<HWND, ()> {
|
||||
let foreground_window_handle = unsafe { GetForegroundWindow() };
|
||||
|
||||
if foreground_window_handle.is_invalid() {
|
||||
return Err(());
|
||||
}
|
||||
|
||||
Ok(foreground_window_handle)
|
||||
}
|
||||
|
||||
/// Gets the length of the window title bar text.
|
||||
///
|
||||
/// TODO: Future improvement is to use GetLastError for better error handling
|
||||
///
|
||||
/// https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getwindowtextlengthw
|
||||
fn get_window_title_length(window_handle: HWND) -> Result<usize, ()> {
|
||||
if window_handle.is_invalid() {
|
||||
return Err(());
|
||||
}
|
||||
|
||||
match usize::try_from(unsafe { GetWindowTextLengthW(window_handle) }) {
|
||||
Ok(length) => Ok(length),
|
||||
Err(_) => Err(()),
|
||||
}
|
||||
}
|
||||
|
||||
/// Gets the window title bar title.
|
||||
///
|
||||
/// TODO: Future improvement is to use GetLastError for better error handling
|
||||
///
|
||||
/// https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getwindowtextw
|
||||
fn get_window_title(window_handle: HWND) -> Result<Option<String>, ()> {
|
||||
if window_handle.is_invalid() {
|
||||
return Err(());
|
||||
}
|
||||
|
||||
let window_title_length = get_window_title_length(window_handle)?;
|
||||
if window_title_length == 0 {
|
||||
return Ok(None);
|
||||
}
|
||||
|
||||
let mut buffer: Vec<u16> = vec![0; window_title_length + 1]; // add extra space for the null character
|
||||
|
||||
let window_title_length = unsafe { GetWindowTextW(window_handle, &mut buffer) };
|
||||
if window_title_length == 0 {
|
||||
return Ok(None);
|
||||
}
|
||||
|
||||
let window_title = OsString::from_wide(&buffer);
|
||||
|
||||
Ok(Some(window_title.to_string_lossy().into_owned()))
|
||||
}
|
||||
@@ -14,6 +14,7 @@ default = []
|
||||
manual_test = []
|
||||
|
||||
[dependencies]
|
||||
autotype = { path = "../autotype" }
|
||||
base64 = { workspace = true }
|
||||
hex = { workspace = true }
|
||||
anyhow = { workspace = true }
|
||||
|
||||
3
apps/desktop/desktop_native/napi/index.d.ts
vendored
3
apps/desktop/desktop_native/napi/index.d.ts
vendored
@@ -208,3 +208,6 @@ export declare namespace logging {
|
||||
}
|
||||
export function initNapiLog(jsLogFn: (err: Error | null, arg0: LogLevel, arg1: string) => any): void
|
||||
}
|
||||
export declare namespace autotype {
|
||||
export function getForegroundWindowTitle(): string
|
||||
}
|
||||
|
||||
@@ -865,3 +865,15 @@ pub mod logging {
|
||||
fn flush(&self) {}
|
||||
}
|
||||
}
|
||||
|
||||
#[napi]
|
||||
pub mod autotype {
|
||||
#[napi]
|
||||
pub fn get_foreground_window_title() -> napi::Result<String, napi::Status> {
|
||||
autotype::get_foreground_window_title().map_err(|_| {
|
||||
napi::Error::from_reason(
|
||||
"Autotype Error: faild to get foreground window title".to_string(),
|
||||
)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import { autotype } from "@bitwarden/desktop-napi";
|
||||
|
||||
import { DesktopAutotypeService } from "../services/desktop-autotype.service";
|
||||
|
||||
export class MainDesktopAutotypeService {
|
||||
@@ -17,6 +19,10 @@ export class MainDesktopAutotypeService {
|
||||
private enableAutotype() {
|
||||
// eslint-disable-next-line no-console
|
||||
console.log("Enabling Autotype...");
|
||||
|
||||
const result = autotype.getForegroundWindowTitle();
|
||||
// eslint-disable-next-line no-console
|
||||
console.log("Window Title: " + result);
|
||||
}
|
||||
|
||||
// TODO: this will call into desktop native code
|
||||
|
||||
Reference in New Issue
Block a user