#![deny(missing_docs)]
use kitsune2_api::*;
use std::sync::{Arc, Mutex};
#[derive(Debug)]
pub struct Ed25519Verifier;
impl Verifier for Ed25519Verifier {
fn verify(
&self,
agent_info: &AgentInfo,
message: &[u8],
signature: &[u8],
) -> bool {
use ed25519_dalek::Verifier;
let agent: [u8; 32] = match (***agent_info.agent).try_into() {
Ok(agent) => agent,
Err(_) => return false,
};
let agent = match ed25519_dalek::VerifyingKey::from_bytes(&agent) {
Ok(agent) => agent,
Err(_) => return false,
};
let signature: [u8; 64] = match signature.try_into() {
Ok(signature) => signature,
Err(_) => return false,
};
let signature = ed25519_dalek::Signature::from_bytes(&signature);
agent.verify(message, &signature).is_ok()
}
}
struct Ed25519LocalAgentInner {
cb: Option<Arc<dyn Fn() + 'static + Send + Sync>>,
cur: DhtArc,
tgt: DhtArc,
}
pub struct Ed25519LocalAgent {
pk: ed25519_dalek::SigningKey,
id: AgentId,
inner: Mutex<Ed25519LocalAgentInner>,
}
impl std::fmt::Debug for Ed25519LocalAgent {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let storage_arc = self.inner.lock().unwrap().cur;
f.debug_struct("Ed25519LocalAgent")
.field("agent", &self.id)
.field("storage_arc", &storage_arc)
.finish()
}
}
impl Default for Ed25519LocalAgent {
fn default() -> Self {
Self::new(ed25519_dalek::SigningKey::generate(&mut rand::thread_rng()))
}
}
impl Ed25519LocalAgent {
fn new(pk: ed25519_dalek::SigningKey) -> Self {
let id = bytes::Bytes::copy_from_slice(pk.verifying_key().as_bytes());
Self {
pk,
id: id.into(),
inner: Mutex::new(Ed25519LocalAgentInner {
cb: None,
cur: DhtArc::Empty,
tgt: DhtArc::Empty,
}),
}
}
pub fn from_seed(seed: &[u8; 32]) -> Self {
Self::new(ed25519_dalek::SigningKey::from_bytes(seed))
}
pub fn sign(&self, message: &[u8]) -> bytes::Bytes {
use ed25519_dalek::Signer;
bytes::Bytes::copy_from_slice(&self.pk.sign(message).to_bytes())
}
}
impl Signer for Ed25519LocalAgent {
fn sign<'a, 'b: 'a, 'c: 'a>(
&'a self,
_agent_info: &'b AgentInfo,
message: &'c [u8],
) -> BoxFut<'a, K2Result<bytes::Bytes>> {
Box::pin(async move { Ok(self.sign(message)) })
}
}
impl LocalAgent for Ed25519LocalAgent {
fn agent(&self) -> &AgentId {
&self.id
}
fn register_cb(&self, cb: Arc<dyn Fn() + 'static + Send + Sync>) {
self.inner.lock().unwrap().cb = Some(cb);
}
fn invoke_cb(&self) {
let cb = self.inner.lock().unwrap().cb.clone();
if let Some(cb) = cb {
cb();
}
}
fn get_cur_storage_arc(&self) -> DhtArc {
self.inner.lock().unwrap().cur
}
fn set_cur_storage_arc(&self, arc: DhtArc) {
self.inner.lock().unwrap().cur = arc;
}
fn get_tgt_storage_arc(&self) -> DhtArc {
self.inner.lock().unwrap().tgt
}
fn set_tgt_storage_arc_hint(&self, arc: DhtArc) {
self.inner.lock().unwrap().tgt = arc;
}
}
pub fn default_test_builder() -> Builder {
Builder {
config: Config::default(),
verifier: Arc::new(Ed25519Verifier),
auth_material: None,
kitsune: factories::CoreKitsuneFactory::create(),
space: factories::CoreSpaceFactory::create(),
peer_store: factories::MemPeerStoreFactory::create(),
bootstrap: factories::MemBootstrapFactory::create(),
fetch: factories::CoreFetchFactory::create(),
report: factories::CoreReportFactory::create(),
transport: factories::MemTransportFactory::create(),
op_store: factories::MemOpStoreFactory::create(),
peer_meta_store: factories::MemPeerMetaStoreFactory::create(),
gossip: factories::CoreGossipStubFactory::create(),
local_agent_store: factories::CoreLocalAgentStoreFactory::create(),
publish: factories::CorePublishFactory::create(),
blocks: factories::MemBlocksFactory::create(),
}
}
pub mod factories;
mod common;
pub use common::*;
#[cfg(any(doc, docsrs))]
pub mod doc;
#[cfg(test)]
mod test {
use super::*;
#[test]
fn ed25519_sanity() {
use kitsune2_api::*;
use kitsune2_test_utils::agent::*;
let i1 = AgentBuilder::default().build(Ed25519LocalAgent::default());
let enc = i1.encode().unwrap();
let i2 =
AgentInfoSigned::decode(&Ed25519Verifier, enc.as_bytes()).unwrap();
assert_eq!(i1, i2);
}
}