use crypto::{Ed25519SigningKey, Ed25519VerifyingKey}; use libchat::{IdentId, IdentityProvider, trunc}; use crate::ClientError; type AccountAddr = String; pub struct DelegateSigner { signing_key: Ed25519SigningKey, verifying_key: Ed25519VerifyingKey, identifier: IdentId, account_addr: Option, } impl DelegateSigner { pub fn random() -> Self { let signing_key = Ed25519SigningKey::generate(); let verifying_key = signing_key.verifying_key(); let identifier = DelegateCredential::unassociated(&verifying_key).into(); Self { signing_key, verifying_key, identifier, account_addr: None, } } pub fn associate(&mut self, account_addr: AccountAddr) { self.identifier = DelegateCredential::associated(&self.verifying_key, account_addr.as_str()).into(); self.account_addr = Some(account_addr); } pub fn account_addr(&self) -> Option<&str> { self.account_addr.as_deref() } } impl IdentityProvider for DelegateSigner { fn id(&self) -> libchat::IdentIdRef<'_> { &self.identifier } fn display_name(&self) -> String { trunc(self.identifier.as_str()) } fn sign(&self, payload: &[u8]) -> crypto::Ed25519Signature { self.signing_key.sign(payload) } fn public_key(&self) -> &Ed25519VerifyingKey { &self.verifying_key } } /// Represents the senders information for received frames. #[derive(Debug)] pub struct DelegateCredential { delegate_id: Ed25519VerifyingKey, account_addr: Option, } impl DelegateCredential { const TAG_DELEGATE_ID: u8 = 0x01; const TAG_ACCOUNT_ADDR: u8 = 0x02; pub fn unassociated(delegate: &Ed25519VerifyingKey) -> Self { Self { delegate_id: delegate.clone(), account_addr: None, } } pub fn associated(delegate: &Ed25519VerifyingKey, account: &str) -> Self { Self { delegate_id: delegate.clone(), account_addr: Some(account.to_string()), } } pub fn to_vec(self) -> Vec { let mut data = Vec::new(); data.extend_from_slice(&[0x23, 0x23]); let key_bytes = self.delegate_id.as_ref(); data.extend_from_slice(&[Self::TAG_DELEGATE_ID, key_bytes.len() as u8]); data.extend_from_slice(key_bytes); if let Some(addr) = self.account_addr { let addr_bytes = addr.as_bytes(); data.extend_from_slice(&[Self::TAG_ACCOUNT_ADDR, addr_bytes.len() as u8]); data.extend_from_slice(addr_bytes); } data } } impl From for Vec { fn from(value: DelegateCredential) -> Self { value.to_vec() } } impl From> for DelegateCredential { fn from(value: Vec) -> Self { assert_eq!(&value[..2], &[0x23, 0x23], "invalid magic bytes"); let mut delegate_id = None; let mut account_addr = None; let mut i = 2; while i + 2 <= value.len() { let tag = value[i]; let len = value[i + 1] as usize; i += 2; let v = &value[i..i + len]; i += len; match tag { DelegateCredential::TAG_DELEGATE_ID => { let bytes: &[u8; 32] = v.try_into().expect("invalid delegate_id length"); delegate_id = Some( Ed25519VerifyingKey::from_bytes(bytes).expect("invalid verifying key"), ); } DelegateCredential::TAG_ACCOUNT_ADDR => { account_addr = Some(String::from_utf8(v.to_vec()).expect("invalid account_addr utf8")); } _ => {} } } Self { delegate_id: delegate_id.expect("missing delegate_id TLV field"), account_addr, } } } impl From for IdentId { fn from(value: DelegateCredential) -> Self { IdentId::new(hex::encode(value.to_vec())) } } impl TryFrom for DelegateCredential { type Error = ClientError; fn try_from(value: IdentId) -> Result { Ok(hex::decode(value.as_str()) .map_err(|e| ClientError::BadlyFormedCredential)? .into()) } }