[PS-1469] Ensure the window is focused when prompting for biometrics (#3534)

This commit is contained in:
Oscar Hinton 2022-09-15 16:17:09 +02:00 committed by GitHub
parent 8b73658e54
commit d2736fe035
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 49 additions and 8 deletions

View File

@ -30,6 +30,8 @@ windows = {version = "0.32.0", features = [
"Win32_Foundation",
"Win32_Security_Credentials",
"Win32_System_WinRT",
"Win32_UI_Input_KeyboardAndMouse",
"Win32_UI_WindowsAndMessaging",
]}
[target.'cfg(windows)'.dev-dependencies]

View File

@ -1,19 +1,33 @@
use anyhow::Result;
use windows::{
core::factory, Foundation::IAsyncOperation, Security::Credentials::UI::*,
Win32::Foundation::HWND, Win32::System::WinRT::IUserConsentVerifierInterop,
core::{factory, HSTRING},
Foundation::IAsyncOperation,
Security::Credentials::UI::*,
Win32::{
Foundation::HWND,
System::WinRT::IUserConsentVerifierInterop,
UI::{
Input::KeyboardAndMouse::{
self, keybd_event, GetAsyncKeyState, SetFocus, KEYEVENTF_EXTENDEDKEY,
KEYEVENTF_KEYUP, VK_MENU,
},
WindowsAndMessaging::{self, SetForegroundWindow},
},
},
};
pub fn prompt(hwnd: Vec<u8>, message: String) -> Result<bool> {
let interop = factory::<UserConsentVerifier, IUserConsentVerifierInterop>()?;
let h = isize::from_le_bytes(hwnd.try_into().unwrap());
let h = isize::from_le_bytes(hwnd.clone().try_into().unwrap());
let window = HWND(h);
let operation: IAsyncOperation<UserConsentVerificationResult> =
unsafe { interop.RequestVerificationForWindowAsync(window, message)? };
// The Windows Hello prompt is displayed inside the application window. For best result we
// should set the window to the foreground and focus it.
set_focus(window);
let result: UserConsentVerificationResult = operation.get()?;
let interop = factory::<UserConsentVerifier, IUserConsentVerifierInterop>()?;
let operation: IAsyncOperation<UserConsentVerificationResult> =
unsafe { interop.RequestVerificationForWindowAsync(window, &HSTRING::from(message))? };
let result = operation.get()?;
match result {
UserConsentVerificationResult::Verified => Ok(true),
@ -31,6 +45,31 @@ pub fn available() -> Result<bool> {
}
}
fn set_focus(window: HWND) {
let mut pressed = false;
unsafe {
// Simulate holding down Alt key to bypass windows limitations
// https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getasynckeystate#return-value
// The most significant bit indicates if the key is currently being pressed. This means the
// value will be negative if the key is pressed.
if GetAsyncKeyState(VK_MENU.0 as i32) >= 0 {
pressed = true;
keybd_event(VK_MENU.0 as u8, 0, KEYEVENTF_EXTENDEDKEY, 0);
}
SetForegroundWindow(window);
SetFocus(window);
if pressed {
keybd_event(
VK_MENU.0 as u8,
0,
KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP,
0,
);
}
}
}
#[cfg(test)]
mod tests {
use super::*;