use std::convert::TryFrom;
use serde::{Deserialize, Serialize};
#[cfg(feature = "oobi")]
use crate::oobi::OobiManager;
use crate::{
error::Error,
event_message::{
cesr_adapter::ParseError,
signed_event_message::{Message, Notice},
},
prefix::IdentifierPrefix,
processor::Processor,
};
#[cfg(feature = "query")]
use crate::{
event_message::signed_event_message::Op,
processor::event_storage::EventStorage,
query::{
key_state_notice::KeyStateNotice,
query_event::QueryRoute,
query_event::SignedKelQuery,
reply_event::{ReplyRoute, SignedReply},
ReplyType,
},
};
#[cfg(feature = "mailbox")]
use crate::{
event_message::{signature::Signature, signed_event_message::SignedEventMessage},
mailbox::exchange::{Exchange, ExchangeMessage, ForwardTopic, SignedExchange},
};
pub use cesrox::cesr_proof::MaterialPath;
use cesrox::parse_many;
#[cfg(feature = "query")]
use said::version::format::SerializationFormats;
pub mod error;
pub mod event_generator;
#[cfg(all(feature = "query", feature = "oobi", feature = "mailbox"))]
pub mod simple_controller;
pub fn parse_event_stream(stream: &[u8]) -> Result<Vec<Message>, ParseError> {
let (_rest, events) = parse_many(stream).map_err(|e| ParseError::CesrError(e.to_string()))?;
events.into_iter().map(Message::try_from).collect()
}
pub fn parse_notice_stream(stream: &[u8]) -> Result<Vec<Notice>, ParseError> {
let (_rest, notices) = parse_many(stream).map_err(|e| ParseError::CesrError(e.to_string()))?;
notices.into_iter().map(Notice::try_from).collect()
}
#[cfg(any(feature = "query", feature = "oobi"))]
pub fn parse_op_stream(stream: &[u8]) -> Result<Vec<Op>, ParseError> {
let (_rest, ops) = parse_many(stream).map_err(|e| ParseError::CesrError(e.to_string()))?;
ops.into_iter().map(Op::try_from).collect()
}
#[cfg(any(feature = "query", feature = "oobi"))]
pub fn parse_query_stream(stream: &[u8]) -> Result<Vec<SignedKelQuery>, ParseError> {
let (_rest, queries) = parse_many(stream).map_err(|e| ParseError::CesrError(e.to_string()))?;
queries.into_iter().map(SignedKelQuery::try_from).collect()
}
#[cfg(any(feature = "query", feature = "oobi"))]
pub fn parse_reply_stream(stream: &[u8]) -> Result<Vec<SignedReply>, ParseError> {
let (_rest, replies) = parse_many(stream).map_err(|e| ParseError::CesrError(e.to_string()))?;
replies.into_iter().map(SignedReply::try_from).collect()
}
#[cfg(feature = "mailbox")]
pub fn parse_exchange_stream(stream: &[u8]) -> Result<Vec<SignedExchange>, ParseError> {
let (_rest, exchanges) =
parse_many(stream).map_err(|e| ParseError::CesrError(e.to_string()))?;
exchanges
.into_iter()
.map(SignedExchange::try_from)
.collect()
}
pub fn process_notice<P: Processor>(msg: Notice, processor: &P) -> Result<(), Error> {
processor.process_notice(&msg)
}
#[cfg(feature = "query")]
pub fn process_reply<P: Processor>(
sr: SignedReply,
#[cfg(feature = "oobi")] oobi_manager: &OobiManager,
processor: &P,
event_storage: &EventStorage,
) -> Result<(), Error> {
match sr.reply.get_route() {
#[cfg(feature = "oobi")]
ReplyRoute::LocScheme(_) | ReplyRoute::EndRoleAdd(_) | ReplyRoute::EndRoleCut(_) => {
process_signed_oobi(&sr, oobi_manager, event_storage)
}
ReplyRoute::Ksn(_, _) => processor.process_op_reply(&sr),
}
}
#[cfg(feature = "oobi")]
pub fn process_signed_oobi(
signed_oobi: &SignedReply,
oobi_manager: &OobiManager,
event_storage: &EventStorage,
) -> Result<(), Error> {
use crate::processor::validator::EventValidator;
let validator = EventValidator::new(event_storage.db.clone());
validator.verify(&signed_oobi.reply.encode()?, &signed_oobi.signature)?;
signed_oobi.reply.check_digest()?;
oobi_manager
.process_oobi(signed_oobi)
.map_err(|e| Error::SemanticError(e.to_string()))?;
Ok(())
}
#[cfg(feature = "mailbox")]
pub fn process_signed_exn(exn: SignedExchange, storage: &EventStorage) -> Result<(), Error> {
let exn_message = &exn.exchange_message;
let verification_result =
exn.signature
.iter()
.try_fold(true, |acc, signature| -> Result<bool, Error> {
Ok(acc && signature.verify(&exn_message.encode()?, storage)?)
});
if verification_result? {
process_exn(exn_message, exn.data_signature, storage)
} else {
Err(Error::SignatureVerificationError)
}
}
#[cfg(feature = "mailbox")]
fn process_exn(
exn: &ExchangeMessage,
attachemnt: (MaterialPath, Vec<Signature>),
storage: &EventStorage,
) -> Result<(), Error> {
let (receipient, to_forward, topic) = match &exn.data.data {
Exchange::Fwd { args, to_forward } => (&args.recipient_id, to_forward, &args.topic),
};
let (sigs, witness_receipts) = attachemnt.1.into_iter().fold(
(vec![], vec![]),
|(mut signatures, mut witness_receipts), s| {
match s {
Signature::Transferable(_sd, mut sigs) => signatures.append(&mut sigs),
Signature::NonTransferable(receipts) => witness_receipts.push(receipts),
}
(signatures, witness_receipts)
},
);
let signed_to_forward = SignedEventMessage {
event_message: to_forward.clone(),
signatures: sigs,
witness_receipts: if witness_receipts.is_empty() {
None
} else {
Some(witness_receipts)
},
delegator_seal: None,
};
match topic {
ForwardTopic::Multisig => {
storage.add_mailbox_multisig(receipient, signed_to_forward)?;
}
ForwardTopic::Delegate => {
storage.add_mailbox_delegate(receipient, signed_to_forward)?;
}
};
Ok(())
}
#[cfg(feature = "query")]
pub fn process_signed_query(
qr: SignedKelQuery,
storage: &EventStorage,
) -> Result<ReplyType, SignedQueryError> {
let signature = qr.signature;
let ver_result = signature.verify(
&qr.query.encode().map_err(|_e| Error::VersionError)?,
storage,
)?;
if !ver_result {
return Err(SignedQueryError::InvalidSignature);
};
Ok(process_query(qr.query.get_route(), storage)?)
}
#[derive(Debug, thiserror::Error, Serialize, Deserialize)]
pub enum SignedQueryError {
#[error(transparent)]
KeriError(#[from] crate::error::Error),
#[error(transparent)]
DbError(#[from] crate::database::DbError),
#[error(transparent)]
QueryError(#[from] QueryError),
#[error("unknown signer with id {id:?}")]
UnknownSigner { id: IdentifierPrefix },
#[error("signature verification failed")]
InvalidSignature,
}
#[cfg(feature = "query")]
fn process_query(qr: &QueryRoute, storage: &EventStorage) -> Result<ReplyType, QueryError> {
match qr {
QueryRoute::Log { args, .. } => Ok(ReplyType::Kel(
storage
.get_kel_messages_with_receipts(&args.i)?
.ok_or_else(|| QueryError::UnknownId { id: args.i.clone() })?
.into_iter()
.map(Message::Notice)
.collect(),
)),
QueryRoute::Ksn { args, .. } => {
let state = storage
.get_state(&args.i)?
.ok_or_else(|| QueryError::UnknownId { id: args.i.clone() })?;
let ksn = KeyStateNotice::new_ksn(state, SerializationFormats::JSON);
Ok(ReplyType::Ksn(ksn))
}
#[cfg(feature = "mailbox")]
QueryRoute::Mbx { args, .. } => {
let mail = storage.get_mailbox_messages(args)?;
Ok(ReplyType::Mbx(mail))
}
}
}
#[derive(Debug, thiserror::Error, Serialize, Deserialize)]
pub enum QueryError {
#[error(transparent)]
KeriError(#[from] crate::error::Error),
#[error(transparent)]
DbError(#[from] crate::database::DbError),
#[error("unknown identifier {id:?}")]
UnknownId { id: IdentifierPrefix },
}
pub mod prelude {
#[cfg(feature = "oobi")]
pub use crate::actor::process_signed_oobi;
#[cfg(feature = "query")]
pub use crate::actor::{process_reply, process_signed_query};
#[cfg(feature = "query")]
pub use crate::query::ReplyType;
pub use crate::{
actor::process_notice,
database::SledEventDatabase,
event_message::signed_event_message::Message,
processor::{basic_processor::BasicProcessor, event_storage::EventStorage, Processor},
};
pub use said::version::{error::Error as VersionError, format::SerializationFormats};
pub use said::{
derivation::HashFunction, derivation::HashFunctionCode, SelfAddressingIdentifier,
};
}