mirror of
https://github.com/bitwarden/browser
synced 2026-02-04 10:43:47 +00:00
PM-19255: Initial add (refactor) for add credentials
This commit is contained in:
@@ -4,12 +4,14 @@
|
||||
|
||||
use std::ffi::c_uchar;
|
||||
use std::ptr;
|
||||
use webauthn::*;
|
||||
use windows::Win32::Foundation::*;
|
||||
use windows::Win32::System::Com::*;
|
||||
use windows::Win32::System::LibraryLoader::*;
|
||||
use windows_core::*;
|
||||
|
||||
mod pluginauthenticator;
|
||||
mod util;
|
||||
mod webauthn;
|
||||
|
||||
const AUTHENTICATOR_NAME: &str = "Bitwarden Desktop Authenticator";
|
||||
@@ -27,6 +29,25 @@ pub fn register() -> std::result::Result<(), String> {
|
||||
|
||||
add_authenticator()?;
|
||||
|
||||
// add test credential
|
||||
let test_credential = ExperimentalWebAuthnPluginCredentialDetails::create(
|
||||
String::from("32"),
|
||||
String::from("webauthn.io"),
|
||||
String::from("WebAuthn Website"),
|
||||
String::from("14"),
|
||||
String::from("web user name"),
|
||||
String::from("web user display name"),
|
||||
);
|
||||
let test_credential_list: Vec<ExperimentalWebAuthnPluginCredentialDetails> =
|
||||
vec![test_credential];
|
||||
let credentials = ExperimentalWebAuthnPluginCredentialDetailsList::create(
|
||||
String::from(CLSID),
|
||||
test_credential_list,
|
||||
);
|
||||
|
||||
let result = add_credentials(credentials);
|
||||
println!("test: {:?}", result);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -105,7 +126,7 @@ fn add_authenticator() -> std::result::Result<(), String> {
|
||||
|
||||
let add_authenticator_options = webauthn::ExperimentalWebAuthnPluginAddAuthenticatorOptions {
|
||||
authenticator_name: authenticator_name_ptr,
|
||||
com_clsid: clsid_ptr,
|
||||
plugin_clsid: clsid_ptr,
|
||||
rpid: relying_party_id_ptr,
|
||||
light_theme_logo: ptr::null(), // unused by Windows
|
||||
dark_theme_logo: ptr::null(), // unused by Windows
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
/*
|
||||
This file exposes the functions and types defined here: https://github.com/microsoft/webauthn/blob/master/experimental/pluginauthenticator.h
|
||||
This file exposes safe functions and types for interacting with the experimental
|
||||
Windows Plugin Authenticator API defined here:
|
||||
|
||||
https://github.com/microsoft/webauthn/blob/master/experimental/pluginauthenticator.h
|
||||
*/
|
||||
|
||||
use windows::Win32::System::Com::*;
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
use windows::Win32::Foundation::*;
|
||||
use windows::Win32::System::LibraryLoader::*;
|
||||
use windows_core::*;
|
||||
|
||||
pub 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
|
||||
}
|
||||
|
||||
pub trait WindowsString {
|
||||
fn into_win_utf8(self: Self) -> (*mut u8, u32);
|
||||
fn into_win_utf16(self: Self) -> (*mut u16, u32);
|
||||
}
|
||||
|
||||
impl WindowsString for String {
|
||||
fn into_win_utf8(self: Self) -> (*mut u8, u32) {
|
||||
let mut v = self.into_bytes();
|
||||
v.push(0);
|
||||
|
||||
(v.as_mut_ptr(), v.len() as u32)
|
||||
}
|
||||
|
||||
fn into_win_utf16(self: Self) -> (*mut u16, u32) {
|
||||
let mut v: Vec<u16> = self.encode_utf16().collect();
|
||||
v.push(0);
|
||||
|
||||
(v.as_mut_ptr(), v.len() as u32)
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,19 @@
|
||||
/*
|
||||
This file exposes the functions and types defined here: https://github.com/microsoft/webauthn/blob/master/experimental/webauthn.h
|
||||
This file exposes safe functions and types for interacting with the experimental
|
||||
Windows WebAuthn API defined here:
|
||||
|
||||
https://github.com/microsoft/webauthn/blob/master/experimental/webauthn.h
|
||||
*/
|
||||
|
||||
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::*;
|
||||
|
||||
use crate::util::*;
|
||||
|
||||
/// Used when adding a Windows plugin authenticator.
|
||||
/// Header File Name: _EXPERIMENTAL_WEBAUTHN_PLUGIN_ADD_AUTHENTICATOR_OPTIONS
|
||||
/// Header File Usage: EXPERIMENTAL_WebAuthNPluginAddAuthenticator()
|
||||
@@ -9,7 +21,7 @@
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct ExperimentalWebAuthnPluginAddAuthenticatorOptions {
|
||||
pub authenticator_name: *const u16,
|
||||
pub com_clsid: *const u16,
|
||||
pub plugin_clsid: *const u16,
|
||||
pub rpid: *const u16,
|
||||
pub light_theme_logo: *const u16,
|
||||
pub dark_theme_logo: *const u16,
|
||||
@@ -27,3 +39,132 @@ pub struct ExperimentalWebAuthnPluginAddAuthenticatorResponse {
|
||||
pub plugin_operation_signing_key_byte_count: u32,
|
||||
pub plugin_operation_signing_key: *mut u8,
|
||||
}
|
||||
|
||||
/// Represents a credential.
|
||||
/// Header File Name: _EXPERIMENTAL_WEBAUTHN_PLUGIN_CREDENTIAL_DETAILS
|
||||
/// Header File Usage: _EXPERIMENTAL_WEBAUTHN_PLUGIN_CREDENTIAL_DETAILS_LIST
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct ExperimentalWebAuthnPluginCredentialDetails {
|
||||
pub credential_id_byte_count: u32,
|
||||
pub credential_id_pointer: *mut u8,
|
||||
pub rpid: *mut u16,
|
||||
pub rp_friendly_name: *mut u16,
|
||||
pub user_id_byte_count: u32,
|
||||
pub user_id: *mut u16,
|
||||
pub user_name: *mut u16,
|
||||
pub user_display_name: *mut u16,
|
||||
}
|
||||
|
||||
impl ExperimentalWebAuthnPluginCredentialDetails {
|
||||
pub fn create(
|
||||
credential_id: String,
|
||||
rpid: String,
|
||||
rp_friendly_name: String,
|
||||
user_id: String,
|
||||
user_name: String,
|
||||
user_display_name: String,
|
||||
) -> Self {
|
||||
let (credential_id_pointer, credential_id_byte_count) = credential_id.into_win_utf8();
|
||||
let (user_id, user_id_byte_count) = user_id.into_win_utf16();
|
||||
|
||||
Self {
|
||||
credential_id_byte_count,
|
||||
credential_id_pointer,
|
||||
rpid: rpid.into_win_utf16().0,
|
||||
rp_friendly_name: rp_friendly_name.into_win_utf16().0,
|
||||
user_id_byte_count,
|
||||
user_id,
|
||||
user_name: user_name.into_win_utf16().0,
|
||||
user_display_name: user_display_name.into_win_utf16().0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Represents a list of credentials.
|
||||
/// Header File Name: _EXPERIMENTAL_WEBAUTHN_PLUGIN_CREDENTIAL_DETAILS_LIST
|
||||
/// Header File Usage: EXPERIMENTAL_WebAuthNPluginAuthenticatorAddCredentials()
|
||||
/// EXPERIMENTAL_WebAuthNPluginAuthenticatorRemoveCredentials()
|
||||
/// EXPERIMENTAL_WebAuthNPluginAuthenticatorGetAllCredentials()
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct ExperimentalWebAuthnPluginCredentialDetailsList {
|
||||
pub plugin_clsid: *mut u16,
|
||||
pub credential_count: u32,
|
||||
pub credentials: *mut *mut ExperimentalWebAuthnPluginCredentialDetails,
|
||||
}
|
||||
|
||||
/*
|
||||
let mut credentials: Vec<ExperimentalWebAuthnPluginCredentialDetails>
|
||||
|
||||
let mut credentials: Vec<*mut ExperimentalWebAuthnPluginCredentialDetails> = credentials
|
||||
.iter()
|
||||
.map(|cred| cred as *mut _)
|
||||
.collect();
|
||||
|
||||
let credentials_len = credentials.len();
|
||||
let credentials_capacity = credentials.capacity();
|
||||
let mut credentials_pointer = credentials.as_mut_ptr();
|
||||
std::mem::forget(credentials);
|
||||
*/
|
||||
|
||||
impl ExperimentalWebAuthnPluginCredentialDetailsList {
|
||||
pub fn create(
|
||||
clsid: String,
|
||||
mut credentials: Vec<ExperimentalWebAuthnPluginCredentialDetails>,
|
||||
) -> Self {
|
||||
let mut credentials: Vec<*mut ExperimentalWebAuthnPluginCredentialDetails> = credentials
|
||||
.into_iter()
|
||||
.map(|mut cred| {
|
||||
let cred_pointer: *mut ExperimentalWebAuthnPluginCredentialDetails = &mut cred;
|
||||
cred_pointer
|
||||
})
|
||||
.collect();
|
||||
|
||||
let credentials_len = credentials.len();
|
||||
let _credentials_capacity = credentials.capacity();
|
||||
let mut credentials_pointer = credentials.as_mut_ptr();
|
||||
// TODO: remember the above 3 so it can be re-created and dropped later - refactor this
|
||||
std::mem::forget(credentials); // forget so Rust doesn't drop the memory
|
||||
|
||||
Self {
|
||||
plugin_clsid: clsid.into_win_utf16().0,
|
||||
credential_count: credentials_len as u32,
|
||||
credentials: credentials_pointer,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type EXPERIMENTAL_WebAuthNPluginAuthenticatorAddCredentialsFnDeclaration =
|
||||
unsafe extern "cdecl" fn(
|
||||
pCredentialDetailsList: *mut ExperimentalWebAuthnPluginCredentialDetailsList,
|
||||
) -> HRESULT;
|
||||
|
||||
pub fn add_credentials(
|
||||
mut credentials_list: ExperimentalWebAuthnPluginCredentialDetailsList,
|
||||
) -> std::result::Result<(), String> {
|
||||
let result = unsafe {
|
||||
delay_load::<EXPERIMENTAL_WebAuthNPluginAuthenticatorAddCredentialsFnDeclaration>(
|
||||
s!("webauthn.dll"),
|
||||
s!("EXPERIMENTAL_WebAuthNPluginAuthenticatorAddCredentials"),
|
||||
)
|
||||
};
|
||||
|
||||
match result {
|
||||
Some(api) => {
|
||||
let result = unsafe { api(&mut credentials_list) };
|
||||
|
||||
if result.is_err() {
|
||||
return Err(format!(
|
||||
"Error: Error response from EXPERIMENTAL_WebAuthNPluginAuthenticatorAddCredentials()\n{}",
|
||||
result.message()
|
||||
));
|
||||
}
|
||||
|
||||
Ok(())
|
||||
},
|
||||
None => {
|
||||
Err(String::from("Error: Can't complete add_credentials(), as the function EXPERIMENTAL_WebAuthNPluginAuthenticatorAddCredentials can't be loaded."))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -162,7 +162,7 @@
|
||||
"backgroundColor": "#175DDC",
|
||||
"applicationId": "bitwardendesktop",
|
||||
"identityName": "8bitSolutionsLLC.bitwardendesktop",
|
||||
"publisher": "CN=14D52771-DE3C-4886-B8BF-825BA7690418",
|
||||
"publisher": "CN=com.bitwarden.localdevelopment",
|
||||
"publisherDisplayName": "Bitwarden Inc",
|
||||
"languages": [
|
||||
"en-US",
|
||||
|
||||
@@ -46,7 +46,7 @@
|
||||
"pack:mac:mas:with-extension": "npm run clean:dist && npm run build:macos-extension:mas && electron-builder --mac mas --universal -p never",
|
||||
"pack:mac:masdev": "npm run clean:dist && electron-builder --mac mas-dev --universal -p never",
|
||||
"pack:mac:masdev:with-extension": "npm run clean:dist && npm run build:macos-extension:masdev && electron-builder --mac mas-dev --universal -p never",
|
||||
"pack:win": "npm run clean:dist && electron-builder --win --x64 --arm64 --ia32 -p never -c.win.certificateSubjectName=\"8bit Solutions LLC\"",
|
||||
"pack:win": "npm run clean:dist && electron-builder --win --x64 --arm64 --ia32 -p never",
|
||||
"pack:win:ci": "npm run clean:dist && electron-builder --win --x64 --arm64 --ia32 -p never",
|
||||
"dist:dir": "npm run build && npm run pack:dir",
|
||||
"dist:lin": "npm run build && npm run pack:lin",
|
||||
|
||||
@@ -3,6 +3,8 @@ import * as path from "path";
|
||||
|
||||
import { app } from "electron";
|
||||
|
||||
import { passkey_authenticator } from "@bitwarden/desktop-napi";
|
||||
|
||||
if (
|
||||
process.platform === "darwin" &&
|
||||
process.argv.some((arg) => arg.indexOf("chrome-extension://") !== -1 || arg.indexOf("{") !== -1)
|
||||
@@ -40,6 +42,8 @@ if (
|
||||
// eslint-disable-next-line
|
||||
const Main = require("./main").Main;
|
||||
|
||||
passkey_authenticator.register();
|
||||
|
||||
const main = new Main();
|
||||
main.bootstrap();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user