use std::future::Future;
use auths_keri::Prefix;
use auths_verifier::core::Ed25519PublicKey;
#[derive(Debug, thiserror::Error)]
#[non_exhaustive]
pub enum NetworkError {
#[error("endpoint unreachable: {endpoint}")]
Unreachable {
endpoint: String,
},
#[error("request timed out: {endpoint}")]
Timeout {
endpoint: String,
},
#[error("resource not found: {resource}")]
NotFound {
resource: String,
},
#[error("unauthorized")]
Unauthorized,
#[error("invalid response: {detail}")]
InvalidResponse {
detail: String,
},
#[error("internal network error: {0}")]
Internal(Box<dyn std::error::Error + Send + Sync>),
}
impl auths_crypto::AuthsErrorInfo for NetworkError {
fn error_code(&self) -> &'static str {
match self {
Self::Unreachable { .. } => "AUTHS-E3601",
Self::Timeout { .. } => "AUTHS-E3602",
Self::NotFound { .. } => "AUTHS-E3603",
Self::Unauthorized => "AUTHS-E3604",
Self::InvalidResponse { .. } => "AUTHS-E3605",
Self::Internal(_) => "AUTHS-E3606",
}
}
fn suggestion(&self) -> Option<&'static str> {
match self {
Self::Unreachable { .. } => Some("Check your internet connection"),
Self::Timeout { .. } => Some("The server may be overloaded — retry later"),
Self::Unauthorized => Some("Check your authentication credentials"),
Self::NotFound { .. } => Some(
"The requested resource was not found on the server; verify the URL or identifier",
),
Self::InvalidResponse { .. } => {
Some("The server returned an unexpected response; check server compatibility")
}
Self::Internal(_) => Some(
"The server encountered an internal error; retry later or contact the server administrator",
),
}
}
}
#[derive(Debug, thiserror::Error)]
#[non_exhaustive]
pub enum ResolutionError {
#[error("DID not found: {did}")]
DidNotFound {
did: String,
},
#[error("invalid DID {did}: {reason}")]
InvalidDid {
did: String,
reason: String,
},
#[error("key revoked for DID: {did}")]
KeyRevoked {
did: String,
},
#[error("network error: {0}")]
Network(#[from] NetworkError),
}
impl auths_crypto::AuthsErrorInfo for ResolutionError {
fn error_code(&self) -> &'static str {
match self {
Self::DidNotFound { .. } => "AUTHS-E3701",
Self::InvalidDid { .. } => "AUTHS-E3702",
Self::KeyRevoked { .. } => "AUTHS-E3703",
Self::Network(_) => "AUTHS-E3704",
}
}
fn suggestion(&self) -> Option<&'static str> {
match self {
Self::DidNotFound { .. } => Some("Verify the DID is correct and the identity exists"),
Self::InvalidDid { .. } => {
Some("Check the DID format (e.g., did:key:z6Mk... or did:keri:E...)")
}
Self::KeyRevoked { .. } => {
Some("This key has been revoked — contact the identity owner")
}
Self::Network(_) => Some("Check your internet connection"),
}
}
}
#[derive(Debug, Clone)]
pub enum ResolvedIdentity {
Key {
did: String,
public_key: Ed25519PublicKey,
},
Keri {
did: String,
public_key: Ed25519PublicKey,
sequence: u128,
can_rotate: bool,
},
}
impl ResolvedIdentity {
pub fn did(&self) -> &str {
match self {
ResolvedIdentity::Key { did, .. } | ResolvedIdentity::Keri { did, .. } => did,
}
}
pub fn public_key(&self) -> &Ed25519PublicKey {
match self {
ResolvedIdentity::Key { public_key, .. }
| ResolvedIdentity::Keri { public_key, .. } => public_key,
}
}
pub fn is_key(&self) -> bool {
matches!(self, ResolvedIdentity::Key { .. })
}
pub fn is_keri(&self) -> bool {
matches!(self, ResolvedIdentity::Keri { .. })
}
}
pub trait IdentityResolver: Send + Sync {
fn resolve_identity(
&self,
did: &str,
) -> impl Future<Output = Result<ResolvedIdentity, ResolutionError>> + Send;
}
pub trait WitnessClient: Send + Sync {
fn submit_event(
&self,
endpoint: &str,
event: &[u8],
) -> impl Future<Output = Result<Vec<u8>, NetworkError>> + Send;
fn query_receipts(
&self,
endpoint: &str,
prefix: &Prefix,
) -> impl Future<Output = Result<Vec<Vec<u8>>, NetworkError>> + Send;
}
#[derive(Debug, Clone, Default)]
pub struct RateLimitInfo {
pub limit: Option<i32>,
pub remaining: Option<i32>,
pub reset: Option<i64>,
pub tier: Option<String>,
}
#[derive(Debug)]
pub struct RegistryResponse {
pub status: u16,
pub body: Vec<u8>,
pub rate_limit: Option<RateLimitInfo>,
}
pub trait RegistryClient: Send + Sync {
fn fetch_registry_data(
&self,
registry_url: &str,
path: &str,
) -> impl Future<Output = Result<Vec<u8>, NetworkError>> + Send;
fn push_registry_data(
&self,
registry_url: &str,
path: &str,
data: &[u8],
) -> impl Future<Output = Result<(), NetworkError>> + Send;
fn post_json(
&self,
registry_url: &str,
path: &str,
json_body: &[u8],
) -> impl Future<Output = Result<RegistryResponse, NetworkError>> + Send;
}