wip passkey registration day 2
This commit is contained in:
Generated
+18
-18
@@ -24,8 +24,10 @@ dependencies = [
|
|||||||
"dioxus",
|
"dioxus",
|
||||||
"dioxus-primitives",
|
"dioxus-primitives",
|
||||||
"dotenv",
|
"dotenv",
|
||||||
|
"js-sys",
|
||||||
"prost",
|
"prost",
|
||||||
"serde",
|
"serde",
|
||||||
|
"serde-wasm-bindgen",
|
||||||
"serde_repr",
|
"serde_repr",
|
||||||
"tonic",
|
"tonic",
|
||||||
"tonic-build",
|
"tonic-build",
|
||||||
@@ -1669,10 +1671,12 @@ checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "js-sys"
|
name = "js-sys"
|
||||||
version = "0.3.91"
|
version = "0.3.95"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b49715b7073f385ba4bc528e5747d02e66cb39c6146efb66b781f131f0fb399c"
|
checksum = "2964e92d1d9dc3364cae4d718d93f227e3abb088e747d92e0395bfdedf1c12ca"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"futures-util",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"wasm-bindgen",
|
"wasm-bindgen",
|
||||||
]
|
]
|
||||||
@@ -3340,9 +3344,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasm-bindgen"
|
name = "wasm-bindgen"
|
||||||
version = "0.2.114"
|
version = "0.2.118"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "6532f9a5c1ece3798cb1c2cfdba640b9b3ba884f5db45973a6f442510a87d38e"
|
checksum = "0bf938a0bacb0469e83c1e148908bd7d5a6010354cf4fb73279b7447422e3a89"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
@@ -3353,23 +3357,19 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasm-bindgen-futures"
|
name = "wasm-bindgen-futures"
|
||||||
version = "0.4.64"
|
version = "0.4.68"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e9c5522b3a28661442748e09d40924dfb9ca614b21c00d3fd135720e48b67db8"
|
checksum = "f371d383f2fb139252e0bfac3b81b265689bf45b6874af544ffa4c975ac1ebf8"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
|
||||||
"futures-util",
|
|
||||||
"js-sys",
|
"js-sys",
|
||||||
"once_cell",
|
|
||||||
"wasm-bindgen",
|
"wasm-bindgen",
|
||||||
"web-sys",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasm-bindgen-macro"
|
name = "wasm-bindgen-macro"
|
||||||
version = "0.2.114"
|
version = "0.2.118"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "18a2d50fcf105fb33bb15f00e7a77b772945a2ee45dcf454961fd843e74c18e6"
|
checksum = "eeff24f84126c0ec2db7a449f0c2ec963c6a49efe0698c4242929da037ca28ed"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"quote",
|
"quote",
|
||||||
"wasm-bindgen-macro-support",
|
"wasm-bindgen-macro-support",
|
||||||
@@ -3377,9 +3377,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasm-bindgen-macro-support"
|
name = "wasm-bindgen-macro-support"
|
||||||
version = "0.2.114"
|
version = "0.2.118"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "03ce4caeaac547cdf713d280eda22a730824dd11e6b8c3ca9e42247b25c631e3"
|
checksum = "9d08065faf983b2b80a79fd87d8254c409281cf7de75fc4b773019824196c904"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bumpalo",
|
"bumpalo",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
@@ -3390,9 +3390,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasm-bindgen-shared"
|
name = "wasm-bindgen-shared"
|
||||||
version = "0.2.114"
|
version = "0.2.118"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "75a326b8c223ee17883a4251907455a2431acc2791c98c26279376490c378c16"
|
checksum = "5fd04d9e306f1907bd13c6361b5c6bfc7b3b3c095ed3f8a9246390f8dbdee129"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"unicode-ident",
|
"unicode-ident",
|
||||||
]
|
]
|
||||||
@@ -3412,9 +3412,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "web-sys"
|
name = "web-sys"
|
||||||
version = "0.3.91"
|
version = "0.3.95"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "854ba17bb104abfb26ba36da9729addc7ce7f06f5c0f90f3c391f8461cca21f9"
|
checksum = "4f2dfbb17949fa2088e5d39408c48368947b86f7834484e87b73de55bc14d97d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"js-sys",
|
"js-sys",
|
||||||
"wasm-bindgen",
|
"wasm-bindgen",
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ edition = "2024"
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
dioxus = { version = "0.7.5", features = ["router"] }
|
dioxus = { version = "0.7.5", features = ["router"] }
|
||||||
serde = "1.0.228"
|
serde = { version = "1.0.228", features = ["derive"] }
|
||||||
serde_repr = "0.1.20"
|
serde_repr = "0.1.20"
|
||||||
tonic = { version = "*", default-features = false, features = [
|
tonic = { version = "*", default-features = false, features = [
|
||||||
"codegen",
|
"codegen",
|
||||||
@@ -15,8 +15,10 @@ tonic = { version = "*", default-features = false, features = [
|
|||||||
] }
|
] }
|
||||||
prost = "0.13"
|
prost = "0.13"
|
||||||
tonic-web-wasm-client = "0.7"
|
tonic-web-wasm-client = "0.7"
|
||||||
web-sys = { version = "0.3.91", features = ["Storage", "Window", "Navigator", "CredentialsContainer", "CredentialCreationOptions"] }
|
web-sys = { version = "0.3.91", features = ["Storage", "Window", "Navigator", "CredentialsContainer", "CredentialCreationOptions", "AttestationConveyancePreference", "PublicKeyCredentialCreationOptions", "PublicKeyCredentialRpEntity", "PublicKeyCredentialUserEntity"] }
|
||||||
dioxus-primitives = { git = "https://github.com/DioxusLabs/components", version = "0.0.1", default-features = false }
|
dioxus-primitives = { git = "https://github.com/DioxusLabs/components", version = "0.0.1", default-features = false }
|
||||||
|
serde-wasm-bindgen = "0.6.5"
|
||||||
|
js-sys = "0.3.95"
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
tonic-build = { version = "*", default-features = false, features = ["prost"] }
|
tonic-build = { version = "*", default-features = false, features = ["prost"] }
|
||||||
|
|||||||
+9
-4
@@ -3,13 +3,15 @@ use std::env;
|
|||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
|
|
||||||
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
fn main() -> Result<(), Box<dyn std::error::Error>>
|
||||||
|
{
|
||||||
tonic_build::configure()
|
tonic_build::configure()
|
||||||
.build_server(false)
|
.build_server(false)
|
||||||
.build_client(true)
|
.build_client(true)
|
||||||
.compile_protos(
|
.compile_protos(
|
||||||
&[
|
&[
|
||||||
"../AobaServer/Proto/Aoba.proto",
|
"../AobaServer/Proto/Aoba.proto",
|
||||||
|
"../AobaServer/Proto/Account.proto",
|
||||||
"../AobaServer/Proto/Auth.proto",
|
"../AobaServer/Proto/Auth.proto",
|
||||||
"../AobaServer/Proto/Metrics.proto",
|
"../AobaServer/Proto/Metrics.proto",
|
||||||
"../AobaServer/Proto/Types.proto",
|
"../AobaServer/Proto/Types.proto",
|
||||||
@@ -20,15 +22,18 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn forward_env() {
|
fn forward_env()
|
||||||
|
{
|
||||||
let dest_path = "./src/env.rs";
|
let dest_path = "./src/env.rs";
|
||||||
let mut f = File::create(&dest_path).unwrap();
|
let mut f = File::create(&dest_path).unwrap();
|
||||||
f.write_all(b"// This file is automatically generated by build.rs\n\n")
|
f.write_all(b"// This file is automatically generated by build.rs\n\n")
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
dotenv().ok();
|
dotenv().ok();
|
||||||
for (key, value) in env::vars() {
|
for (key, value) in env::vars()
|
||||||
if key.starts_with("APP_") {
|
{
|
||||||
|
if key.starts_with("APP_")
|
||||||
|
{
|
||||||
f.write_all("#[allow(dead_code)]\n".as_bytes()).unwrap();
|
f.write_all("#[allow(dead_code)]\n".as_bytes()).unwrap();
|
||||||
let line = format!(
|
let line = format!(
|
||||||
"pub const {}: &'static str = \"{}\";\n",
|
"pub const {}: &'static str = \"{}\";\n",
|
||||||
|
|||||||
@@ -1,10 +1,15 @@
|
|||||||
use dioxus::prelude::*;
|
use dioxus::prelude::*;
|
||||||
use web_sys::{CredentialCreationOptions, window};
|
use js_sys::{Uint8Array, wasm_bindgen::JsValue};
|
||||||
|
use web_sys::{
|
||||||
|
CredentialCreationOptions, PublicKeyCredentialCreationOptions, PublicKeyCredentialRpEntity,
|
||||||
|
PublicKeyCredentialUserEntity, window,
|
||||||
|
};
|
||||||
|
|
||||||
use crate::components::basic::Button;
|
use crate::{components::basic::Button, rpc::aoba::PasskeyCredentialCreateOptions};
|
||||||
|
|
||||||
#[component]
|
#[component]
|
||||||
pub fn PasskeyRegistrationButton() -> Element {
|
pub fn PasskeyRegistrationButton() -> Element
|
||||||
|
{
|
||||||
rsx! {
|
rsx! {
|
||||||
Button{
|
Button{
|
||||||
text: "Register Passkey",
|
text: "Register Passkey",
|
||||||
@@ -15,22 +20,55 @@ pub fn PasskeyRegistrationButton() -> Element {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn start_passkey_registration() {
|
fn start_passkey_registration()
|
||||||
create_credential();
|
{
|
||||||
|
create_credential(todo!());
|
||||||
}
|
}
|
||||||
|
|
||||||
fn create_credential() {
|
fn create_credential(req_opts: PasskeyCredentialCreateOptions)
|
||||||
let credentials = window()
|
{
|
||||||
.expect("Failed to get window")
|
let window = window().expect("Window does not exist");
|
||||||
.navigator()
|
let credentaials = window.navigator().credentials();
|
||||||
.credentials();
|
|
||||||
|
|
||||||
|
let opts = opts_from_rpc(req_opts);
|
||||||
|
|
||||||
|
let result = credentaials.create_with_options(&opts);
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn opts_from_rpc(rpc_opts: PasskeyCredentialCreateOptions) -> CredentialCreationOptions
|
||||||
|
{
|
||||||
|
let opt_user = &rpc_opts.user.expect("user is missing");
|
||||||
|
let opt_rp = &rpc_opts.rp.expect("rp is missing");
|
||||||
let opts = CredentialCreationOptions::new();
|
let opts = CredentialCreationOptions::new();
|
||||||
let _result = credentials.create_with_options(&opts);
|
let rp = PublicKeyCredentialRpEntity::new(&opt_rp.name);
|
||||||
|
rp.set_id(&opt_rp.id);
|
||||||
|
|
||||||
|
let user = PublicKeyCredentialUserEntity::new_with_u8_array(
|
||||||
|
&opt_user.name,
|
||||||
|
&opt_user.display_name,
|
||||||
|
&to_u8_array(&opt_user.id),
|
||||||
|
);
|
||||||
|
let pub_key_opts = PublicKeyCredentialCreationOptions::new_with_u8_array(
|
||||||
|
&to_u8_array(&rpc_opts.challenge),
|
||||||
|
&JsValue::undefined(),
|
||||||
|
&rp,
|
||||||
|
&user,
|
||||||
|
);
|
||||||
|
//pub_key_opts.set_exclude_credentials(val);
|
||||||
|
opts.set_public_key(&pub_key_opts);
|
||||||
|
|
||||||
|
return opts;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn to_u8_array(value: &String) -> Uint8Array
|
||||||
|
{
|
||||||
|
todo!()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[component]
|
#[component]
|
||||||
pub fn PasskeyLoginButton() -> Element {
|
pub fn PasskeyLoginButton() -> Element
|
||||||
|
{
|
||||||
rsx! {
|
rsx! {
|
||||||
Button{
|
Button{
|
||||||
text: "Login with Passkey"
|
text: "Login with Passkey"
|
||||||
|
|||||||
+18
-1
@@ -6,7 +6,9 @@ use tonic_web_wasm_client::Client;
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
RPC_HOST,
|
RPC_HOST,
|
||||||
rpc::aoba::{auth_rpc_client::AuthRpcClient, metrics_rpc_client::MetricsRpcClient},
|
rpc::aoba::{
|
||||||
|
account_rpc_client::AccountRpcClient, auth_rpc_client::AuthRpcClient, metrics_rpc_client::MetricsRpcClient,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub mod aoba
|
pub mod aoba
|
||||||
@@ -17,6 +19,7 @@ pub mod aoba
|
|||||||
static RPC_CLIENT: RpcConnection = RpcConnection {
|
static RPC_CLIENT: RpcConnection = RpcConnection {
|
||||||
aoba: RwLock::new(None),
|
aoba: RwLock::new(None),
|
||||||
auth: RwLock::new(None),
|
auth: RwLock::new(None),
|
||||||
|
account: RwLock::new(None),
|
||||||
metrics: RwLock::new(None),
|
metrics: RwLock::new(None),
|
||||||
jwt: RwLock::new(None),
|
jwt: RwLock::new(None),
|
||||||
};
|
};
|
||||||
@@ -26,6 +29,7 @@ pub struct RpcConnection
|
|||||||
{
|
{
|
||||||
aoba: RwLock<Option<AobaRpcClient<InterceptedService<Client, AuthInterceptor>>>>,
|
aoba: RwLock<Option<AobaRpcClient<InterceptedService<Client, AuthInterceptor>>>>,
|
||||||
auth: RwLock<Option<AuthRpcClient<Client>>>,
|
auth: RwLock<Option<AuthRpcClient<Client>>>,
|
||||||
|
account: RwLock<Option<AccountRpcClient<InterceptedService<Client, AuthInterceptor>>>>,
|
||||||
metrics: RwLock<Option<MetricsRpcClient<InterceptedService<Client, AuthInterceptor>>>>,
|
metrics: RwLock<Option<MetricsRpcClient<InterceptedService<Client, AuthInterceptor>>>>,
|
||||||
jwt: RwLock<Option<String>>,
|
jwt: RwLock<Option<String>>,
|
||||||
}
|
}
|
||||||
@@ -38,6 +42,12 @@ impl RpcConnection
|
|||||||
return self.aoba.read().unwrap().clone().unwrap();
|
return self.aoba.read().unwrap().clone().unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_account_client(&self) -> AccountRpcClient<InterceptedService<Client, AuthInterceptor>>
|
||||||
|
{
|
||||||
|
self.ensure_client();
|
||||||
|
return self.account.read().unwrap().clone().unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
pub fn get_auth_client(&self) -> AuthRpcClient<Client>
|
pub fn get_auth_client(&self) -> AuthRpcClient<Client>
|
||||||
{
|
{
|
||||||
self.ensure_client();
|
self.ensure_client();
|
||||||
@@ -58,6 +68,8 @@ impl RpcConnection
|
|||||||
let aoba_client = AobaRpcClient::with_interceptor(wasm_client.clone(), AuthInterceptor);
|
let aoba_client = AobaRpcClient::with_interceptor(wasm_client.clone(), AuthInterceptor);
|
||||||
*self.aoba.write().unwrap() = Some(aoba_client);
|
*self.aoba.write().unwrap() = Some(aoba_client);
|
||||||
*self.auth.write().unwrap() = Some(AuthRpcClient::new(wasm_client.clone()));
|
*self.auth.write().unwrap() = Some(AuthRpcClient::new(wasm_client.clone()));
|
||||||
|
*self.account.write().unwrap() =
|
||||||
|
Some(AccountRpcClient::with_interceptor(wasm_client.clone(), AuthInterceptor));
|
||||||
*self.metrics.write().unwrap() =
|
*self.metrics.write().unwrap() =
|
||||||
Some(MetricsRpcClient::with_interceptor(wasm_client.clone(), AuthInterceptor));
|
Some(MetricsRpcClient::with_interceptor(wasm_client.clone(), AuthInterceptor));
|
||||||
}
|
}
|
||||||
@@ -90,6 +102,11 @@ pub fn get_auth_rpc_client() -> AuthRpcClient<Client>
|
|||||||
return RPC_CLIENT.get_auth_client();
|
return RPC_CLIENT.get_auth_client();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_account_rpc_client() -> AccountRpcClient<InterceptedService<Client, AuthInterceptor>>
|
||||||
|
{
|
||||||
|
return RPC_CLIENT.get_account_client();
|
||||||
|
}
|
||||||
|
|
||||||
pub fn get_metrics_rpc_client() -> MetricsRpcClient<InterceptedService<Client, AuthInterceptor>>
|
pub fn get_metrics_rpc_client() -> MetricsRpcClient<InterceptedService<Client, AuthInterceptor>>
|
||||||
{
|
{
|
||||||
return RPC_CLIENT.get_metrics_client();
|
return RPC_CLIENT.get_metrics_client();
|
||||||
|
|||||||
@@ -123,8 +123,28 @@ message PasskeyPayload {
|
|||||||
|
|
||||||
message PasskeyCredentialCreateOptions{
|
message PasskeyCredentialCreateOptions{
|
||||||
string challenge = 1;
|
string challenge = 1;
|
||||||
string userId = 2;
|
PublicKeyCredentialUser user = 2;
|
||||||
|
PublicKeyCredentialRpEntity rp = 3;
|
||||||
|
repeated PubKeyCredParam pubKeyParams = 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
message PubKeyCredParam{
|
||||||
|
string alg = 1;
|
||||||
|
string type = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
message PublicKeyCredentialRpEntity{
|
||||||
|
string id = 1;
|
||||||
|
string icon = 2;
|
||||||
|
string name = 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
message PublicKeyCredentialUser{
|
||||||
|
string id = 1;
|
||||||
|
string name = 2;
|
||||||
|
string displayName = 3;
|
||||||
|
}
|
||||||
|
|
||||||
message PasskeyRegistrationCredentials{
|
message PasskeyRegistrationCredentials{
|
||||||
string id = 1;
|
string id = 1;
|
||||||
string rawId = 2;
|
string rawId = 2;
|
||||||
@@ -137,3 +157,10 @@ message CredentialsClientResponse{
|
|||||||
string attestationObject = 2;
|
string attestationObject = 2;
|
||||||
string authenticatorData = 3;
|
string authenticatorData = 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
message PublicKeyCredentialDescriptor{
|
||||||
|
string type = 1;
|
||||||
|
string id = 2;
|
||||||
|
repeated string transports = 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -32,13 +32,16 @@ public class AccountRpcService(IFido2 fido2, AccountsService accounts) : Account
|
|||||||
var credOptions = fido2.RequestNewCredential(new RequestNewCredentialParams
|
var credOptions = fido2.RequestNewCredential(new RequestNewCredentialParams
|
||||||
{
|
{
|
||||||
User = user,
|
User = user,
|
||||||
ExcludeCredentials = curUser.CredentialDescriptors
|
ExcludeCredentials = curUser.CredentialDescriptors,
|
||||||
});
|
AuthenticatorSelection = new AuthenticatorSelection
|
||||||
return new PasskeyCredentialCreateOptions
|
|
||||||
{
|
{
|
||||||
Challenge = credOptions.Challenge.ToB64String().Replace('+', '-').Replace('/', '_'),
|
ResidentKey = Fido2NetLib.Objects.ResidentKeyRequirement.Required,
|
||||||
UserId = credOptions.User.Id.ToB64String().Replace('+', '-').Replace('/', '_')
|
UserVerification = Fido2NetLib.Objects.UserVerificationRequirement.Preferred
|
||||||
};
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
return credOptions.ToRPC();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override Task<Empty> CompletePasskeyRegistration(PasskeyRegistrationCredentials request, ServerCallContext context)
|
public override Task<Empty> CompletePasskeyRegistration(PasskeyRegistrationCredentials request, ServerCallContext context)
|
||||||
|
|||||||
@@ -0,0 +1,55 @@
|
|||||||
|
using Aoba.RPC;
|
||||||
|
|
||||||
|
using Isopoh.Cryptography.Argon2;
|
||||||
|
|
||||||
|
namespace AobaServer.Utils;
|
||||||
|
|
||||||
|
public static class PasskeyExtensions
|
||||||
|
{
|
||||||
|
public static PublicKeyCredentialRpEntity ToRPC(this Fido2NetLib.PublicKeyCredentialRpEntity value)
|
||||||
|
{
|
||||||
|
return new PublicKeyCredentialRpEntity
|
||||||
|
{
|
||||||
|
Id = value.Id,
|
||||||
|
Icon = value.Icon,
|
||||||
|
Name = value.Name,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public static PublicKeyCredentialUser ToRPC(this Fido2NetLib.Fido2User value)
|
||||||
|
{
|
||||||
|
return new PublicKeyCredentialUser
|
||||||
|
{
|
||||||
|
Id = value.Id.ToB64String(),
|
||||||
|
DisplayName = value.DisplayName,
|
||||||
|
Name = value.Name,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public static PubKeyCredParam ToRPC(this Fido2NetLib.PubKeyCredParam value)
|
||||||
|
{
|
||||||
|
return new PubKeyCredParam
|
||||||
|
{
|
||||||
|
Alg = value.Alg.ToString(),
|
||||||
|
Type = value.Type.ToString(),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IEnumerable<PubKeyCredParam> ToRPC(this IEnumerable<Fido2NetLib.PubKeyCredParam> value)
|
||||||
|
{
|
||||||
|
return value.Select(x => x.ToRPC());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static PasskeyCredentialCreateOptions ToRPC(this Fido2NetLib.CredentialCreateOptions value)
|
||||||
|
{
|
||||||
|
var opts = new PasskeyCredentialCreateOptions
|
||||||
|
{
|
||||||
|
Challenge = value.Challenge.ToB64String(),
|
||||||
|
Rp = value.Rp.ToRPC(),
|
||||||
|
User = value.User.ToRPC()
|
||||||
|
};
|
||||||
|
//todo: excluded credentials
|
||||||
|
opts.PubKeyParams.AddRange(value.PubKeyCredParams.ToRPC());
|
||||||
|
return opts;
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user