mirror of
https://github.com/bitwarden/browser
synced 2026-02-08 12:40:26 +00:00
Add native transfer_focus() method
This commit is contained in:
1
apps/desktop/desktop_native/Cargo.lock
generated
1
apps/desktop/desktop_native/Cargo.lock
generated
@@ -938,6 +938,7 @@ dependencies = [
|
||||
"tokio",
|
||||
"tracing",
|
||||
"tracing-subscriber",
|
||||
"windows 0.61.3",
|
||||
"windows-registry",
|
||||
"windows_plugin_authenticator",
|
||||
]
|
||||
|
||||
@@ -27,6 +27,7 @@ tracing = { workspace = true }
|
||||
tracing-subscriber = { workspace = true }
|
||||
|
||||
[target.'cfg(windows)'.dependencies]
|
||||
windows = { workspace = true }
|
||||
windows-registry = { workspace = true }
|
||||
windows_plugin_authenticator = { path = "../windows_plugin_authenticator" }
|
||||
|
||||
|
||||
1
apps/desktop/desktop_native/napi/index.d.ts
vendored
1
apps/desktop/desktop_native/napi/index.d.ts
vendored
@@ -147,6 +147,7 @@ export declare namespace autostart {
|
||||
}
|
||||
export declare namespace autofill {
|
||||
export function runCommand(value: string): Promise<string>
|
||||
export function transferFocus(handle: Array<number>): Promise<void>
|
||||
export const enum UserVerification {
|
||||
Preferred = 'preferred',
|
||||
Required = 'required',
|
||||
|
||||
@@ -636,6 +636,8 @@ pub mod autofill {
|
||||
use serde::{de::DeserializeOwned, Deserialize, Serialize};
|
||||
use tracing::error;
|
||||
|
||||
use crate::passkey_authenticator_internal;
|
||||
|
||||
#[napi]
|
||||
pub async fn run_command(value: String) -> napi::Result<String> {
|
||||
desktop_core::autofill::run_command(value)
|
||||
@@ -643,6 +645,12 @@ pub mod autofill {
|
||||
.map_err(|e| napi::Error::from_reason(e.to_string()))
|
||||
}
|
||||
|
||||
#[napi]
|
||||
pub async fn transfer_focus(handle: Vec<u8>) -> napi::Result<()> {
|
||||
passkey_authenticator_internal::transfer_focus(handle)
|
||||
.map_err(|e| napi::Error::from_reason(e.to_string()))
|
||||
}
|
||||
|
||||
#[derive(Debug, serde::Serialize, serde:: Deserialize)]
|
||||
pub enum BitwardenError {
|
||||
Internal(String),
|
||||
|
||||
@@ -3,3 +3,7 @@ use anyhow::{bail, Result};
|
||||
pub fn register() -> Result<()> {
|
||||
bail!("Not implemented")
|
||||
}
|
||||
|
||||
pub fn transfer_focus(handle: Vec<u8>) -> Result<()> {
|
||||
bail!("Not implemented")
|
||||
}
|
||||
|
||||
@@ -1,7 +1,33 @@
|
||||
use anyhow::{anyhow, Result};
|
||||
use windows::Win32::{
|
||||
Foundation::HWND,
|
||||
UI::{Input::KeyboardAndMouse::SetFocus, WindowsAndMessaging::BringWindowToTop},
|
||||
};
|
||||
|
||||
pub fn register() -> Result<()> {
|
||||
windows_plugin_authenticator::register().map_err(|e| anyhow!(e))?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn transfer_focus(handle: Vec<u8>) -> Result<()> {
|
||||
unsafe {
|
||||
// SAFETY: We check to make sure that the vec is the expected size
|
||||
// before converting it. If the handle is invalid when passed to
|
||||
// Windows, the request will be rejected.
|
||||
if handle.len() != size_of::<HWND>() {
|
||||
return Err(anyhow!("Invalid window handle received: {:?}", handle));
|
||||
}
|
||||
|
||||
let hwnd = *handle.as_ptr().cast();
|
||||
|
||||
tracing::debug!("Transferring focus to {hwnd:?}");
|
||||
let result = SetFocus(Some(hwnd));
|
||||
tracing::debug!("SetFocus? {result:?}");
|
||||
|
||||
let result = BringWindowToTop(hwnd);
|
||||
tracing::debug!("BringWindowToTop? {result:?}");
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -12,6 +12,8 @@ export default {
|
||||
runCommand: <C extends Command>(params: RunCommandParams<C>): Promise<RunCommandResult<C>> =>
|
||||
ipcRenderer.invoke("autofill.runCommand", params),
|
||||
|
||||
transferFocus: (handle: Uint8Array) => ipcRenderer.invoke("autofill.transferFocus", handle),
|
||||
|
||||
listenerReady: () => ipcRenderer.send("autofill.listenerReady"),
|
||||
|
||||
listenPasskeyRegistration: (
|
||||
|
||||
@@ -383,9 +383,11 @@ export class DesktopFido2UserInterfaceSession implements Fido2UserInterfaceSessi
|
||||
// TODO: modalState is just a proxy for what we actually want: whether the window is visible.
|
||||
// We should add a way for services to query window visibility.
|
||||
const modalState = await firstValueFrom(this.desktopSettingsService.modalMode$);
|
||||
const windowHandle = modalState.isModalModeActive ? await ipc.platform.getNativeWindowHandle() : this.windowObject.handle;
|
||||
|
||||
const uvRequest = ipc.autofill.runCommand<NativeAutofillUserVerificationCommand>({
|
||||
await ipc.autofill.transferFocus(windowHandle);
|
||||
// Ensure our window is hidden when showing the OS user verification dialog.
|
||||
this.logService.debug("Hiding UI");
|
||||
this.hideUi();
|
||||
const uvResult = await ipc.autofill.runCommand<NativeAutofillUserVerificationCommand>({
|
||||
namespace: "autofill",
|
||||
command: "user-verification",
|
||||
params: {
|
||||
@@ -395,12 +397,6 @@ export class DesktopFido2UserInterfaceSession implements Fido2UserInterfaceSessi
|
||||
displayHint,
|
||||
},
|
||||
});
|
||||
// Ensure our window is hidden when showing the OS user verification dialog.
|
||||
// TODO: This is prone to data races and, on Windows, may cause the Windows
|
||||
// Hello dialog not to have keyboard input focus. We need a better solution
|
||||
// than this.
|
||||
this.hideUi();
|
||||
const uvResult = await uvRequest;
|
||||
if (uvResult.type === "error") {
|
||||
this.logService.error("Error getting user verification", uvResult.error);
|
||||
return false;
|
||||
|
||||
@@ -84,6 +84,17 @@ export class NativeAutofillMain {
|
||||
},
|
||||
);
|
||||
|
||||
ipcMain.handle(
|
||||
"autofill.transferFocus",
|
||||
(
|
||||
_event: any,
|
||||
handle: Uint8Array,
|
||||
): Promise<void> => {
|
||||
return this.transferFocus(handle);
|
||||
},
|
||||
);
|
||||
|
||||
|
||||
this.ipcServer = await autofill.IpcServer.listen(
|
||||
"af",
|
||||
// RegistrationCallback
|
||||
@@ -228,4 +239,10 @@ export class NativeAutofillMain {
|
||||
return { type: "error", error: String(e) } as RunCommandResult<C>;
|
||||
}
|
||||
}
|
||||
|
||||
private transferFocus(handle: Uint8Array): Promise<void> {
|
||||
const h = Array.from(handle);
|
||||
this.logService.debug("Transferring focus to", h);
|
||||
return autofill.transferFocus(h);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user