1#![deny(missing_docs)]
2use kitsune2_api::*;
5use std::sync::{Arc, Mutex};
6
7#[derive(Debug)]
9pub struct Ed25519Verifier;
10
11impl Verifier for Ed25519Verifier {
12 fn verify(
13 &self,
14 agent_info: &AgentInfo,
15 message: &[u8],
16 signature: &[u8],
17 ) -> bool {
18 use ed25519_dalek::Verifier;
19
20 let agent: [u8; 32] = match (***agent_info.agent).try_into() {
21 Ok(agent) => agent,
22 Err(_) => return false,
23 };
24
25 let agent = match ed25519_dalek::VerifyingKey::from_bytes(&agent) {
26 Ok(agent) => agent,
27 Err(_) => return false,
28 };
29
30 let signature: [u8; 64] = match signature.try_into() {
31 Ok(signature) => signature,
32 Err(_) => return false,
33 };
34
35 let signature = ed25519_dalek::Signature::from_bytes(&signature);
36
37 agent.verify(message, &signature).is_ok()
38 }
39}
40
41struct Ed25519LocalAgentInner {
42 cb: Option<Arc<dyn Fn() + 'static + Send + Sync>>,
43 cur: DhtArc,
44 tgt: DhtArc,
45}
46
47pub struct Ed25519LocalAgent {
49 pk: ed25519_dalek::SigningKey,
50 id: AgentId,
51 inner: Mutex<Ed25519LocalAgentInner>,
52}
53
54impl std::fmt::Debug for Ed25519LocalAgent {
55 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
56 let storage_arc = self.inner.lock().unwrap().cur;
57 f.debug_struct("Ed25519LocalAgent")
58 .field("agent", &self.id)
59 .field("storage_arc", &storage_arc)
60 .finish()
61 }
62}
63
64impl Default for Ed25519LocalAgent {
65 fn default() -> Self {
66 Self::new(ed25519_dalek::SigningKey::generate(&mut rand::thread_rng()))
67 }
68}
69
70impl Ed25519LocalAgent {
71 fn new(pk: ed25519_dalek::SigningKey) -> Self {
72 let id = bytes::Bytes::copy_from_slice(pk.verifying_key().as_bytes());
73 Self {
74 pk,
75 id: id.into(),
76 inner: Mutex::new(Ed25519LocalAgentInner {
77 cb: None,
78 cur: DhtArc::Empty,
79 tgt: DhtArc::Empty,
80 }),
81 }
82 }
83
84 pub fn from_seed(seed: &[u8; 32]) -> Self {
86 Self::new(ed25519_dalek::SigningKey::from_bytes(seed))
87 }
88
89 pub fn sign(&self, message: &[u8]) -> bytes::Bytes {
91 use ed25519_dalek::Signer;
92 bytes::Bytes::copy_from_slice(&self.pk.sign(message).to_bytes())
93 }
94}
95
96impl Signer for Ed25519LocalAgent {
97 fn sign<'a, 'b: 'a, 'c: 'a>(
98 &'a self,
99 _agent_info: &'b AgentInfo,
100 message: &'c [u8],
101 ) -> BoxFut<'a, K2Result<bytes::Bytes>> {
102 Box::pin(async move { Ok(self.sign(message)) })
103 }
104}
105
106impl LocalAgent for Ed25519LocalAgent {
107 fn agent(&self) -> &AgentId {
108 &self.id
109 }
110
111 fn register_cb(&self, cb: Arc<dyn Fn() + 'static + Send + Sync>) {
112 self.inner.lock().unwrap().cb = Some(cb);
113 }
114
115 fn invoke_cb(&self) {
116 let cb = self.inner.lock().unwrap().cb.clone();
117 if let Some(cb) = cb {
118 cb();
119 }
120 }
121
122 fn get_cur_storage_arc(&self) -> DhtArc {
123 self.inner.lock().unwrap().cur
124 }
125
126 fn set_cur_storage_arc(&self, arc: DhtArc) {
127 self.inner.lock().unwrap().cur = arc;
128 }
129
130 fn get_tgt_storage_arc(&self) -> DhtArc {
131 self.inner.lock().unwrap().tgt
132 }
133
134 fn set_tgt_storage_arc_hint(&self, arc: DhtArc) {
135 self.inner.lock().unwrap().tgt = arc;
136 }
137}
138
139pub fn default_test_builder() -> Builder {
157 Builder {
158 config: Config::default(),
159 verifier: Arc::new(Ed25519Verifier),
160 auth_material: None,
161 kitsune: factories::CoreKitsuneFactory::create(),
162 space: factories::CoreSpaceFactory::create(),
163 peer_store: factories::MemPeerStoreFactory::create(),
164 bootstrap: factories::MemBootstrapFactory::create(),
165 fetch: factories::CoreFetchFactory::create(),
166 report: factories::CoreReportFactory::create(),
167 transport: factories::MemTransportFactory::create(),
168 op_store: factories::MemOpStoreFactory::create(),
169 peer_meta_store: factories::MemPeerMetaStoreFactory::create(),
170 gossip: factories::CoreGossipStubFactory::create(),
171 local_agent_store: factories::CoreLocalAgentStoreFactory::create(),
172 publish: factories::CorePublishFactory::create(),
173 blocks: factories::MemBlocksFactory::create(),
174 }
175}
176
177pub mod factories;
178
179mod common;
180pub use common::*;
181
182#[cfg(any(doc, docsrs))]
183pub mod doc;
184
185#[cfg(test)]
186mod test {
187 use super::*;
188
189 #[test]
190 fn ed25519_sanity() {
191 use kitsune2_api::*;
192 use kitsune2_test_utils::agent::*;
193
194 let i1 = AgentBuilder::default().build(Ed25519LocalAgent::default());
195 let enc = i1.encode().unwrap();
196 let i2 =
197 AgentInfoSigned::decode(&Ed25519Verifier, enc.as_bytes()).unwrap();
198
199 assert_eq!(i1, i2);
200 }
201}