Skip to content

Commit

Permalink
Propagate sign error
Browse files Browse the repository at this point in the history
  • Loading branch information
broody committed Mar 21, 2024
1 parent 5bb90e4 commit 0225b72
Show file tree
Hide file tree
Showing 4 changed files with 67 additions and 31 deletions.
6 changes: 4 additions & 2 deletions crates/account_sdk/src/webauthn_signer/account.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -84,6 +84,8 @@ where
pub enum SignError {
#[error("Signer error: {0}")]

Check warning on line 85 in crates/account_sdk/src/webauthn_signer/account.rs

View workflow job for this annotation

GitHub Actions / fmt

Diff in /home/runner/work/cairo-webauthn/cairo-webauthn/crates/account_sdk/src/webauthn_signer/account.rs
Signer(EcdsaSignError),
#[error("Device error: {0}")]
Device(DeviceError)
}

#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
Expand All @@ -110,7 +112,7 @@ where
) -> Result<Vec<FieldElement>, 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);
Expand Down
81 changes: 57 additions & 24 deletions crates/account_sdk/src/webauthn_signer/signers/device.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,25 @@
use std::result::Result;

Check warning on line 1 in crates/account_sdk/src/webauthn_signer/signers/device.rs

View workflow job for this annotation

GitHub Actions / fmt

Diff in /home/runner/work/cairo-webauthn/cairo-webauthn/crates/account_sdk/src/webauthn_signer/signers/device.rs
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}};

Check failure on line 7 in crates/account_sdk/src/webauthn_signer/signers/device.rs

View workflow job for this annotation

GitHub Actions / clippy

unused import: `self`

Check warning on line 7 in crates/account_sdk/src/webauthn_signer/signers/device.rs

View workflow job for this annotation

GitHub Actions / fmt

Diff in /home/runner/work/cairo-webauthn/cairo-webauthn/crates/account_sdk/src/webauthn_signer/signers/device.rs

Check failure on line 7 in crates/account_sdk/src/webauthn_signer/signers/device.rs

View workflow job for this annotation

GitHub Actions / ensure-wasm

unused import: `self`

Check failure on line 7 in crates/account_sdk/src/webauthn_signer/signers/device.rs

View workflow job for this annotation

GitHub Actions / test

unused import: `self`

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}")]

Check warning on line 17 in crates/account_sdk/src/webauthn_signer/signers/device.rs

View workflow job for this annotation

GitHub Actions / fmt

Diff in /home/runner/work/cairo-webauthn/cairo-webauthn/crates/account_sdk/src/webauthn_signer/signers/device.rs
GetAssertion(String),
#[error("Channel error: {0}")]
Channel(String)
}

#[derive(Debug, Clone)]
pub struct DeviceSigner {

Check warning on line 24 in crates/account_sdk/src/webauthn_signer/signers/device.rs

View workflow job for this annotation

GitHub Actions / fmt

Diff in /home/runner/work/cairo-webauthn/cairo-webauthn/crates/account_sdk/src/webauthn_signer/signers/device.rs
pub rp_id: String,
Expand All @@ -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<Self, SignError> {

Check warning on line 37 in crates/account_sdk/src/webauthn_signer/signers/device.rs

View workflow job for this annotation

GitHub Actions / fmt

Diff in /home/runner/work/cairo-webauthn/cairo-webauthn/crates/account_sdk/src/webauthn_signer/signers/device.rs
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<MakeCredentialResponse, SignError> {
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<GetAssertionResponse, SignError> {
let (tx, rx) = oneshot::channel();
let credential_id = self.credential_id.clone();
let rp_id = self.rp_id.to_owned();
Expand All @@ -62,36 +86,45 @@ 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)
.uv(UserVerificationRequirement::Required)
.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<AuthenticatorAssertionResponse, SignError> {
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,
Expand All @@ -100,7 +133,7 @@ impl Signer for DeviceSigner {
client_data_json,
signature,
user_handle: None,
}
})
}

fn public_key_bytes(&self) -> ([u8; 32], [u8; 32]) {
Expand Down
3 changes: 2 additions & 1 deletion crates/account_sdk/src/webauthn_signer/signers/mod.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use super::credential::AuthenticatorAssertionResponse;
use super::account::SignError;
use async_trait::async_trait;

pub mod device;
Expand All @@ -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<AuthenticatorAssertionResponse, SignError>;
fn public_key_bytes(&self) -> ([u8; 32], [u8; 32]);
}
8 changes: 4 additions & 4 deletions crates/account_sdk/src/webauthn_signer/signers/p256r1.rs
Original file line number Diff line number Diff line change
@@ -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},
Expand Down Expand Up @@ -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<AuthenticatorAssertionResponse, SignError> {
use sha2::{digest::Update, Digest, Sha256};

let authenticator_data = AuthenticatorData {
Expand All @@ -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,
}
})
}
}

Expand Down

0 comments on commit 0225b72

Please sign in to comment.