keri_core/actor/
mod.rs

1use std::convert::TryFrom;
2
3use serde::{Deserialize, Serialize};
4
5#[cfg(feature = "oobi-manager")]
6use crate::oobi_manager::OobiManager;
7#[cfg(feature = "query")]
8use crate::{
9    database::EventDatabase,
10    event_message::{signature::Signature, signed_event_message::Op},
11    processor::event_storage::EventStorage,
12    query::{
13        key_state_notice::KeyStateNotice,
14        query_event::QueryRoute,
15        query_event::SignedQueryMessage,
16        reply_event::{ReplyRoute, SignedReply},
17        ReplyType,
18    },
19};
20use crate::{
21    error::Error,
22    event_message::{
23        cesr_adapter::ParseError,
24        signed_event_message::{Message, Notice},
25    },
26    prefix::IdentifierPrefix,
27    processor::Processor,
28};
29#[cfg(feature = "mailbox")]
30use crate::{
31    event_message::signed_event_message::SignedEventMessage,
32    mailbox::exchange::{Exchange, ExchangeMessage, ForwardTopic, SignedExchange},
33    query::mailbox::MailboxRoute,
34};
35pub use cesrox::cesr_proof::MaterialPath;
36use cesrox::parse_many;
37#[cfg(feature = "query")]
38use said::version::format::SerializationFormats;
39
40pub mod error;
41pub mod event_generator;
42
43#[cfg(feature = "query")]
44pub mod possible_response;
45#[cfg(all(feature = "mailbox", feature = "oobi-manager"))]
46pub mod simple_controller;
47
48pub fn parse_event_stream(stream: &[u8]) -> Result<Vec<Message>, ParseError> {
49    let (_rest, events) = parse_many(stream).map_err(|e| ParseError::CesrError(e.to_string()))?;
50    events.into_iter().map(Message::try_from).collect()
51}
52
53pub fn parse_notice_stream(stream: &[u8]) -> Result<Vec<Notice>, ParseError> {
54    let (_rest, notices) = parse_many(stream).map_err(|e| ParseError::CesrError(e.to_string()))?;
55    notices.into_iter().map(Notice::try_from).collect()
56}
57
58#[cfg(any(feature = "query", feature = "oobi-manager"))]
59pub fn parse_op_stream(stream: &[u8]) -> Result<Vec<Op>, ParseError> {
60    let (_rest, ops) = parse_many(stream).map_err(|e| ParseError::CesrError(e.to_string()))?;
61    ops.into_iter().map(Op::try_from).collect()
62}
63
64#[cfg(any(feature = "query", feature = "oobi-manager"))]
65pub fn parse_query_stream(stream: &[u8]) -> Result<Vec<SignedQueryMessage>, ParseError> {
66    let (_rest, queries) = parse_many(stream).map_err(|e| ParseError::CesrError(e.to_string()))?;
67    queries
68        .into_iter()
69        .map(SignedQueryMessage::try_from)
70        .collect()
71}
72
73#[cfg(feature = "query")]
74pub fn parse_reply_stream(stream: &[u8]) -> Result<Vec<SignedReply>, ParseError> {
75    let (_rest, replies) = parse_many(stream).map_err(|e| ParseError::CesrError(e.to_string()))?;
76    replies.into_iter().map(SignedReply::try_from).collect()
77}
78
79#[cfg(feature = "mailbox")]
80pub fn parse_exchange_stream(stream: &[u8]) -> Result<Vec<SignedExchange>, ParseError> {
81    let (_rest, exchanges) =
82        parse_many(stream).map_err(|e| ParseError::CesrError(e.to_string()))?;
83    exchanges
84        .into_iter()
85        .map(SignedExchange::try_from)
86        .collect()
87}
88
89pub fn process_notice<P: Processor>(msg: Notice, processor: &P) -> Result<(), Error> {
90    processor.process_notice(&msg)
91}
92
93#[cfg(feature = "query")]
94pub fn process_reply<P: Processor>(
95    sr: SignedReply,
96    #[cfg(feature = "oobi-manager")] oobi_manager: &OobiManager,
97    processor: &P,
98    event_storage: &EventStorage<P::Database>,
99) -> Result<(), Error> {
100    match sr.reply.get_route() {
101        #[cfg(feature = "oobi-manager")]
102        ReplyRoute::LocScheme(_) | ReplyRoute::EndRoleAdd(_) | ReplyRoute::EndRoleCut(_) => {
103            process_signed_oobi(&sr, oobi_manager, event_storage)
104        }
105        ReplyRoute::Ksn(_, _) => processor.process_op_reply(&sr),
106        _ => { Ok(()) }
107    }
108}
109
110#[cfg(feature = "oobi-manager")]
111pub fn process_signed_oobi<D: EventDatabase + 'static>(
112    signed_oobi: &SignedReply,
113    oobi_manager: &OobiManager,
114    event_storage: &EventStorage<D>,
115) -> Result<(), Error> {
116    use crate::processor::validator::EventValidator;
117
118    let validator = EventValidator::new(event_storage.events_db.clone());
119    // check signature
120    validator.verify(&signed_oobi.reply.encode()?, &signed_oobi.signature)?;
121    // check digest
122    signed_oobi.reply.check_digest()?;
123    // save
124    let r = oobi_manager
125        .process_oobi(signed_oobi)
126        .map_err(|e| Error::SemanticError(e.to_string()))?;
127
128    Ok(())
129}
130
131#[cfg(feature = "mailbox")]
132pub fn process_signed_exn<D: EventDatabase>(
133    exn: SignedExchange,
134    storage: &EventStorage<D>,
135) -> Result<(), Error> {
136    let exn_message = &exn.exchange_message;
137    let verification_result =
138        exn.signature
139            .iter()
140            .try_fold(true, |acc, signature| -> Result<bool, Error> {
141                Ok(acc && signature.verify(&exn_message.encode()?, storage)?)
142            });
143    if verification_result? {
144        process_exn(exn_message, exn.data_signature, storage)
145    } else {
146        Err(Error::SignatureVerificationError)
147    }
148}
149
150#[cfg(feature = "mailbox")]
151fn process_exn<D: EventDatabase>(
152    exn: &ExchangeMessage,
153    attachment: (MaterialPath, Vec<Signature>),
154    storage: &EventStorage<D>,
155) -> Result<(), Error> {
156    let (recipient, to_forward, topic) = match &exn.data.data {
157        Exchange::Fwd { args, to_forward } => (&args.recipient_id, to_forward, &args.topic),
158    };
159    let (sigs, witness_receipts) = attachment.1.into_iter().fold(
160        (vec![], vec![]),
161        |(mut signatures, mut witness_receipts), s| {
162            match s {
163                Signature::Transferable(_sd, mut sigs) => signatures.append(&mut sigs),
164                Signature::NonTransferable(receipts) => witness_receipts.push(receipts),
165            }
166            (signatures, witness_receipts)
167        },
168    );
169
170    let signed_to_forward = SignedEventMessage {
171        event_message: to_forward.clone(),
172        signatures: sigs,
173        witness_receipts: if witness_receipts.is_empty() {
174            None
175        } else {
176            Some(witness_receipts)
177        },
178        delegator_seal: None,
179    };
180
181    match topic {
182        ForwardTopic::Multisig => {
183            storage.add_mailbox_multisig(recipient, signed_to_forward)?;
184        }
185        ForwardTopic::Delegate => {
186            storage.add_mailbox_delegate(recipient, signed_to_forward)?;
187        }
188    };
189    Ok(())
190}
191
192#[cfg(feature = "query")]
193pub fn process_signed_query<D: EventDatabase>(
194    qr: SignedQueryMessage,
195    storage: &EventStorage<D>,
196) -> Result<ReplyType, SignedQueryError> {
197    let verify = |data: &[u8], signature: Signature| -> Result<_, SignedQueryError> {
198        let ver_result = signature.verify(&data, storage)?;
199        if !ver_result {
200            Err(SignedQueryError::InvalidSignature)
201        } else {
202            Ok(())
203        }
204    };
205    match qr {
206        SignedQueryMessage::KelQuery(kqry) => {
207            let signature = kqry.signature;
208            let data = &kqry.query.encode().map_err(|_e| Error::VersionError)?;
209            // check signatures
210            verify(&data, signature)?;
211
212            // TODO check timestamps
213            // unpack and check what's inside
214            Ok(process_query(kqry.query.get_route(), storage)?)
215        }
216        #[cfg(feature = "mailbox")]
217        SignedQueryMessage::MailboxQuery(mqry) => {
218            let signature = mqry.signature;
219            let data = &mqry.query.encode().map_err(|_e| Error::VersionError)?;
220            // check signatures
221            verify(&data, signature)?;
222            Ok(process_mailbox_query(&mqry.query.data.data, storage)?)
223        }
224    }
225}
226
227#[derive(Debug, thiserror::Error, Serialize, Deserialize)]
228pub enum SignedQueryError {
229    #[error(transparent)]
230    KeriError(#[from] crate::error::Error),
231
232    #[error(transparent)]
233    QueryError(#[from] QueryError),
234
235    #[error("unknown signer with id {id:?}")]
236    UnknownSigner { id: IdentifierPrefix },
237
238    #[error("signature verification failed")]
239    InvalidSignature,
240}
241
242#[cfg(feature = "query")]
243pub fn process_query<D: EventDatabase>(
244    qr: &QueryRoute,
245    storage: &EventStorage<D>,
246) -> Result<ReplyType, QueryError> {
247    match qr {
248        QueryRoute::Ksn { args, .. } => {
249            // return reply message with ksn inside
250            let state = storage
251                .get_state(&args.i)
252                .ok_or_else(|| QueryError::UnknownId { id: args.i.clone() })?;
253            let ksn = KeyStateNotice::new_ksn(state, SerializationFormats::JSON);
254            Ok(ReplyType::Ksn(ksn))
255        }
256        QueryRoute::Logs {
257            reply_route: _,
258            args,
259        } => {
260            let response = match (args.s, args.limit) {
261                (None, _) => storage.get_kel_messages_with_receipts_all(&args.i)?,
262                (Some(sn), None) => storage
263                    .get_event_at_sn(&args.i, sn)
264                    .map(|event| vec![Notice::Event(event.signed_event_message)]),
265                (Some(sn), Some(limit)) => {
266                    storage.get_kel_messages_with_receipts_range(&args.i, sn, limit)?
267                }
268            }
269            .ok_or_else(|| QueryError::UnknownId { id: args.i.clone() })?
270            .into_iter()
271            .map(Message::Notice)
272            .collect::<Vec<_>>();
273
274            Ok(ReplyType::Kel(response))
275        }
276    }
277}
278
279#[cfg(feature = "mailbox")]
280pub fn process_mailbox_query<D: EventDatabase>(
281    qr: &MailboxRoute,
282    storage: &EventStorage<D>,
283) -> Result<ReplyType, QueryError> {
284    match qr {
285        MailboxRoute::Mbx { args, .. } => {
286            let mail = storage.get_mailbox_messages(args)?;
287            Ok(ReplyType::Mbx(mail))
288        }
289    }
290}
291
292#[derive(Debug, thiserror::Error, Serialize, Deserialize)]
293pub enum QueryError {
294    #[error(transparent)]
295    KeriError(#[from] crate::error::Error),
296
297    #[error("unknown identifier {id:?}")]
298    UnknownId { id: IdentifierPrefix },
299}
300
301pub mod prelude {
302    #[cfg(feature = "oobi-manager")]
303    pub use crate::actor::process_signed_oobi;
304    #[cfg(feature = "query")]
305    pub use crate::actor::{process_reply, process_signed_query};
306    #[cfg(feature = "query")]
307    pub use crate::query::ReplyType;
308    pub use crate::{
309        actor::process_notice,
310        event_message::signed_event_message::Message,
311        processor::{basic_processor::BasicProcessor, event_storage::EventStorage, Processor},
312    };
313    pub use said::version::{error::Error as VersionError, format::SerializationFormats};
314    pub use said::{
315        derivation::HashFunction, derivation::HashFunctionCode, SelfAddressingIdentifier,
316    };
317}