From 0225b72a651e7177767d3914f8c79ac07943d671 Mon Sep 17 00:00:00 2001 From: broody Date: Thu, 21 Mar 2024 07:41:08 -1000 Subject: [PATCH] Propagate sign error --- .../src/webauthn_signer/account.rs | 6 +- .../src/webauthn_signer/signers/device.rs | 81 +++++++++++++------ .../src/webauthn_signer/signers/mod.rs | 3 +- .../src/webauthn_signer/signers/p256r1.rs | 8 +- 4 files changed, 67 insertions(+), 31 deletions(-) diff --git a/crates/account_sdk/src/webauthn_signer/account.rs b/crates/account_sdk/src/webauthn_signer/account.rs index 251e9c9..d981398 100644 --- a/crates/account_sdk/src/webauthn_signer/account.rs +++ b/crates/account_sdk/src/webauthn_signer/account.rs @@ -19,7 +19,7 @@ use std::sync::Arc; use crate::felt_ser::to_felts; -use super::cairo_args::VerifyWebauthnSignerArgs; +use super::{cairo_args::VerifyWebauthnSignerArgs, signers::device::DeviceError}; use crate::abigen::account::WebauthnSignature; use crate::webauthn_signer::signers::Signer; @@ -84,6 +84,8 @@ where pub enum SignError { #[error("Signer error: {0}")] Signer(EcdsaSignError), + #[error("Device error: {0}")] + Device(DeviceError) } #[cfg_attr(not(target_arch = "wasm32"), async_trait)] @@ -110,7 +112,7 @@ where ) -> Result, Self::SignError> { let tx_hash = execution.transaction_hash(self.chain_id, self.address, query_only, self); let challenge = tx_hash.to_bytes_be().to_vec(); - let assertion = self.signer.sign(&challenge).await; + let assertion = self.signer.sign(&challenge).await?; let args = VerifyWebauthnSignerArgs::from_response(self.origin.clone(), challenge, assertion); diff --git a/crates/account_sdk/src/webauthn_signer/signers/device.rs b/crates/account_sdk/src/webauthn_signer/signers/device.rs index ead278d..1d1e1ca 100644 --- a/crates/account_sdk/src/webauthn_signer/signers/device.rs +++ b/crates/account_sdk/src/webauthn_signer/signers/device.rs @@ -1,12 +1,25 @@ +use std::result::Result; use async_trait::async_trait; use futures::channel::oneshot; use wasm_bindgen_futures::spawn_local; use wasm_webauthn::*; -use crate::webauthn_signer::credential::{AuthenticatorAssertionResponse, AuthenticatorData}; +use crate::webauthn_signer::{account::SignError, credential::{self, AuthenticatorAssertionResponse, AuthenticatorData}}; use super::Signer; +#[derive(Debug, thiserror::Error)] +pub enum DeviceError { + #[error("Invalid args")] + InvalidArgs, + #[error("Create credential error: {0}")] + CreateCredential(String), + #[error("Get assertion error: {0}")] + GetAssertion(String), + #[error("Channel error: {0}")] + Channel(String) +} + #[derive(Debug, Clone)] pub struct DeviceSigner { pub rp_id: String, @@ -21,39 +34,50 @@ impl DeviceSigner { } } - pub async fn register(rp_id: String, user_name: String, challenge: &[u8]) -> Self { + pub async fn register(rp_id: String, user_name: String, challenge: &[u8]) -> Result { let MakeCredentialResponse { credential - } = Self::create_credential(rp_id.clone(), user_name, challenge).await; + } = Self::create_credential(rp_id.clone(), user_name, challenge).await?; - Self { + Ok(Self { rp_id, credential_id: credential.id.0 - } + }) } - async fn create_credential(rp_id: String, user_name: String, challenge: &[u8]) -> MakeCredentialResponse { + async fn create_credential(rp_id: String, user_name: String, challenge: &[u8]) -> Result { let (tx, rx) = oneshot::channel(); let rp_id = rp_id.to_owned(); let challenge = challenge.to_vec(); spawn_local(async move { - let results: MakeCredentialResponse = MakeCredentialArgsBuilder::default() + let result = MakeCredentialArgsBuilder::default() .rp_id(Some(rp_id)) .challenge(challenge) .user_name(Some(user_name)) .uv(UserVerificationRequirement::Required) - .build().expect("invalid args") - .make_credential().await - .expect("make credential"); - - tx.send(results).expect("receiver dropped") + .build() + .expect("invalid args") + .make_credential().await; + + + match result { + Ok(credential) => { + let _ = tx.send(Ok(credential)); + }, + Err(e) => { + let _ = tx.send(Err(DeviceError::CreateCredential(e.to_string()))); + } + } }); - rx.await.expect("receiver dropped") + match rx.await { + Ok(result) => result.map_err(SignError::Device), + Err(_) => Err(SignError::Device(DeviceError::Channel("receiver dropped".to_string()))) + } } - async fn get_assertion(&self, challenge: &[u8]) -> GetAssertionResponse { + async fn get_assertion(&self, challenge: &[u8]) -> Result { let (tx, rx) = oneshot::channel(); let credential_id = self.credential_id.clone(); let rp_id = self.rp_id.to_owned(); @@ -62,7 +86,7 @@ impl DeviceSigner { spawn_local(async move { let credential = Credential::from(CredentialID(credential_id)); - let results: GetAssertionResponse = GetAssertionArgsBuilder::default() + let result = GetAssertionArgsBuilder::default() .rp_id(Some(rp_id)) .credentials(Some(vec![credential])) .challenge(challenge) @@ -70,28 +94,37 @@ impl DeviceSigner { .build() .expect("invalid args") .get_assertion() - .await - .expect("get assertion"); - - tx.send(results).expect("receiver dropped"); + .await; + + match result { + Ok(assertion) => { + let _ = tx.send(Ok(assertion)); + }, + Err(e) => { + let _ = tx.send(Err(DeviceError::GetAssertion(e.to_string()))); + } + } }); - rx.await.expect("receiver dropped") + match rx.await { + Ok(result) => result.map_err(SignError::Device), + Err(_) => Err(SignError::Device(DeviceError::Channel("receiver dropped".to_string()))) + } } } #[cfg_attr(not(target_arch = "wasm32"), async_trait)] #[cfg_attr(target_arch = "wasm32", async_trait(?Send))] impl Signer for DeviceSigner { - async fn sign(&self, challenge: &[u8]) -> AuthenticatorAssertionResponse { + async fn sign(&self, challenge: &[u8]) -> Result { let GetAssertionResponse { signature, client_data_json, flags, counter, - } = self.get_assertion(challenge).await; + } = self.get_assertion(challenge).await?; - AuthenticatorAssertionResponse { + Ok(AuthenticatorAssertionResponse { authenticator_data: AuthenticatorData { rp_id_hash: [0; 32], flags, @@ -100,7 +133,7 @@ impl Signer for DeviceSigner { client_data_json, signature, user_handle: None, - } + }) } fn public_key_bytes(&self) -> ([u8; 32], [u8; 32]) { diff --git a/crates/account_sdk/src/webauthn_signer/signers/mod.rs b/crates/account_sdk/src/webauthn_signer/signers/mod.rs index d65330c..0f3cf73 100644 --- a/crates/account_sdk/src/webauthn_signer/signers/mod.rs +++ b/crates/account_sdk/src/webauthn_signer/signers/mod.rs @@ -1,4 +1,5 @@ use super::credential::AuthenticatorAssertionResponse; +use super::account::SignError; use async_trait::async_trait; pub mod device; @@ -7,6 +8,6 @@ pub mod p256r1; #[cfg_attr(not(target_arch = "wasm32"), async_trait)] #[cfg_attr(target_arch = "wasm32", async_trait(?Send))] pub trait Signer { - async fn sign(&self, challenge: &[u8]) -> AuthenticatorAssertionResponse; + async fn sign(&self, challenge: &[u8]) -> Result; fn public_key_bytes(&self) -> ([u8; 32], [u8; 32]); } diff --git a/crates/account_sdk/src/webauthn_signer/signers/p256r1.rs b/crates/account_sdk/src/webauthn_signer/signers/p256r1.rs index 48ec9bf..ccef318 100644 --- a/crates/account_sdk/src/webauthn_signer/signers/p256r1.rs +++ b/crates/account_sdk/src/webauthn_signer/signers/p256r1.rs @@ -1,4 +1,4 @@ -use crate::webauthn_signer::credential::{AuthenticatorData, CliendData}; +use crate::webauthn_signer::{account::SignError, credential::{AuthenticatorData, CliendData}}; use async_trait::async_trait; use p256::{ ecdsa::{signature::Signer as P256Signer, Signature, SigningKey, VerifyingKey}, @@ -34,7 +34,7 @@ impl Signer for P256r1Signer { P256VerifyingKeyConverter::new(*self.signing_key.verifying_key()).to_bytes() } - async fn sign(&self, challenge: &[u8]) -> AuthenticatorAssertionResponse { + async fn sign(&self, challenge: &[u8]) -> Result { use sha2::{digest::Update, Digest, Sha256}; let authenticator_data = AuthenticatorData { @@ -50,12 +50,12 @@ impl Signer for P256r1Signer { let signature: Signature = self.signing_key.try_sign(&to_sign).unwrap(); let signature = signature.to_bytes().to_vec(); - AuthenticatorAssertionResponse { + Ok(AuthenticatorAssertionResponse { authenticator_data, client_data_json, signature, user_handle: None, - } + }) } }