diff --git a/crates/bioauth-flow-rpc/src/data.rs b/crates/bioauth-flow-rpc/src/data.rs new file mode 100644 index 000000000..6108720a6 --- /dev/null +++ b/crates/bioauth-flow-rpc/src/data.rs @@ -0,0 +1,48 @@ +//! The RPC request and response data, excluding errors. + +/// The parameters necessary to initialize the FaceTec Device SDK. +pub type FacetecDeviceSdkParams = serde_json::Map; + +/// The bioauth status as used in the RPC. +#[derive(Debug, PartialEq, Eq, serde::Serialize, serde::Deserialize)] +pub enum BioauthStatus { + /// When the status can't be determined, but there was no error. + /// Can happen if the validator key is absent. + Unknown, + /// There is no active authentication for the currently used validator key. + Inactive, + /// There is an active authentication for the currently used validator key. + Active { + /// The timestamp when the authentication will expire. + expires_at: Timestamp, + }, +} + +impl From> for BioauthStatus { + fn from(status: bioauth_flow_api::BioauthStatus) -> Self { + match status { + bioauth_flow_api::BioauthStatus::Inactive => Self::Inactive, + bioauth_flow_api::BioauthStatus::Active { expires_at } => Self::Active { expires_at }, + } + } +} + +/// `enroll_v2` flow result. +#[derive(Debug, PartialEq, Eq, serde::Serialize, serde::Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct EnrollV2Result { + /// Scan result blob. + pub scan_result_blob: Option, +} + +/// `authenticate_v2` related flow result. +#[derive(Debug, PartialEq, Eq, serde::Serialize, serde::Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct AuthenticateV2Result { + /// An opaque auth ticket generated for this authentication attempt. + pub auth_ticket: Box<[u8]>, + /// The robonode signature for this opaque auth ticket. + pub auth_ticket_signature: Box<[u8]>, + /// Scan result blob. + pub scan_result_blob: Option, +} diff --git a/crates/bioauth-flow-rpc/src/error/code.rs b/crates/bioauth-flow-rpc/src/error/code.rs new file mode 100644 index 000000000..83a2483c2 --- /dev/null +++ b/crates/bioauth-flow-rpc/src/error/code.rs @@ -0,0 +1,21 @@ +//! Custom rpc error codes. + +/// Signer has failed. +pub const SIGN: i32 = 100; + +/// Request to robonode has failed. +pub const ROBONODE: i32 = 200; + +/// Call to runtime api has failed. +pub const RUNTIME_API: i32 = 300; + +/// Authenticate transaction has failed. +pub const TRANSACTION: i32 = 400; + +/// Validator key is not available. +pub const MISSING_VALIDATOR_KEY: i32 = + rpc_validator_key_logic::api_error_code::MISSING_VALIDATOR_KEY; + +/// Validator key extraction has failed. +pub const VALIDATOR_KEY_EXTRACTION: i32 = + rpc_validator_key_logic::api_error_code::VALIDATOR_KEY_EXTRACTION; diff --git a/crates/bioauth-flow-rpc/src/error_data.rs b/crates/bioauth-flow-rpc/src/error/data.rs similarity index 100% rename from crates/bioauth-flow-rpc/src/error_data.rs rename to crates/bioauth-flow-rpc/src/error/data.rs diff --git a/crates/bioauth-flow-rpc/src/error/mod.rs b/crates/bioauth-flow-rpc/src/error/mod.rs new file mode 100644 index 000000000..c20ba46ab --- /dev/null +++ b/crates/bioauth-flow-rpc/src/error/mod.rs @@ -0,0 +1,8 @@ +//! All bioauth flow error kinds that we expose in the RPC. + +pub mod code; +pub mod data; +pub mod shared; +mod sign; + +pub use self::sign::Error as Sign; diff --git a/crates/bioauth-flow-rpc/src/errors/shared.rs b/crates/bioauth-flow-rpc/src/error/shared.rs similarity index 73% rename from crates/bioauth-flow-rpc/src/errors/shared.rs rename to crates/bioauth-flow-rpc/src/error/shared.rs index 7f3493744..c8b8aa0ea 100644 --- a/crates/bioauth-flow-rpc/src/errors/shared.rs +++ b/crates/bioauth-flow-rpc/src/error/shared.rs @@ -3,7 +3,7 @@ use rpc_validator_key_logic::Error as ValidatorKeyError; use serde::Serialize; -use super::{api_error_code, sign::Error as SignError}; +use super::{code, sign::Error as SignError}; /// The robonode requests related error. #[derive(Debug)] @@ -28,24 +28,21 @@ impl FlowBaseError { match self { Self::KeyExtraction(err @ ValidatorKeyError::MissingValidatorKey) => { rpc_error_response::data( - api_error_code::MISSING_VALIDATOR_KEY, + code::MISSING_VALIDATOR_KEY, err.to_string(), rpc_validator_key_logic::error_data::ValidatorKeyNotAvailable, ) } Self::KeyExtraction(err @ ValidatorKeyError::ValidatorKeyExtraction) => { - rpc_error_response::simple( - api_error_code::VALIDATOR_KEY_EXTRACTION, - err.to_string(), - ) + rpc_error_response::simple(code::VALIDATOR_KEY_EXTRACTION, err.to_string()) } - Self::Sign(err) => rpc_error_response::simple(api_error_code::SIGN, err.to_string()), + Self::Sign(err) => rpc_error_response::simple(code::SIGN, err.to_string()), Self::RobonodeClient(err @ robonode_client::Error::Call(inner)) => { let maybe_data = (robonode_call_error_data)(inner); - rpc_error_response::raw(api_error_code::ROBONODE, err.to_string(), maybe_data) + rpc_error_response::raw(code::ROBONODE, err.to_string(), maybe_data) } Self::RobonodeClient(err @ robonode_client::Error::Reqwest(_)) => { - rpc_error_response::simple(api_error_code::ROBONODE, err.to_string()) + rpc_error_response::simple(code::ROBONODE, err.to_string()) } } } diff --git a/crates/bioauth-flow-rpc/src/errors/sign.rs b/crates/bioauth-flow-rpc/src/error/sign.rs similarity index 100% rename from crates/bioauth-flow-rpc/src/errors/sign.rs rename to crates/bioauth-flow-rpc/src/error/sign.rs diff --git a/crates/bioauth-flow-rpc/src/errors/mod.rs b/crates/bioauth-flow-rpc/src/errors/mod.rs deleted file mode 100644 index 0d5014562..000000000 --- a/crates/bioauth-flow-rpc/src/errors/mod.rs +++ /dev/null @@ -1,34 +0,0 @@ -//! All bioauth flow error kinds that we expose in the RPC. - -pub mod authenticate; -pub mod authenticate_v2; -pub mod enroll; -pub mod enroll_v2; -pub mod get_facetec_device_sdk_params; -pub mod get_facetec_session_token; -pub mod shared; -pub mod sign; -pub mod status; - -/// Custom rpc error codes. -pub mod api_error_code { - /// Signer has failed. - pub const SIGN: i32 = 100; - - /// Request to robonode has failed. - pub const ROBONODE: i32 = 200; - - /// Call to runtime api has failed. - pub const RUNTIME_API: i32 = 300; - - /// Authenticate transaction has failed. - pub const TRANSACTION: i32 = 400; - - /// Validator key is not available. - pub const MISSING_VALIDATOR_KEY: i32 = - rpc_validator_key_logic::api_error_code::MISSING_VALIDATOR_KEY; - - /// Validator key extraction has failed. - pub const VALIDATOR_KEY_EXTRACTION: i32 = - rpc_validator_key_logic::api_error_code::VALIDATOR_KEY_EXTRACTION; -} diff --git a/crates/bioauth-flow-rpc/src/lib.rs b/crates/bioauth-flow-rpc/src/lib.rs index 6ee994da0..6db02510d 100644 --- a/crates/bioauth-flow-rpc/src/lib.rs +++ b/crates/bioauth-flow-rpc/src/lib.rs @@ -9,96 +9,29 @@ use std::sync::Arc; use bioauth_flow_api::BioauthFlowApi; use bioauth_keys::traits::KeyExtractor as KeyExtractorT; -use errors::{ - authenticate::Error as AuthenticateError, authenticate_v2::Error as AuthenticateV2Error, - enroll::Error as EnrollError, enroll_v2::Error as EnrollV2Error, - get_facetec_device_sdk_params::Error as GetFacetecDeviceSdkParamsError, - get_facetec_session_token::Error as GetFacetecSessionToken, shared::FlowBaseError, - sign::Error as SignError, status::Error as StatusError, -}; use futures::StreamExt; use jsonrpsee::{core::RpcResult, proc_macros::rpc}; use primitives_liveness_data::{LivenessData, OpaqueLivenessData}; use robonode_client::{AuthenticateRequest, AuthenticateResponse, EnrollRequest, EnrollResponse}; use rpc_deny_unsafe::DenyUnsafe; use sc_transaction_pool_api::{TransactionPool as TransactionPoolT, TransactionStatus, TxHash}; -use serde::{Deserialize, Serialize}; -use serde_json::{Map, Value}; use sp_api::{BlockT, Decode, Encode, ProvideRuntimeApi}; use sp_blockchain::HeaderBackend; use tracing::*; -pub mod error_data; -mod errors; +pub mod data; +pub mod error; +pub mod method; +pub mod signer; -/// Signer provides signatures for the data. -#[async_trait::async_trait] -pub trait Signer { - /// Signature error. - /// Error may originate from communicating with HSM, or from a thread pool failure, etc. - type Error; - - /// Sign the provided data and return the signature, or an error if the signing fails. - async fn sign<'a, D>(&self, data: D) -> std::result::Result - where - D: AsRef<[u8]> + Send + 'a; -} - -/// A factory that spits out [`Signer`]s. -pub trait SignerFactory { - /// The type of [`Signer`] this factory will create. - type Signer: Signer; - - /// Create a [`Signer`] using the provided public key. - fn new_signer(&self, key: K) -> Self::Signer; -} - -impl SignerFactory for P -where - P: std::ops::Deref, - F: Fn(K) -> S, - S: Signer, -{ - type Signer = S; - - fn new_signer(&self, key: K) -> Self::Signer { - self(key) - } -} - -/// The parameters necessary to initialize the FaceTec Device SDK. -type FacetecDeviceSdkParams = Map; - -/// The bioauth status as used in the RPC. -#[derive(Debug, PartialEq, Eq, Serialize, Deserialize)] -pub enum BioauthStatus { - /// When the status can't be determined, but there was no error. - /// Can happen if the validator key is absent. - Unknown, - /// There is no active authentication for the currently used validator key. - Inactive, - /// There is an active authentication for the currently used validator key. - Active { - /// The timestamp when the authentication will expire. - expires_at: Timestamp, - }, -} - -impl From> for BioauthStatus { - fn from(status: bioauth_flow_api::BioauthStatus) -> Self { - match status { - bioauth_flow_api::BioauthStatus::Inactive => Self::Inactive, - bioauth_flow_api::BioauthStatus::Active { expires_at } => Self::Active { expires_at }, - } - } -} +pub use self::signer::Signer; /// The API exposed via JSON-RPC. #[rpc(server)] pub trait Bioauth { /// Get the configuration required for the Device SDK. #[method(name = "bioauth_getFacetecDeviceSdkParams")] - async fn get_facetec_device_sdk_params(&self) -> RpcResult; + async fn get_facetec_device_sdk_params(&self) -> RpcResult; /// Get a FaceTec Session Token. #[method(name = "bioauth_getFacetecSessionToken")] @@ -106,7 +39,7 @@ pub trait Bioauth { /// Get the current bioauth status. #[method(name = "bioauth_status")] - async fn status(&self) -> RpcResult>; + async fn status(&self) -> RpcResult>; /// Enroll with provided liveness data. #[method(name = "bioauth_enroll")] @@ -114,7 +47,7 @@ pub trait Bioauth { /// Enroll with provided liveness data V2. #[method(name = "bioauth_enrollV2")] - async fn enroll_v2(&self, liveness_data: LivenessData) -> RpcResult; + async fn enroll_v2(&self, liveness_data: LivenessData) -> RpcResult; /// Authenticate with provided liveness data. #[method(name = "bioauth_authenticate")] @@ -122,28 +55,10 @@ pub trait Bioauth { /// Request auth ticket based on provided liveness data. #[method(name = "bioauth_authenticateV2")] - async fn authenticate_v2(&self, liveness_data: LivenessData) - -> RpcResult; -} - -/// `enroll_v2` flow result. -#[derive(Debug, PartialEq, Eq, Serialize, Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct EnrollV2Result { - /// Scan result blob. - pub scan_result_blob: Option, -} - -/// `authenticate_v2` related flow result. -#[derive(Debug, PartialEq, Eq, Serialize, Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct AuthenticateV2Result { - /// An opaque auth ticket generated for this authentication attempt. - pub auth_ticket: Box<[u8]>, - /// The robonode signature for this opaque auth ticket. - pub auth_ticket_signature: Box<[u8]>, - /// Scan result blob. - pub scan_result_blob: Option, + async fn authenticate_v2( + &self, + liveness_data: LivenessData, + ) -> RpcResult; } /// The RPC implementation. @@ -235,20 +150,20 @@ where ValidatorKeyExtractor: KeyExtractorT, ValidatorKeyExtractor::PublicKeyType: Encode + AsRef<[u8]> + Clone, ValidatorKeyExtractor::Error: std::fmt::Debug, - ValidatorSignerFactory: SignerFactory, ValidatorKeyExtractor::PublicKeyType>, - <, ValidatorKeyExtractor::PublicKeyType>>::Signer as Signer>>::Error: + ValidatorSignerFactory: signer::Factory, ValidatorKeyExtractor::PublicKeyType>, + <, ValidatorKeyExtractor::PublicKeyType>>::Signer as Signer>>::Error: std::error::Error + 'static, Block: BlockT, TransactionPool: TransactionPoolT, { /// Return the opaque liveness data and corresponding signature. - async fn sign(&self, validator_key: ::PublicKeyType, liveness_data: &LivenessData) -> Result<(OpaqueLivenessData, Vec), SignError> { + async fn sign(&self, validator_key: ::PublicKeyType, liveness_data: &LivenessData) -> Result<(OpaqueLivenessData, Vec), error::Sign> { let opaque_liveness_data = OpaqueLivenessData::from(liveness_data); let signer = self.validator_signer_factory.new_signer(validator_key); let signature = signer.sign(&opaque_liveness_data).await.map_err(|error| { tracing::error!(message = "Signing failed", ?error); - SignError::SigningFailed + error::Sign::SigningFailed })?; Ok((opaque_liveness_data, signature)) @@ -257,18 +172,18 @@ where /// Do enroll with provided liveness data. async fn do_enroll(&self, liveness_data: LivenessData) -> Result< EnrollResponse, - FlowBaseError + error::shared::FlowBaseError > { info!("Bioauth flow - enrolling in progress"); let public_key = rpc_validator_key_logic::validator_public_key(&self.validator_key_extractor) - .map_err(FlowBaseError::KeyExtraction)?; + .map_err(error::shared::FlowBaseError::KeyExtraction)?; let (opaque_liveness_data, signature) = self .sign(public_key.clone(), &liveness_data) .await - .map_err(FlowBaseError::Sign)?; + .map_err(error::shared::FlowBaseError::Sign)?; let response = self .robonode_client @@ -279,7 +194,7 @@ where public_key: public_key.as_ref(), }) .await - .map_err(FlowBaseError::RobonodeClient)?; + .map_err(error::shared::FlowBaseError::RobonodeClient)?; info!("Bioauth flow - enrolling complete"); @@ -289,18 +204,18 @@ where /// Do authenticate with provided liveness data. async fn do_authenticate(&self, liveness_data: LivenessData) -> Result< AuthenticateResponse, - FlowBaseError + error::shared::FlowBaseError > { info!("Bioauth flow - authentication in progress"); let public_key = rpc_validator_key_logic::validator_public_key(&self.validator_key_extractor) - .map_err(FlowBaseError::KeyExtraction)?; + .map_err(error::shared::FlowBaseError::KeyExtraction)?; let (opaque_liveness_data, signature) = self .sign(public_key, &liveness_data) .await - .map_err(FlowBaseError::Sign)?; + .map_err(error::shared::FlowBaseError::Sign)?; let response = self .robonode_client @@ -310,7 +225,7 @@ where liveness_data_signature: signature.as_ref(), }) .await - .map_err(FlowBaseError::RobonodeClient)?; + .map_err(error::shared::FlowBaseError::RobonodeClient)?; info!("Bioauth flow - authentication complete"); @@ -352,8 +267,8 @@ where ValidatorKeyExtractor: KeyExtractorT, ValidatorKeyExtractor::PublicKeyType: Encode + AsRef<[u8]> + Clone, ValidatorKeyExtractor::Error: std::fmt::Debug, - ValidatorSignerFactory: SignerFactory, ValidatorKeyExtractor::PublicKeyType>, - <, ValidatorKeyExtractor::PublicKeyType>>::Signer as Signer>>::Error: + ValidatorSignerFactory: signer::Factory, ValidatorKeyExtractor::PublicKeyType>, + <, ValidatorKeyExtractor::PublicKeyType>>::Signer as Signer>>::Error: std::error::Error + 'static, Client: HeaderBackend, Client: ProvideRuntimeApi, @@ -364,13 +279,13 @@ where Timestamp: Encode + Decode, TransactionPool: TransactionPoolT, { - async fn get_facetec_device_sdk_params(&self) -> RpcResult { + async fn get_facetec_device_sdk_params(&self) -> RpcResult { let res = self .robonode_client .as_ref() .get_facetec_device_sdk_params() .await - .map_err(GetFacetecDeviceSdkParamsError::Robonode)?; + .map_err(method::get_facetec_device_sdk_params::Error::Robonode)?; Ok(res) } @@ -380,15 +295,15 @@ where .as_ref() .get_facetec_session_token() .await - .map_err(GetFacetecSessionToken::Robonode)?; + .map_err(method::get_facetec_session_token::Error::Robonode)?; Ok(res.session_token) } - async fn status(&self) -> RpcResult> { + async fn status(&self) -> RpcResult> { let own_key = match rpc_validator_key_logic::validator_public_key(&self.validator_key_extractor) { Ok(v) => v, - Err(rpc_validator_key_logic::Error::MissingValidatorKey) => return Ok(BioauthStatus::Unknown), - Err(rpc_validator_key_logic::Error::ValidatorKeyExtraction) => return Err(StatusError::ValidatorKeyExtraction.into()), + Err(rpc_validator_key_logic::Error::MissingValidatorKey) => return Ok(data::BioauthStatus::Unknown), + Err(rpc_validator_key_logic::Error::ValidatorKeyExtraction) => return Err(method::status::Error::ValidatorKeyExtraction.into()), }; // Extract an id of the last imported block. @@ -398,7 +313,7 @@ where .client .runtime_api() .bioauth_status(at, &own_key) - .map_err(StatusError::RuntimeApi)?; + .map_err(method::status::Error::RuntimeApi)?; Ok(status.into()) } @@ -406,31 +321,31 @@ where async fn enroll(&self, liveness_data: LivenessData) -> RpcResult<()> { self.deny_unsafe.check_if_safe()?; - self.do_enroll(liveness_data).await.map_err(EnrollError)?; + self.do_enroll(liveness_data).await.map_err(method::enroll::Error)?; Ok(()) } - async fn enroll_v2(&self, liveness_data: LivenessData) -> RpcResult { + async fn enroll_v2(&self, liveness_data: LivenessData) -> RpcResult { self.deny_unsafe.check_if_safe()?; let EnrollResponse { scan_result_blob } = self .do_enroll(liveness_data) .await - .map_err(EnrollV2Error)?; + .map_err(method::enroll_v2::Error)?; - Ok(EnrollV2Result { scan_result_blob }) + Ok(data::EnrollV2Result { scan_result_blob }) } async fn authenticate(&self, liveness_data: LivenessData) -> RpcResult> { self.deny_unsafe.check_if_safe()?; - let errtype = |val: errors::authenticate::Error| { val }; + let errtype = |val: method::authenticate::Error| { val }; let response = self .do_authenticate(liveness_data) .await - .map_err(AuthenticateError::RobonodeRequest) + .map_err(method::authenticate::Error::RobonodeRequest) .map_err(errtype)?; info!(message = "We've obtained an auth ticket", auth_ticket = ?response.auth_ticket); @@ -445,7 +360,7 @@ where response.auth_ticket.into(), response.auth_ticket_signature.into(), ) - .map_err(AuthenticateError::RuntimeApi).map_err(errtype)?; + .map_err(method::authenticate::Error::RuntimeApi).map_err(errtype)?; info!("Bioauth flow - submitting authenticate transaction"); @@ -458,7 +373,7 @@ where ext, ) .await - .map_err(AuthenticateError::BioauthTx).map_err(errtype)?.fuse(); + .map_err(method::authenticate::Error::BioauthTx).map_err(errtype)?.fuse(); tokio::spawn(async move { loop { @@ -532,17 +447,17 @@ where async fn authenticate_v2( &self, liveness_data: LivenessData, - ) -> RpcResult { + ) -> RpcResult { self.deny_unsafe.check_if_safe()?; let AuthenticateResponse { auth_ticket, auth_ticket_signature, scan_result_blob, - } = self.do_authenticate(liveness_data).await.map_err(AuthenticateV2Error)?; + } = self.do_authenticate(liveness_data).await.map_err(method::authenticate_v2::Error)?; info!(message = "We've obtained an auth ticket", auth_ticket = ?auth_ticket); - Ok(AuthenticateV2Result { auth_ticket, auth_ticket_signature, scan_result_blob }) + Ok(data::AuthenticateV2Result { auth_ticket, auth_ticket_signature, scan_result_blob }) } } diff --git a/crates/bioauth-flow-rpc/src/errors/authenticate.rs b/crates/bioauth-flow-rpc/src/method/authenticate.rs similarity index 88% rename from crates/bioauth-flow-rpc/src/errors/authenticate.rs rename to crates/bioauth-flow-rpc/src/method/authenticate.rs index 4258ff4d4..30d39c5ea 100644 --- a/crates/bioauth-flow-rpc/src/errors/authenticate.rs +++ b/crates/bioauth-flow-rpc/src/method/authenticate.rs @@ -3,14 +3,13 @@ use sp_api::ApiError; use sp_runtime::transaction_validity::InvalidTransaction; -use super::{api_error_code, shared}; -use crate::error_data::{self, BioauthTxErrorDetails}; +use crate::error; /// The `authenticate` method error kinds. #[derive(Debug)] pub enum Error { /// An error that can occur during doing a request to robonode. - RobonodeRequest(shared::FlowBaseError), + RobonodeRequest(error::shared::FlowBaseError), /// An error that can occur during doing a call into runtime api. RuntimeApi(ApiError), /// An error that can occur with transaction pool logic. @@ -23,11 +22,12 @@ where { fn from(err: Error) -> Self { match err { - Error::RobonodeRequest(err) => err.to_jsonrpsee_error::<_, error_data::ShouldRetry>( - |call_error| match call_error { + Error::RobonodeRequest(err) => { + err.to_jsonrpsee_error::<_, error::data::ShouldRetry>(|call_error| match call_error + { robonode_client::AuthenticateError::FaceScanRejectedNoBlob | robonode_client::AuthenticateError::FaceScanRejected(_) => { - Some(error_data::ShouldRetry) + Some(error::data::ShouldRetry) } robonode_client::AuthenticateError::InvalidLivenessData @@ -39,21 +39,21 @@ where | robonode_client::AuthenticateError::LogicInternal(_) | robonode_client::AuthenticateError::UnknownCode(_) | robonode_client::AuthenticateError::Unknown(_) => None, - }, - ), + }) + } Error::RuntimeApi(err) => { - rpc_error_response::simple(api_error_code::RUNTIME_API, err.to_string()) + rpc_error_response::simple(error::code::RUNTIME_API, err.to_string()) } Error::BioauthTx(err) => { let (message, data) = map_txpool_error(err); - rpc_error_response::raw(api_error_code::TRANSACTION, message, data) + rpc_error_response::raw(error::code::TRANSACTION, message, data) } } } } /// Convert a transaction pool error into a human-readable. -fn map_txpool_error(err: T) -> (String, Option) +fn map_txpool_error(err: T) -> (String, Option) where T: sc_transaction_pool_api::error::IntoPoolError, { @@ -70,7 +70,7 @@ where let (kind, message) = match err { // Provide some custom-tweaked error messages for a few select cases: Error::InvalidTransaction(InvalidTransaction::BadProof) => ( - error_data::BioauthTxErrorKind::AuthTicketSignatureInvalid, + error::data::BioauthTxErrorKind::AuthTicketSignatureInvalid, "Invalid auth ticket signature", ), Error::InvalidTransaction(InvalidTransaction::Custom(custom_code)) @@ -79,16 +79,16 @@ where as u8) => { ( - error_data::BioauthTxErrorKind::UnableToParseAuthTicket, + error::data::BioauthTxErrorKind::UnableToParseAuthTicket, "Unable to parse a validly signed auth ticket", ) } Error::InvalidTransaction(InvalidTransaction::Stale) => ( - error_data::BioauthTxErrorKind::NonceAlreadyUsed, + error::data::BioauthTxErrorKind::NonceAlreadyUsed, "The auth ticket you provided has already been used", ), Error::InvalidTransaction(InvalidTransaction::Future) => ( - error_data::BioauthTxErrorKind::AlreadyAuthenticated, + error::data::BioauthTxErrorKind::AlreadyAuthenticated, "Active authentication exists currently, and you can't authenticate again yet", ), // For the rest cases, fallback to simple error rendering. @@ -97,7 +97,7 @@ where } }; - let data = BioauthTxErrorDetails { + let data = error::data::BioauthTxErrorDetails { inner_error: err.to_string(), kind, message, @@ -115,13 +115,14 @@ mod tests { use rpc_validator_key_logic::Error as ValidatorKeyError; use super::*; - use crate::errors::sign::Error as SignError; #[test] fn error_key_extraction_validator_key_extraction() { let error: jsonrpsee::core::Error = Error::::RobonodeRequest( - shared::FlowBaseError::KeyExtraction(ValidatorKeyError::ValidatorKeyExtraction), + error::shared::FlowBaseError::KeyExtraction( + ValidatorKeyError::ValidatorKeyExtraction, + ), ) .into(); let error: ErrorObject = error.into(); @@ -137,7 +138,7 @@ mod tests { fn error_key_extraction_missing_validator_key() { let error: jsonrpsee::core::Error = Error::::RobonodeRequest( - shared::FlowBaseError::KeyExtraction(ValidatorKeyError::MissingValidatorKey), + error::shared::FlowBaseError::KeyExtraction(ValidatorKeyError::MissingValidatorKey), ) .into(); let error: ErrorObject = error.into(); @@ -153,7 +154,7 @@ mod tests { fn error_sign() { let error: jsonrpsee::core::Error = Error::::RobonodeRequest( - shared::FlowBaseError::Sign(SignError::SigningFailed), + error::shared::FlowBaseError::Sign(error::Sign::SigningFailed), ) .into(); let error: ErrorObject = error.into(); @@ -169,7 +170,7 @@ mod tests { fn error_robonode_face_scan_rejected() { let error: jsonrpsee::core::Error = Error::::RobonodeRequest( - shared::FlowBaseError::RobonodeClient(robonode_client::Error::Call( + error::shared::FlowBaseError::RobonodeClient(robonode_client::Error::Call( robonode_client::AuthenticateError::FaceScanRejectedNoBlob, )), ) @@ -188,7 +189,7 @@ mod tests { fn error_robonode_logic_internal() { let error: jsonrpsee::core::Error = Error::::RobonodeRequest( - shared::FlowBaseError::RobonodeClient(robonode_client::Error::Call( + error::shared::FlowBaseError::RobonodeClient(robonode_client::Error::Call( robonode_client::AuthenticateError::LogicInternalNoBlob, )), ) @@ -207,7 +208,7 @@ mod tests { fn error_robonode_other() { let error: jsonrpsee::core::Error = Error::::RobonodeRequest( - shared::FlowBaseError::RobonodeClient(robonode_client::Error::Call( + error::shared::FlowBaseError::RobonodeClient(robonode_client::Error::Call( robonode_client::AuthenticateError::Unknown("test".to_owned()), )), ) diff --git a/crates/bioauth-flow-rpc/src/errors/authenticate_v2.rs b/crates/bioauth-flow-rpc/src/method/authenticate_v2.rs similarity index 80% rename from crates/bioauth-flow-rpc/src/errors/authenticate_v2.rs rename to crates/bioauth-flow-rpc/src/method/authenticate_v2.rs index 244cc75f3..c8ad9ee33 100644 --- a/crates/bioauth-flow-rpc/src/errors/authenticate_v2.rs +++ b/crates/bioauth-flow-rpc/src/method/authenticate_v2.rs @@ -1,25 +1,24 @@ //! The `authenticate_v2` method error. -use super::shared; -use crate::error_data; +use crate::error; /// The `authenticate_v2` method error kinds. #[derive(Debug)] -pub struct Error(pub shared::FlowBaseError); +pub struct Error(pub error::shared::FlowBaseError); impl From for jsonrpsee::core::Error { fn from(err: Error) -> Self { err.0 - .to_jsonrpsee_error::<_, error_data::BlobOrRetry>(|call_error| match call_error { + .to_jsonrpsee_error::<_, error::data::BlobOrRetry>(|call_error| match call_error { robonode_client::AuthenticateError::PersonNotFound(ref scan_result_blob) | robonode_client::AuthenticateError::FaceScanRejected(ref scan_result_blob) | robonode_client::AuthenticateError::SignatureInvalid(ref scan_result_blob) | robonode_client::AuthenticateError::LogicInternal(ref scan_result_blob) => { - Some(error_data::ScanResultBlob(scan_result_blob.clone()).into()) + Some(error::data::ScanResultBlob(scan_result_blob.clone()).into()) } robonode_client::AuthenticateError::FaceScanRejectedNoBlob => { - Some(error_data::ShouldRetry.into()) + Some(error::data::ShouldRetry.into()) } robonode_client::AuthenticateError::InvalidLivenessData @@ -39,11 +38,10 @@ mod tests { use rpc_validator_key_logic::Error as ValidatorKeyError; use super::*; - use crate::errors::sign::Error as SignError; #[test] fn error_key_extraction_validator_key_extraction() { - let error: jsonrpsee::core::Error = Error(shared::FlowBaseError::KeyExtraction( + let error: jsonrpsee::core::Error = Error(error::shared::FlowBaseError::KeyExtraction( ValidatorKeyError::ValidatorKeyExtraction, )) .into(); @@ -58,7 +56,7 @@ mod tests { #[test] fn error_key_extraction_missing_validator_key() { - let error: jsonrpsee::core::Error = Error(shared::FlowBaseError::KeyExtraction( + let error: jsonrpsee::core::Error = Error(error::shared::FlowBaseError::KeyExtraction( ValidatorKeyError::MissingValidatorKey, )) .into(); @@ -73,8 +71,10 @@ mod tests { #[test] fn error_sign() { - let error: jsonrpsee::core::Error = - Error(shared::FlowBaseError::Sign(SignError::SigningFailed)).into(); + let error: jsonrpsee::core::Error = Error(error::shared::FlowBaseError::Sign( + error::Sign::SigningFailed, + )) + .into(); let error: ErrorObject = error.into(); let expected_error_message = "{\"code\":100,\"message\":\"signing failed\"}"; @@ -86,7 +86,7 @@ mod tests { #[test] fn error_robonode_face_scan_rejected() { - let error: jsonrpsee::core::Error = Error(shared::FlowBaseError::RobonodeClient( + let error: jsonrpsee::core::Error = Error(error::shared::FlowBaseError::RobonodeClient( robonode_client::Error::Call(robonode_client::AuthenticateError::FaceScanRejected( "scan result blob".to_owned(), )), @@ -104,7 +104,7 @@ mod tests { #[test] fn error_robonode_logic_internal() { - let error: jsonrpsee::core::Error = Error(shared::FlowBaseError::RobonodeClient( + let error: jsonrpsee::core::Error = Error(error::shared::FlowBaseError::RobonodeClient( robonode_client::Error::Call(robonode_client::AuthenticateError::LogicInternal( "scan result blob".to_owned(), )), @@ -122,7 +122,7 @@ mod tests { #[test] fn error_robonode_other() { - let error: jsonrpsee::core::Error = Error(shared::FlowBaseError::RobonodeClient( + let error: jsonrpsee::core::Error = Error(error::shared::FlowBaseError::RobonodeClient( robonode_client::Error::Call(robonode_client::AuthenticateError::Unknown( "test".to_owned(), )), diff --git a/crates/bioauth-flow-rpc/src/errors/enroll.rs b/crates/bioauth-flow-rpc/src/method/enroll.rs similarity index 80% rename from crates/bioauth-flow-rpc/src/errors/enroll.rs rename to crates/bioauth-flow-rpc/src/method/enroll.rs index 857a92dd7..613e667ef 100644 --- a/crates/bioauth-flow-rpc/src/errors/enroll.rs +++ b/crates/bioauth-flow-rpc/src/method/enroll.rs @@ -1,19 +1,18 @@ //! The `enroll` method error. -use super::shared; -use crate::error_data; +use crate::error; /// The `enroll` method error kinds. #[derive(Debug)] -pub struct Error(pub shared::FlowBaseError); +pub struct Error(pub error::shared::FlowBaseError); impl From for jsonrpsee::core::Error { fn from(err: Error) -> Self { err.0 - .to_jsonrpsee_error::<_, error_data::ShouldRetry>(|call_error| match call_error { + .to_jsonrpsee_error::<_, error::data::ShouldRetry>(|call_error| match call_error { robonode_client::EnrollError::FaceScanRejectedNoBlob | robonode_client::EnrollError::FaceScanRejected(_) => { - Some(error_data::ShouldRetry) + Some(error::data::ShouldRetry) } robonode_client::EnrollError::InvalidPublicKey @@ -36,11 +35,10 @@ mod tests { use rpc_validator_key_logic::Error as ValidatorKeyError; use super::*; - use crate::errors::sign::Error as SignError; #[test] fn error_key_extraction_validator_key_extraction() { - let error: jsonrpsee::core::Error = Error(shared::FlowBaseError::KeyExtraction( + let error: jsonrpsee::core::Error = Error(error::shared::FlowBaseError::KeyExtraction( ValidatorKeyError::ValidatorKeyExtraction, )) .into(); @@ -55,7 +53,7 @@ mod tests { #[test] fn error_key_extraction_missing_validator_key() { - let error: jsonrpsee::core::Error = Error(shared::FlowBaseError::KeyExtraction( + let error: jsonrpsee::core::Error = Error(error::shared::FlowBaseError::KeyExtraction( ValidatorKeyError::MissingValidatorKey, )) .into(); @@ -70,7 +68,7 @@ mod tests { #[test] fn error_robonode_face_scan_rejected() { - let error: jsonrpsee::core::Error = Error(shared::FlowBaseError::RobonodeClient( + let error: jsonrpsee::core::Error = Error(error::shared::FlowBaseError::RobonodeClient( robonode_client::Error::Call(robonode_client::EnrollError::FaceScanRejectedNoBlob), )) .into(); @@ -86,7 +84,7 @@ mod tests { #[test] fn error_robonode_logic_internal() { - let error: jsonrpsee::core::Error = Error(shared::FlowBaseError::RobonodeClient( + let error: jsonrpsee::core::Error = Error(error::shared::FlowBaseError::RobonodeClient( robonode_client::Error::Call(robonode_client::EnrollError::LogicInternalNoBlob), )) .into(); @@ -102,7 +100,7 @@ mod tests { #[test] fn error_robonode_other() { - let error: jsonrpsee::core::Error = Error(shared::FlowBaseError::RobonodeClient( + let error: jsonrpsee::core::Error = Error(error::shared::FlowBaseError::RobonodeClient( robonode_client::Error::Call(robonode_client::EnrollError::Unknown("test".to_owned())), )) .into(); @@ -118,8 +116,10 @@ mod tests { #[test] fn error_sign() { - let error: jsonrpsee::core::Error = - Error(shared::FlowBaseError::Sign(SignError::SigningFailed)).into(); + let error: jsonrpsee::core::Error = Error(error::shared::FlowBaseError::Sign( + error::Sign::SigningFailed, + )) + .into(); let error: ErrorObject = error.into(); let expected_error_message = "{\"code\":100,\"message\":\"signing failed\"}"; diff --git a/crates/bioauth-flow-rpc/src/errors/enroll_v2.rs b/crates/bioauth-flow-rpc/src/method/enroll_v2.rs similarity index 80% rename from crates/bioauth-flow-rpc/src/errors/enroll_v2.rs rename to crates/bioauth-flow-rpc/src/method/enroll_v2.rs index 576571c4b..e59babc2b 100644 --- a/crates/bioauth-flow-rpc/src/errors/enroll_v2.rs +++ b/crates/bioauth-flow-rpc/src/method/enroll_v2.rs @@ -1,24 +1,23 @@ //! The `enroll_v2` method error. -use super::shared; -use crate::error_data; +use crate::error; /// The `enroll_v2` method error kinds. #[derive(Debug)] -pub struct Error(pub shared::FlowBaseError); +pub struct Error(pub error::shared::FlowBaseError); impl From for jsonrpsee::core::Error { fn from(err: Error) -> Self { err.0 - .to_jsonrpsee_error::<_, error_data::BlobOrRetry>(|call_error| match call_error { + .to_jsonrpsee_error::<_, error::data::BlobOrRetry>(|call_error| match call_error { robonode_client::EnrollError::FaceScanRejected(ref scan_result_blob) | robonode_client::EnrollError::PersonAlreadyEnrolled(ref scan_result_blob) | robonode_client::EnrollError::LogicInternal(ref scan_result_blob) => { - Some(error_data::ScanResultBlob(scan_result_blob.clone()).into()) + Some(error::data::ScanResultBlob(scan_result_blob.clone()).into()) } robonode_client::EnrollError::FaceScanRejectedNoBlob => { - Some(error_data::ShouldRetry.into()) + Some(error::data::ShouldRetry.into()) } robonode_client::EnrollError::InvalidPublicKey @@ -39,11 +38,10 @@ mod tests { use rpc_validator_key_logic::Error as ValidatorKeyError; use super::*; - use crate::errors::sign::Error as SignError; #[test] fn error_key_extraction_validator_key_extraction() { - let error: jsonrpsee::core::Error = Error(shared::FlowBaseError::KeyExtraction( + let error: jsonrpsee::core::Error = Error(error::shared::FlowBaseError::KeyExtraction( ValidatorKeyError::ValidatorKeyExtraction, )) .into(); @@ -58,7 +56,7 @@ mod tests { #[test] fn error_key_extraction_missing_validator_key() { - let error: jsonrpsee::core::Error = Error(shared::FlowBaseError::KeyExtraction( + let error: jsonrpsee::core::Error = Error(error::shared::FlowBaseError::KeyExtraction( ValidatorKeyError::MissingValidatorKey, )) .into(); @@ -73,7 +71,7 @@ mod tests { #[test] fn error_robonode_face_scan_rejected() { - let error: jsonrpsee::core::Error = Error(shared::FlowBaseError::RobonodeClient( + let error: jsonrpsee::core::Error = Error(error::shared::FlowBaseError::RobonodeClient( robonode_client::Error::Call(robonode_client::EnrollError::FaceScanRejected( "scan result blob".to_owned(), )), @@ -91,7 +89,7 @@ mod tests { #[test] fn error_robonode_logic_internal() { - let error: jsonrpsee::core::Error = Error(shared::FlowBaseError::RobonodeClient( + let error: jsonrpsee::core::Error = Error(error::shared::FlowBaseError::RobonodeClient( robonode_client::Error::Call(robonode_client::EnrollError::LogicInternal( "scan result blob".to_owned(), )), @@ -109,7 +107,7 @@ mod tests { #[test] fn error_robonode_other() { - let error: jsonrpsee::core::Error = Error(shared::FlowBaseError::RobonodeClient( + let error: jsonrpsee::core::Error = Error(error::shared::FlowBaseError::RobonodeClient( robonode_client::Error::Call(robonode_client::EnrollError::Unknown("test".to_owned())), )) .into(); @@ -125,8 +123,10 @@ mod tests { #[test] fn error_sign() { - let error: jsonrpsee::core::Error = - Error(shared::FlowBaseError::Sign(SignError::SigningFailed)).into(); + let error: jsonrpsee::core::Error = Error(error::shared::FlowBaseError::Sign( + error::Sign::SigningFailed, + )) + .into(); let error: ErrorObject = error.into(); let expected_error_message = "{\"code\":100,\"message\":\"signing failed\"}"; diff --git a/crates/bioauth-flow-rpc/src/errors/get_facetec_device_sdk_params.rs b/crates/bioauth-flow-rpc/src/method/get_facetec_device_sdk_params.rs similarity index 90% rename from crates/bioauth-flow-rpc/src/errors/get_facetec_device_sdk_params.rs rename to crates/bioauth-flow-rpc/src/method/get_facetec_device_sdk_params.rs index a3e43a324..646c2635e 100644 --- a/crates/bioauth-flow-rpc/src/errors/get_facetec_device_sdk_params.rs +++ b/crates/bioauth-flow-rpc/src/method/get_facetec_device_sdk_params.rs @@ -1,6 +1,6 @@ //! The `get_facetec_device_sdk_params` method error. -use super::api_error_code; +use crate::error; /// The `get_facetec_device_sdk_params` method error kinds. #[derive(Debug)] @@ -13,7 +13,7 @@ impl From for jsonrpsee::core::Error { fn from(err: Error) -> Self { match err { Error::Robonode(err) => { - rpc_error_response::simple(api_error_code::ROBONODE, err.to_string()) + rpc_error_response::simple(error::code::ROBONODE, err.to_string()) } } } diff --git a/crates/bioauth-flow-rpc/src/errors/get_facetec_session_token.rs b/crates/bioauth-flow-rpc/src/method/get_facetec_session_token.rs similarity index 90% rename from crates/bioauth-flow-rpc/src/errors/get_facetec_session_token.rs rename to crates/bioauth-flow-rpc/src/method/get_facetec_session_token.rs index 83cf32c9f..fa320ed9b 100644 --- a/crates/bioauth-flow-rpc/src/errors/get_facetec_session_token.rs +++ b/crates/bioauth-flow-rpc/src/method/get_facetec_session_token.rs @@ -1,6 +1,6 @@ //! The `get_facetec_session_token` method error. -use super::api_error_code; +use crate::error; /// The `get_facetec_session_token` method error kinds. #[derive(Debug)] @@ -13,7 +13,7 @@ impl From for jsonrpsee::core::Error { fn from(err: Error) -> Self { match err { Error::Robonode(err) => { - rpc_error_response::simple(api_error_code::ROBONODE, err.to_string()) + rpc_error_response::simple(error::code::ROBONODE, err.to_string()) } } } diff --git a/crates/bioauth-flow-rpc/src/method/mod.rs b/crates/bioauth-flow-rpc/src/method/mod.rs new file mode 100644 index 000000000..38324d669 --- /dev/null +++ b/crates/bioauth-flow-rpc/src/method/mod.rs @@ -0,0 +1,9 @@ +//! Module implementation details. + +pub mod authenticate; +pub mod authenticate_v2; +pub mod enroll; +pub mod enroll_v2; +pub mod get_facetec_device_sdk_params; +pub mod get_facetec_session_token; +pub mod status; diff --git a/crates/bioauth-flow-rpc/src/errors/status.rs b/crates/bioauth-flow-rpc/src/method/status.rs similarity index 93% rename from crates/bioauth-flow-rpc/src/errors/status.rs rename to crates/bioauth-flow-rpc/src/method/status.rs index 1e6c46bc4..7a3fa4871 100644 --- a/crates/bioauth-flow-rpc/src/errors/status.rs +++ b/crates/bioauth-flow-rpc/src/method/status.rs @@ -3,7 +3,7 @@ use rpc_validator_key_logic::Error as ValidatorKeyError; use sp_api::ApiError; -use super::api_error_code; +use crate::error; /// The `status` method error kinds. #[derive(Debug)] @@ -19,11 +19,11 @@ impl From for jsonrpsee::core::Error { fn from(err: Error) -> Self { match err { Error::ValidatorKeyExtraction => rpc_error_response::simple( - api_error_code::VALIDATOR_KEY_EXTRACTION, + error::code::VALIDATOR_KEY_EXTRACTION, ValidatorKeyError::ValidatorKeyExtraction.to_string(), ), Error::RuntimeApi(err) => rpc_error_response::simple( - api_error_code::RUNTIME_API, + error::code::RUNTIME_API, format!("unable to get status from the runtime: {err}"), ), } diff --git a/crates/bioauth-flow-rpc/src/signer.rs b/crates/bioauth-flow-rpc/src/signer.rs new file mode 100644 index 000000000..073fd5029 --- /dev/null +++ b/crates/bioauth-flow-rpc/src/signer.rs @@ -0,0 +1,36 @@ +//! Signer. + +/// Signer provides signatures for the data. +#[async_trait::async_trait] +pub trait Signer { + /// Signature error. + /// Error may originate from communicating with HSM, or from a thread pool failure, etc. + type Error; + + /// Sign the provided data and return the signature, or an error if the signing fails. + async fn sign<'a, D>(&self, data: D) -> std::result::Result + where + D: AsRef<[u8]> + Send + 'a; +} + +/// A factory that spits out [`Signer`]s. +pub trait Factory { + /// The type of [`Signer`] this factory will create. + type Signer: Signer; + + /// Create a [`Signer`] using the provided public key. + fn new_signer(&self, key: K) -> Self::Signer; +} + +impl Factory for P +where + P: std::ops::Deref, + F: Fn(K) -> S, + S: Signer, +{ + type Signer = S; + + fn new_signer(&self, key: K) -> Self::Signer { + self(key) + } +} diff --git a/crates/humanode-rpc/src/lib.rs b/crates/humanode-rpc/src/lib.rs index 881e8653c..512f1e2e4 100644 --- a/crates/humanode-rpc/src/lib.rs +++ b/crates/humanode-rpc/src/lib.rs @@ -4,7 +4,7 @@ use std::{collections::BTreeMap, sync::Arc}; use author_ext_api::AuthorExtApi; use author_ext_rpc::{AuthorExt, AuthorExtServer}; -use bioauth_flow_rpc::{Bioauth, BioauthServer, Signer, SignerFactory}; +use bioauth_flow_rpc::{signer, Bioauth, BioauthServer, Signer}; use bioauth_keys::traits::KeyExtractor as KeyExtractorT; use fc_rpc::{ Eth, EthApiServer, EthBlockDataCacheTask, EthConfig, EthFilter, EthFilterApiServer, EthPubSub, @@ -175,9 +175,9 @@ where VKE: KeyExtractorT + Send + Sync + 'static, VKE::PublicKeyType: Encode + AsRef<[u8]> + Clone + Send + Sync + sp_runtime::Serialize, VKE::Error: std::fmt::Debug, - VSF: SignerFactory, VKE::PublicKeyType> + Send + Sync + 'static, + VSF: signer::Factory, VKE::PublicKeyType> + Send + Sync + 'static, VSF::Signer: Send + Sync + 'static, - <, VKE::PublicKeyType>>::Signer as Signer>>::Error: + <, VKE::PublicKeyType>>::Signer as Signer>>::Error: std::error::Error + 'static, A: ChainApi + 'static, SC: SelectChain + 'static,