mirror of
https://github.com/bitwarden/browser
synced 2025-12-16 08:13:42 +00:00
[PM-9126] COM Object Registration (#13278)
* PM-9126: Initial scaffolding for com object registration * PM-9126: Clean Up PACOMObject trait and impl * PM-9126: Add unsafe tests * PM-9126: Clean up registration PR with a working CoRegisterClassObject call * PM-9126: Add AddAuthenticator fn call * PM-9126: Load AddAuthenticator fn call dynamically * PM-9126: Add AddAuthenticator experiments * PR-9126: add brackets around guids * PM-9126: clean up part 1 * PM-9126: Cleanup changes * Only call the register function if on Windows * PM-9126: Block two generated types that create issues for the i686-pc-windows-msvc target * PM-9126: Refine bindings file * PM-9126: Address PR comments part 1 * PM-9126: Address PR comments part 2 * PM-9126: Return result in napi layer * PM-9126: Propogate error from add authenticator call * PM-9126: Change for version update
This commit is contained in:
2
.github/CODEOWNERS
vendored
2
.github/CODEOWNERS
vendored
@@ -122,7 +122,7 @@ apps/desktop/src/autofill @bitwarden/team-autofill-dev
|
|||||||
libs/common/src/autofill @bitwarden/team-autofill-dev
|
libs/common/src/autofill @bitwarden/team-autofill-dev
|
||||||
apps/desktop/macos/autofill-extension @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/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/windows_plugin_authenticator @bitwarden/team-autofill-dev
|
||||||
# DuckDuckGo integration
|
# DuckDuckGo integration
|
||||||
apps/desktop/native-messaging-test-runner @bitwarden/team-autofill-dev
|
apps/desktop/native-messaging-test-runner @bitwarden/team-autofill-dev
|
||||||
apps/desktop/src/services/duckduckgo-message-handler.service.ts @bitwarden/team-autofill-dev
|
apps/desktop/src/services/duckduckgo-message-handler.service.ts @bitwarden/team-autofill-dev
|
||||||
|
|||||||
18
apps/desktop/desktop_native/Cargo.lock
generated
18
apps/desktop/desktop_native/Cargo.lock
generated
@@ -996,6 +996,7 @@ dependencies = [
|
|||||||
"tokio-stream",
|
"tokio-stream",
|
||||||
"tokio-util",
|
"tokio-util",
|
||||||
"windows-registry",
|
"windows-registry",
|
||||||
|
"windows_plugin_authenticator",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -3534,13 +3535,6 @@ dependencies = [
|
|||||||
"windows-link",
|
"windows-link",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "windows-plugin-authenticator"
|
|
||||||
version = "0.0.0"
|
|
||||||
dependencies = [
|
|
||||||
"bindgen",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows-registry"
|
name = "windows-registry"
|
||||||
version = "0.4.0"
|
version = "0.4.0"
|
||||||
@@ -3737,6 +3731,16 @@ version = "0.53.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "581fee95406bb13382d2f65cd4a908ca7b1e4c2f1917f143ba16efe98a589b5d"
|
checksum = "581fee95406bb13382d2f65cd4a908ca7b1e4c2f1917f143ba16efe98a589b5d"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_plugin_authenticator"
|
||||||
|
version = "0.0.0"
|
||||||
|
dependencies = [
|
||||||
|
"bindgen",
|
||||||
|
"hex",
|
||||||
|
"windows 0.61.1",
|
||||||
|
"windows-core 0.61.0",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_x86_64_gnu"
|
name = "windows_x86_64_gnu"
|
||||||
version = "0.48.5"
|
version = "0.48.5"
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[workspace]
|
[workspace]
|
||||||
resolver = "2"
|
resolver = "2"
|
||||||
members = ["napi", "core", "proxy", "macos_provider", "windows-plugin-authenticator"]
|
members = ["napi", "core", "proxy", "macos_provider", "windows_plugin_authenticator"]
|
||||||
|
|
||||||
[workspace.package]
|
[workspace.package]
|
||||||
version = "0.0.0"
|
version = "0.0.0"
|
||||||
@@ -58,6 +58,7 @@ typenum = "=1.17.0"
|
|||||||
uniffi = "=0.28.3"
|
uniffi = "=0.28.3"
|
||||||
widestring = "=1.1.0"
|
widestring = "=1.1.0"
|
||||||
windows = "=0.61.1"
|
windows = "=0.61.1"
|
||||||
|
windows-core = "=0.61.0"
|
||||||
windows-future = "=0.2.0"
|
windows-future = "=0.2.0"
|
||||||
windows-registry = "=0.4.0"
|
windows-registry = "=0.4.0"
|
||||||
zbus = "=4.4.0"
|
zbus = "=4.4.0"
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ tokio-stream = { workspace = true }
|
|||||||
|
|
||||||
[target.'cfg(windows)'.dependencies]
|
[target.'cfg(windows)'.dependencies]
|
||||||
windows-registry = { workspace = true }
|
windows-registry = { workspace = true }
|
||||||
|
windows_plugin_authenticator = { path = "../windows_plugin_authenticator" }
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
napi-build = { workspace = true }
|
napi-build = { workspace = true }
|
||||||
|
|||||||
3
apps/desktop/desktop_native/napi/index.d.ts
vendored
3
apps/desktop/desktop_native/napi/index.d.ts
vendored
@@ -182,3 +182,6 @@ export declare namespace autofill {
|
|||||||
export declare namespace crypto {
|
export declare namespace crypto {
|
||||||
export function argon2(secret: Buffer, salt: Buffer, iterations: number, memory: number, parallelism: number): Promise<Buffer>
|
export function argon2(secret: Buffer, salt: Buffer, iterations: number, memory: number, parallelism: number): Promise<Buffer>
|
||||||
}
|
}
|
||||||
|
export declare namespace passkey_authenticator {
|
||||||
|
export function register(): void
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate napi_derive;
|
extern crate napi_derive;
|
||||||
|
|
||||||
|
mod passkey_authenticator_internal;
|
||||||
mod registry;
|
mod registry;
|
||||||
|
|
||||||
#[napi]
|
#[napi]
|
||||||
@@ -796,3 +797,13 @@ pub mod crypto {
|
|||||||
.map(Buffer::from)
|
.map(Buffer::from)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[napi]
|
||||||
|
pub mod passkey_authenticator {
|
||||||
|
#[napi]
|
||||||
|
pub fn register() -> napi::Result<()> {
|
||||||
|
crate::passkey_authenticator_internal::register().map_err(|e| {
|
||||||
|
napi::Error::from_reason(format!("Passkey registration failed - Error: {e} - {e:?}"))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -0,0 +1,5 @@
|
|||||||
|
use anyhow::{bail, Result};
|
||||||
|
|
||||||
|
pub fn register() -> Result<()> {
|
||||||
|
bail!("Not implemented")
|
||||||
|
}
|
||||||
@@ -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::*;
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
use anyhow::{anyhow, Result};
|
||||||
|
|
||||||
|
pub fn register() -> Result<()> {
|
||||||
|
windows_plugin_authenticator::register().map_err(|e| anyhow!(e))?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
[package]
|
|
||||||
name = "windows-plugin-authenticator"
|
|
||||||
edition = { workspace = true }
|
|
||||||
license = { workspace = true }
|
|
||||||
version = { workspace = true }
|
|
||||||
publish = { workspace = true }
|
|
||||||
|
|
||||||
[target.'cfg(target_os = "windows")'.build-dependencies]
|
|
||||||
bindgen = { workspace = true }
|
|
||||||
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
#![cfg(target_os = "windows")]
|
|
||||||
|
|
||||||
mod pa;
|
|
||||||
|
|
||||||
pub fn get_version_number() -> u64 {
|
|
||||||
unsafe { pa::WebAuthNGetApiVersionNumber() }.into()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn add_authenticator() {
|
|
||||||
unimplemented!();
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
[package]
|
||||||
|
name = "windows_plugin_authenticator"
|
||||||
|
version = { workspace = true }
|
||||||
|
edition = { workspace = true }
|
||||||
|
license = { workspace = true }
|
||||||
|
publish = { workspace = true }
|
||||||
|
|
||||||
|
[target.'cfg(target_os = "windows")'.build-dependencies]
|
||||||
|
bindgen = { workspace = true }
|
||||||
|
|
||||||
|
[target.'cfg(windows)'.dependencies]
|
||||||
|
windows = { workspace = true, features = ["Win32_Foundation", "Win32_Security", "Win32_System_Com", "Win32_System_LibraryLoader" ] }
|
||||||
|
windows-core = { workspace = true }
|
||||||
|
hex = { workspace = true }
|
||||||
@@ -10,12 +10,16 @@ fn windows() {
|
|||||||
let bindings = bindgen::Builder::default()
|
let bindings = bindgen::Builder::default()
|
||||||
.header("pluginauthenticator.hpp")
|
.header("pluginauthenticator.hpp")
|
||||||
.parse_callbacks(Box::new(bindgen::CargoCallbacks::new()))
|
.parse_callbacks(Box::new(bindgen::CargoCallbacks::new()))
|
||||||
|
.allowlist_type("DWORD")
|
||||||
|
.allowlist_type("PBYTE")
|
||||||
|
.allowlist_type("EXPERIMENTAL.*")
|
||||||
|
.allowlist_function("WebAuthNGetApiVersionNumber")
|
||||||
.generate()
|
.generate()
|
||||||
.expect("Unable to generate bindings.");
|
.expect("Unable to generate bindings.");
|
||||||
|
|
||||||
bindings
|
bindings
|
||||||
.write_to_file(format!(
|
.write_to_file(format!(
|
||||||
"{}\\windows_pluginauthenticator_bindings.rs",
|
"{}\\windows_plugin_authenticator_bindings.rs",
|
||||||
out_dir
|
out_dir
|
||||||
))
|
))
|
||||||
.expect("Couldn't write bindings.");
|
.expect("Couldn't write bindings.");
|
||||||
@@ -0,0 +1,264 @@
|
|||||||
|
#![cfg(target_os = "windows")]
|
||||||
|
#![allow(non_snake_case)]
|
||||||
|
#![allow(non_camel_case_types)]
|
||||||
|
|
||||||
|
mod pa;
|
||||||
|
|
||||||
|
use pa::{
|
||||||
|
DWORD, EXPERIMENTAL_PCWEBAUTHN_PLUGIN_CANCEL_OPERATION_REQUEST,
|
||||||
|
EXPERIMENTAL_PCWEBAUTHN_PLUGIN_OPERATION_REQUEST,
|
||||||
|
EXPERIMENTAL_PWEBAUTHN_PLUGIN_ADD_AUTHENTICATOR_RESPONSE,
|
||||||
|
EXPERIMENTAL_PWEBAUTHN_PLUGIN_OPERATION_RESPONSE,
|
||||||
|
EXPERIMENTAL_WEBAUTHN_PLUGIN_ADD_AUTHENTICATOR_RESPONSE, PBYTE,
|
||||||
|
};
|
||||||
|
use std::ffi::c_uchar;
|
||||||
|
use std::ptr;
|
||||||
|
use windows::Win32::Foundation::*;
|
||||||
|
use windows::Win32::System::Com::*;
|
||||||
|
use windows::Win32::System::LibraryLoader::*;
|
||||||
|
use windows_core::*;
|
||||||
|
|
||||||
|
const AUTHENTICATOR_NAME: &str = "Bitwarden Desktop Authenticator";
|
||||||
|
//const AAGUID: &str = "d548826e-79b4-db40-a3d8-11116f7e8349";
|
||||||
|
const CLSID: &str = "0f7dc5d9-69ce-4652-8572-6877fd695062";
|
||||||
|
const RPID: &str = "bitwarden.com";
|
||||||
|
|
||||||
|
/// Returns the current Windows WebAuthN version.
|
||||||
|
pub fn get_version_number() -> u32 {
|
||||||
|
unsafe { pa::WebAuthNGetApiVersionNumber() }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Handles initialization and registration for the Bitwarden desktop app as a
|
||||||
|
/// plugin authenticator with Windows.
|
||||||
|
/// For now, also adds the authenticator
|
||||||
|
pub fn register() -> std::result::Result<(), String> {
|
||||||
|
initialize_com_library()?;
|
||||||
|
|
||||||
|
register_com_library()?;
|
||||||
|
|
||||||
|
add_authenticator()?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Initializes the COM library for use on the calling thread,
|
||||||
|
/// and registers + sets the security values.
|
||||||
|
fn initialize_com_library() -> std::result::Result<(), String> {
|
||||||
|
let result = unsafe { CoInitializeEx(None, COINIT_APARTMENTTHREADED) };
|
||||||
|
|
||||||
|
if result.is_err() {
|
||||||
|
return Err(format!(
|
||||||
|
"Error: couldn't initialize the COM library\n{}",
|
||||||
|
result.message()
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
match unsafe {
|
||||||
|
CoInitializeSecurity(
|
||||||
|
None,
|
||||||
|
-1,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
RPC_C_AUTHN_LEVEL_DEFAULT,
|
||||||
|
RPC_C_IMP_LEVEL_IMPERSONATE,
|
||||||
|
None,
|
||||||
|
EOAC_NONE,
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
} {
|
||||||
|
Ok(_) => Ok(()),
|
||||||
|
Err(e) => Err(format!(
|
||||||
|
"Error: couldn't initialize COM security\n{}",
|
||||||
|
e.message()
|
||||||
|
)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Registers the Bitwarden Plugin Authenticator COM library with Windows.
|
||||||
|
fn register_com_library() -> std::result::Result<(), String> {
|
||||||
|
static FACTORY: windows_core::StaticComObject<Factory> = Factory().into_static();
|
||||||
|
let clsid: *const GUID = &GUID::from_u128(0xa98925d161f640de9327dc418fcb2ff4);
|
||||||
|
|
||||||
|
match unsafe {
|
||||||
|
CoRegisterClassObject(
|
||||||
|
clsid,
|
||||||
|
FACTORY.as_interface_ref(),
|
||||||
|
CLSCTX_LOCAL_SERVER,
|
||||||
|
REGCLS_MULTIPLEUSE,
|
||||||
|
)
|
||||||
|
} {
|
||||||
|
Ok(_) => Ok(()),
|
||||||
|
Err(e) => Err(format!(
|
||||||
|
"Error: couldn't register the COM library\n{}",
|
||||||
|
e.message()
|
||||||
|
)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Adds Bitwarden as a plugin authenticator.
|
||||||
|
fn add_authenticator() -> std::result::Result<(), String> {
|
||||||
|
let authenticator_name: HSTRING = AUTHENTICATOR_NAME.into();
|
||||||
|
let authenticator_name_ptr = PCWSTR(authenticator_name.as_ptr()).as_ptr();
|
||||||
|
|
||||||
|
let clsid: HSTRING = format!("{{{}}}", CLSID).into();
|
||||||
|
let clsid_ptr = PCWSTR(clsid.as_ptr()).as_ptr();
|
||||||
|
|
||||||
|
let relying_party_id: HSTRING = RPID.into();
|
||||||
|
let relying_party_id_ptr = PCWSTR(relying_party_id.as_ptr()).as_ptr();
|
||||||
|
|
||||||
|
// let aaguid: HSTRING = format!("{{{}}}", AAGUID).into();
|
||||||
|
// let aaguid_ptr = PCWSTR(aaguid.as_ptr()).as_ptr();
|
||||||
|
|
||||||
|
// Example authenticator info blob
|
||||||
|
let cbor_authenticator_info = "A60182684649444F5F325F30684649444F5F325F310282637072666B686D61632D7365637265740350D548826E79B4DB40A3D811116F7E834904A362726BF5627570F5627576F5098168696E7465726E616C0A81A263616C672664747970656A7075626C69632D6B6579";
|
||||||
|
let mut authenticator_info_bytes = hex::decode(cbor_authenticator_info).unwrap();
|
||||||
|
|
||||||
|
let add_authenticator_options = EXPERIMENTAL_WEBAUTHN_PLUGIN_ADD_AUTHENTICATOR_OPTIONS {
|
||||||
|
pwszAuthenticatorName: authenticator_name_ptr,
|
||||||
|
pwszPluginClsId: clsid_ptr,
|
||||||
|
pwszPluginRpId: relying_party_id_ptr,
|
||||||
|
pwszLightThemeLogo: ptr::null(), // unused by Windows
|
||||||
|
pwszDarkThemeLogo: ptr::null(), // unused by Windows
|
||||||
|
cbAuthenticatorInfo: authenticator_info_bytes.len() as u32,
|
||||||
|
pbAuthenticatorInfo: authenticator_info_bytes.as_mut_ptr(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let plugin_signing_public_key_byte_count: DWORD = 0;
|
||||||
|
let mut plugin_signing_public_key: c_uchar = 0;
|
||||||
|
let plugin_signing_public_key_ptr: PBYTE = &mut plugin_signing_public_key;
|
||||||
|
|
||||||
|
let mut add_response = EXPERIMENTAL_WEBAUTHN_PLUGIN_ADD_AUTHENTICATOR_RESPONSE {
|
||||||
|
cbOpSignPubKey: plugin_signing_public_key_byte_count,
|
||||||
|
pbOpSignPubKey: plugin_signing_public_key_ptr,
|
||||||
|
};
|
||||||
|
let mut add_response_ptr: *mut EXPERIMENTAL_WEBAUTHN_PLUGIN_ADD_AUTHENTICATOR_RESPONSE =
|
||||||
|
&mut add_response;
|
||||||
|
|
||||||
|
let result = unsafe {
|
||||||
|
delay_load::<EXPERIMENTAL_WebAuthNPluginAddAuthenticatorFnDeclaration>(
|
||||||
|
s!("webauthn.dll"),
|
||||||
|
s!("EXPERIMENTAL_WebAuthNPluginAddAuthenticator"),
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
|
match result {
|
||||||
|
Some(api) => {
|
||||||
|
let result = unsafe { api(&add_authenticator_options, &mut add_response_ptr) };
|
||||||
|
|
||||||
|
if result.is_err() {
|
||||||
|
return Err(format!(
|
||||||
|
"Error: Error response from EXPERIMENTAL_WebAuthNPluginAddAuthenticator()\n{}",
|
||||||
|
result.message()
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
},
|
||||||
|
None => {
|
||||||
|
Err(String::from("Error: Can't complete add_authenticator(), as the function EXPERIMENTAL_WebAuthNPluginAddAuthenticator can't be found."))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
#[derive(Debug, Copy, Clone)]
|
||||||
|
pub struct EXPERIMENTAL_WEBAUTHN_PLUGIN_ADD_AUTHENTICATOR_OPTIONS {
|
||||||
|
pub pwszAuthenticatorName: *const u16,
|
||||||
|
pub pwszPluginClsId: *const u16,
|
||||||
|
pub pwszPluginRpId: *const u16,
|
||||||
|
pub pwszLightThemeLogo: *const u16,
|
||||||
|
pub pwszDarkThemeLogo: *const u16,
|
||||||
|
pub cbAuthenticatorInfo: u32,
|
||||||
|
pub pbAuthenticatorInfo: *const u8,
|
||||||
|
}
|
||||||
|
|
||||||
|
type EXPERIMENTAL_WebAuthNPluginAddAuthenticatorFnDeclaration = unsafe extern "cdecl" fn(
|
||||||
|
pPluginAddAuthenticatorOptions: *const EXPERIMENTAL_WEBAUTHN_PLUGIN_ADD_AUTHENTICATOR_OPTIONS,
|
||||||
|
ppPluginAddAuthenticatorResponse: *mut EXPERIMENTAL_PWEBAUTHN_PLUGIN_ADD_AUTHENTICATOR_RESPONSE,
|
||||||
|
)
|
||||||
|
-> HRESULT;
|
||||||
|
|
||||||
|
unsafe fn delay_load<T>(library: PCSTR, function: PCSTR) -> Option<T> {
|
||||||
|
let library = LoadLibraryExA(library, None, LOAD_LIBRARY_SEARCH_DEFAULT_DIRS);
|
||||||
|
|
||||||
|
let Ok(library) = library else {
|
||||||
|
return None;
|
||||||
|
};
|
||||||
|
|
||||||
|
let address = GetProcAddress(library, function);
|
||||||
|
|
||||||
|
if address.is_some() {
|
||||||
|
return Some(std::mem::transmute_copy(&address));
|
||||||
|
}
|
||||||
|
|
||||||
|
_ = FreeLibrary(library);
|
||||||
|
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
#[interface("e6466e9a-b2f3-47c5-b88d-89bc14a8d998")]
|
||||||
|
unsafe trait EXPERIMENTAL_IPluginAuthenticator: IUnknown {
|
||||||
|
fn EXPERIMENTAL_PluginMakeCredential(
|
||||||
|
&self,
|
||||||
|
request: EXPERIMENTAL_PCWEBAUTHN_PLUGIN_OPERATION_REQUEST,
|
||||||
|
response: *mut EXPERIMENTAL_PWEBAUTHN_PLUGIN_OPERATION_RESPONSE,
|
||||||
|
) -> HRESULT;
|
||||||
|
fn EXPERIMENTAL_PluginGetAssertion(
|
||||||
|
&self,
|
||||||
|
request: EXPERIMENTAL_PCWEBAUTHN_PLUGIN_OPERATION_REQUEST,
|
||||||
|
response: *mut EXPERIMENTAL_PWEBAUTHN_PLUGIN_OPERATION_RESPONSE,
|
||||||
|
) -> HRESULT;
|
||||||
|
fn EXPERIMENTAL_PluginCancelOperation(
|
||||||
|
&self,
|
||||||
|
request: EXPERIMENTAL_PCWEBAUTHN_PLUGIN_CANCEL_OPERATION_REQUEST,
|
||||||
|
) -> HRESULT;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[implement(EXPERIMENTAL_IPluginAuthenticator)]
|
||||||
|
struct PACOMObject;
|
||||||
|
|
||||||
|
impl EXPERIMENTAL_IPluginAuthenticator_Impl for PACOMObject_Impl {
|
||||||
|
unsafe fn EXPERIMENTAL_PluginMakeCredential(
|
||||||
|
&self,
|
||||||
|
_request: EXPERIMENTAL_PCWEBAUTHN_PLUGIN_OPERATION_REQUEST,
|
||||||
|
_response: *mut EXPERIMENTAL_PWEBAUTHN_PLUGIN_OPERATION_RESPONSE,
|
||||||
|
) -> HRESULT {
|
||||||
|
HRESULT(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn EXPERIMENTAL_PluginGetAssertion(
|
||||||
|
&self,
|
||||||
|
_request: EXPERIMENTAL_PCWEBAUTHN_PLUGIN_OPERATION_REQUEST,
|
||||||
|
_response: *mut EXPERIMENTAL_PWEBAUTHN_PLUGIN_OPERATION_RESPONSE,
|
||||||
|
) -> HRESULT {
|
||||||
|
HRESULT(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn EXPERIMENTAL_PluginCancelOperation(
|
||||||
|
&self,
|
||||||
|
_request: EXPERIMENTAL_PCWEBAUTHN_PLUGIN_CANCEL_OPERATION_REQUEST,
|
||||||
|
) -> HRESULT {
|
||||||
|
HRESULT(0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[implement(IClassFactory)]
|
||||||
|
struct Factory();
|
||||||
|
|
||||||
|
impl IClassFactory_Impl for Factory_Impl {
|
||||||
|
fn CreateInstance(
|
||||||
|
&self,
|
||||||
|
outer: Ref<IUnknown>,
|
||||||
|
iid: *const GUID,
|
||||||
|
object: *mut *mut core::ffi::c_void,
|
||||||
|
) -> Result<()> {
|
||||||
|
assert!(outer.is_null());
|
||||||
|
let unknown: IInspectable = PACOMObject.into();
|
||||||
|
unsafe { unknown.query(iid, object).ok() }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn LockServer(&self, lock: BOOL) -> Result<()> {
|
||||||
|
assert!(lock.as_bool());
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -11,5 +11,5 @@
|
|||||||
|
|
||||||
include!(concat!(
|
include!(concat!(
|
||||||
env!("OUT_DIR"),
|
env!("OUT_DIR"),
|
||||||
"/windows_pluginauthenticator_bindings.rs"
|
"/windows_plugin_authenticator_bindings.rs"
|
||||||
));
|
));
|
||||||
Reference in New Issue
Block a user