1use crate::agent_key_manager::{AgentKeyManager, AgentKeyManagerBuilder};
2use crate::config::AgentConfig;
3#[cfg(all(not(target_arch = "wasm32"), test))]
4use crate::did::SyncDIDResolver; use crate::error::{Error, Result};
6use crate::key_manager::KeyManager; #[cfg(not(target_arch = "wasm32"))]
8use crate::message::SecurityMode;
9#[cfg(not(target_arch = "wasm32"))]
10use crate::message_packing::{PackOptions, Packable, UnpackOptions, Unpackable};
11#[cfg(not(target_arch = "wasm32"))]
12use async_trait::async_trait;
13#[cfg(feature = "native")]
14use reqwest::Client;
15#[cfg(target_arch = "wasm32")]
16use serde::de::DeserializeOwned;
17#[cfg(not(target_arch = "wasm32"))]
18use serde_json::Value;
19use std::path::PathBuf;
20use std::sync::Arc;
21#[cfg(feature = "native")]
22use std::time::Duration;
23#[cfg(not(target_arch = "wasm32"))]
24use tap_msg::didcomm::{PlainMessage, PlainMessageExt};
25use tap_msg::TapMessageBody;
26#[cfg(not(target_arch = "wasm32"))]
27use tracing::{debug, error, info, warn};
28
29pub type EnhancedAgentInfo = (
31 String,
32 Vec<String>,
33 std::collections::HashMap<String, String>,
34);
35
36#[derive(Debug, Clone)]
38pub struct DeliveryResult {
39 pub did: String,
41 pub endpoint: String,
43 pub status: Option<u16>,
45 pub error: Option<String>,
47}
48
49#[cfg(not(target_arch = "wasm32"))]
80#[async_trait]
81pub trait Agent {
82 fn get_agent_did(&self) -> &str;
84
85 async fn get_service_endpoint(&self, to: &str) -> Result<Option<String>>;
91
92 async fn send_message<
103 T: TapMessageBody + serde::Serialize + Send + Sync + std::fmt::Debug + 'static,
104 >(
105 &self,
106 message: &T,
107 to: Vec<&str>,
108 deliver: bool,
109 ) -> Result<(String, Vec<DeliveryResult>)>;
110
111 async fn receive_encrypted_message(&self, jwe_value: &Value) -> Result<()>;
122
123 async fn receive_plain_message(&self, message: PlainMessage) -> Result<()>;
132
133 async fn receive_message(&self, raw_message: &str) -> Result<PlainMessage>;
147
148 async fn send_typed<T: TapMessageBody + Send + Sync + std::fmt::Debug + 'static>(
158 &self,
159 message: PlainMessage<T>,
160 deliver: bool,
161 ) -> Result<(String, Vec<DeliveryResult>)> {
162 let plain_message = message.to_plain_message()?;
164 let to_vec: Vec<&str> = plain_message.to.iter().map(|s| s.as_str()).collect();
165
166 let body = serde_json::from_value::<T>(plain_message.body)?;
168 self.send_message(&body, to_vec, deliver).await
169 }
170
171 async fn send_with_context<T>(
184 &self,
185 message: &T,
186 deliver: bool,
187 ) -> Result<(String, Vec<DeliveryResult>)>
188 where
189 T: TapMessageBody
190 + tap_msg::message::MessageContext
191 + Send
192 + Sync
193 + std::fmt::Debug
194 + 'static,
195 {
196 let participant_dids = message.participant_dids();
198 let recipients: Vec<&str> = participant_dids
199 .iter()
200 .map(|s| s.as_str())
201 .filter(|&did| did != self.get_agent_did()) .collect();
203
204 let _routing_hints = message.routing_hints();
206
207 self.send_message(message, recipients, deliver).await
210 }
211
212 async fn send_typed_with_context<T>(
222 &self,
223 message: PlainMessage<T>,
224 deliver: bool,
225 ) -> Result<(String, Vec<DeliveryResult>)>
226 where
227 T: TapMessageBody
228 + tap_msg::message::MessageContext
229 + Send
230 + Sync
231 + std::fmt::Debug
232 + 'static,
233 {
234 let participants = message.extract_participants_with_context();
236 let _recipients: Vec<&str> = participants
237 .iter()
238 .map(|s| s.as_str())
239 .filter(|&did| did != self.get_agent_did()) .collect();
241
242 let _routing_hints = message.routing_hints();
244
245 let body = message.body;
247 self.send_with_context(&body, deliver).await
248 }
249
250 async fn receive_typed<T: TapMessageBody>(&self, raw_message: &str) -> Result<PlainMessage<T>> {
261 let plain_message = self.receive_message(raw_message).await?;
262 plain_message
263 .parse_as()
264 .map_err(|e| Error::Serialization(e.to_string()))
265 }
266
267 async fn create_oob_invitation<T: TapMessageBody + serde::Serialize + Send + Sync>(
278 &self,
279 message: &T,
280 goal_code: &str,
281 goal: &str,
282 service_url: &str,
283 ) -> Result<String>;
284
285 async fn create_payment_link(
294 &self,
295 payment: &tap_msg::message::Payment,
296 config: Option<crate::payment_link::PaymentLinkConfig>,
297 ) -> Result<String>;
298
299 fn parse_oob_invitation(&self, url: &str) -> Result<crate::oob::OutOfBandInvitation>;
307
308 async fn process_oob_invitation(
316 &self,
317 oob_invitation: &crate::oob::OutOfBandInvitation,
318 ) -> Result<PlainMessage>;
319}
320
321#[cfg(target_arch = "wasm32")]
323pub trait WasmAgent {
324 fn get_agent_did(&self) -> &str;
326
327 fn pack_message<T: TapMessageBody + serde::Serialize>(&self, message: &T) -> Result<String>;
329
330 fn unpack_message<T: TapMessageBody + DeserializeOwned>(
332 &self,
333 packed_message: &str,
334 ) -> Result<T>;
335}
336
337#[derive(Debug, Clone)]
339pub struct TapAgent {
340 pub config: AgentConfig,
342 key_manager: Arc<AgentKeyManager>,
344 #[cfg(all(not(target_arch = "wasm32"), test))]
346 resolver: Option<Arc<dyn SyncDIDResolver>>,
347 #[cfg(all(feature = "native", not(target_arch = "wasm32")))]
349 http_client: Option<Client>,
350}
351
352impl TapAgent {
353 pub fn key_manager(&self) -> &Arc<AgentKeyManager> {
355 &self.key_manager
356 }
357
358 pub fn new(config: AgentConfig, key_manager: Arc<AgentKeyManager>) -> Self {
360 #[cfg(all(feature = "native", not(target_arch = "wasm32")))]
361 {
362 let timeout = Duration::from_secs(config.timeout_seconds.unwrap_or(30));
363 let client = Client::builder().timeout(timeout).build().ok();
364
365 #[cfg(test)]
366 let agent = TapAgent {
367 config,
368 key_manager,
369 resolver: None,
370 http_client: client,
371 };
372
373 #[cfg(not(test))]
374 let agent = TapAgent {
375 config,
376 key_manager,
377 http_client: client,
378 };
379
380 agent
381 }
382
383 #[cfg(not(all(feature = "native", not(target_arch = "wasm32"))))]
384 {
385 #[cfg(all(not(target_arch = "wasm32"), test))]
386 let agent = TapAgent {
387 config,
388 key_manager,
389 resolver: None,
390 };
391
392 #[cfg(all(not(target_arch = "wasm32"), not(test)))]
393 let agent = TapAgent {
394 config,
395 key_manager,
396 };
397
398 #[cfg(target_arch = "wasm32")]
399 let agent = TapAgent {
400 config,
401 key_manager,
402 };
403
404 agent
405 }
406 }
407
408 #[cfg(all(not(target_arch = "wasm32"), test))]
410 pub fn new_with_resolver(
411 config: AgentConfig,
412 key_manager: Arc<AgentKeyManager>,
413 resolver: Arc<dyn SyncDIDResolver>,
414 ) -> Self {
415 #[cfg(feature = "native")]
416 {
417 let timeout = Duration::from_secs(config.timeout_seconds.unwrap_or(30));
418 let client = Client::builder().timeout(timeout).build().ok();
419
420 TapAgent {
421 config,
422 key_manager,
423 resolver: Some(resolver),
424 http_client: client,
425 }
426 }
427
428 #[cfg(not(feature = "native"))]
429 {
430 TapAgent {
431 config,
432 key_manager,
433 resolver: Some(resolver),
434 }
435 }
436 }
437
438 pub async fn from_ephemeral_key() -> crate::error::Result<(Self, String)> {
447 use crate::did::{DIDGenerationOptions, KeyType};
448
449 let key_manager = AgentKeyManager::new();
451
452 let key = key_manager.generate_key(DIDGenerationOptions {
454 key_type: KeyType::Ed25519,
455 })?;
456
457 let config = AgentConfig::new(key.did.clone()).with_debug(true);
459
460 #[cfg(all(not(target_arch = "wasm32"), test))]
462 {
463 let resolver = Arc::new(crate::did::MultiResolver::default());
465 let agent = Self::new_with_resolver(config, Arc::new(key_manager), resolver);
466 Ok((agent, key.did))
467 }
468
469 #[cfg(all(not(target_arch = "wasm32"), not(test)))]
470 {
471 let agent = Self::new(config, Arc::new(key_manager));
472 Ok((agent, key.did))
473 }
474
475 #[cfg(target_arch = "wasm32")]
476 {
477 let agent = Self::new(config, Arc::new(key_manager));
478 Ok((agent, key.did))
479 }
480 }
481
482 pub async fn from_stored_keys(did: Option<String>, debug: bool) -> Result<Self> {
495 use crate::storage::KeyStorage;
496
497 let key_manager_builder = AgentKeyManagerBuilder::new().load_from_default_storage();
499 let key_manager = key_manager_builder.build()?;
500
501 let dids = key_manager.list_keys()?;
503 if dids.is_empty() {
504 return Err(Error::Storage(
505 "No keys found in storage. Generate keys first with 'tap-agent-cli generate --save'".to_string(),
506 ));
507 }
508
509 let agent_did = if let Some(specified_did) = did {
511 if !dids.contains(&specified_did) {
512 return Err(Error::Storage(format!(
513 "Key with DID '{}' not found in storage",
514 specified_did
515 )));
516 }
517 specified_did
518 } else {
519 let storage = KeyStorage::load_default()?;
521 storage.default_did.unwrap_or_else(|| dids[0].clone())
522 };
523
524 let config = AgentConfig::new(agent_did).with_debug(debug);
526
527 #[cfg(all(not(target_arch = "wasm32"), test))]
529 {
530 let resolver = Arc::new(crate::did::MultiResolver::default());
532 Ok(TapAgent::new_with_resolver(
533 config,
534 Arc::new(key_manager),
535 resolver,
536 ))
537 }
538
539 #[cfg(all(not(target_arch = "wasm32"), not(test)))]
540 {
541 Ok(TapAgent::new(config, Arc::new(key_manager)))
542 }
543
544 #[cfg(target_arch = "wasm32")]
545 {
546 Ok(TapAgent::new(config, Arc::new(key_manager)))
547 }
548 }
549
550 #[cfg(not(target_arch = "wasm32"))]
561 pub async fn from_secret_helper(
562 config: &crate::secret_helper::SecretHelperConfig,
563 did: &str,
564 debug: bool,
565 ) -> Result<(Self, String)> {
566 let (private_key, key_type) = config.get_key(did)?;
567 Self::from_private_key(&private_key, key_type, debug).await
568 }
569
570 pub async fn from_private_key(
586 private_key: &[u8],
587 key_type: crate::did::KeyType,
588 debug: bool,
589 ) -> Result<(Self, String)> {
590 use crate::did::{DIDKeyGenerator, GeneratedKey};
591 use crate::did::{VerificationMaterial, VerificationMethod, VerificationMethodType};
592 #[cfg(feature = "crypto-ed25519")]
593 use curve25519_dalek::edwards::CompressedEdwardsY;
594 use multibase::{encode, Base};
595
596 let key_manager = AgentKeyManager::new();
598
599 let generated_key = match key_type {
601 #[cfg(feature = "crypto-ed25519")]
602 crate::did::KeyType::Ed25519 => {
603 if private_key.len() != 32 {
604 return Err(Error::Validation(format!(
605 "Invalid Ed25519 private key length: {}, expected 32 bytes",
606 private_key.len()
607 )));
608 }
609
610 let mut private_key_bytes = [0u8; 32];
612 private_key_bytes.copy_from_slice(&private_key[0..32]);
613
614 let signing_key = ed25519_dalek::SigningKey::from_bytes(&private_key_bytes);
615
616 let verifying_key = ed25519_dalek::VerifyingKey::from(&signing_key);
618 let public_key = verifying_key.to_bytes().to_vec();
619
620 let mut prefixed_key = vec![0xed, 0x01];
623 prefixed_key.extend_from_slice(&public_key);
624
625 let multibase_encoded = encode(Base::Base58Btc, &prefixed_key);
627 let did = format!("did:key:{}", multibase_encoded);
628
629 let vm_id = format!("{}#{}", did, multibase_encoded);
631
632 let verification_method = VerificationMethod {
634 id: vm_id.clone(),
635 type_: VerificationMethodType::Ed25519VerificationKey2018,
636 controller: did.clone(),
637 verification_material: VerificationMaterial::Multibase {
638 public_key_multibase: multibase_encoded.clone(),
639 },
640 };
641
642 let x25519_method_and_agreement = {
644 if public_key.len() != 32 {
646 None
647 } else {
648 let edwards_y = match CompressedEdwardsY::from_slice(&public_key) {
650 Ok(point) => point,
651 Err(_) => {
652 return Err(Error::Cryptography(
653 "Failed to create Edwards point".to_string(),
654 ))
655 }
656 };
657
658 let edwards_point = match edwards_y.decompress() {
660 Some(point) => point,
661 None => {
662 return Err(Error::Cryptography(
663 "Failed to decompress Edwards point".to_string(),
664 ))
665 }
666 };
667
668 let montgomery_point = edwards_point.to_montgomery();
670
671 let x25519_key = montgomery_point.to_bytes();
673
674 let mut x25519_prefixed = vec![0xEC, 0x01];
676 x25519_prefixed.extend_from_slice(&x25519_key);
677
678 let x25519_multibase = encode(Base::Base58Btc, &x25519_prefixed);
680
681 let x25519_vm_id = format!("{}#{}", did, x25519_multibase);
683
684 let x25519_verification_method = VerificationMethod {
686 id: x25519_vm_id.clone(),
687 type_: VerificationMethodType::X25519KeyAgreementKey2019,
688 controller: did.clone(),
689 verification_material: VerificationMaterial::Multibase {
690 public_key_multibase: x25519_multibase,
691 },
692 };
693
694 Some((x25519_verification_method, x25519_vm_id))
695 }
696 };
697
698 let mut verification_methods = vec![verification_method.clone()];
700 let mut key_agreement = Vec::new();
701
702 if let Some((x25519_vm, x25519_id)) = x25519_method_and_agreement {
703 verification_methods.push(x25519_vm);
704 key_agreement.push(x25519_id);
705 }
706
707 let did_doc = crate::did::DIDDoc {
709 id: did.clone(),
710 verification_method: verification_methods,
711 authentication: vec![vm_id],
712 key_agreement,
713 assertion_method: Vec::new(),
714 capability_invocation: Vec::new(),
715 capability_delegation: Vec::new(),
716 service: Vec::new(),
717 };
718
719 GeneratedKey {
721 key_type: crate::did::KeyType::Ed25519,
722 did: did.clone(),
723 public_key,
724 private_key: private_key.to_vec(),
725 did_doc,
726 }
727 }
728 #[cfg(feature = "crypto-p256")]
729 crate::did::KeyType::P256 => {
730 if private_key.len() != 32 {
731 return Err(Error::Validation(format!(
732 "Invalid P-256 private key length: {}, expected 32 bytes",
733 private_key.len()
734 )));
735 }
736
737 let signing_key = match p256::ecdsa::SigningKey::from_slice(private_key) {
739 Ok(key) => key,
740 Err(e) => {
741 return Err(Error::Cryptography(format!(
742 "Failed to create P-256 signing key: {:?}",
743 e
744 )))
745 }
746 };
747
748 let public_key = signing_key
750 .verifying_key()
751 .to_encoded_point(false)
752 .to_bytes()
753 .to_vec();
754
755 let mut prefixed_key = vec![0x12, 0x00];
758 prefixed_key.extend_from_slice(&public_key);
759
760 let multibase_encoded = encode(Base::Base58Btc, &prefixed_key);
762 let did = format!("did:key:{}", multibase_encoded);
763
764 let vm_id = format!("{}#{}", did, multibase_encoded);
766
767 let verification_method = VerificationMethod {
769 id: vm_id.clone(),
770 type_: VerificationMethodType::EcdsaSecp256k1VerificationKey2019, controller: did.clone(),
772 verification_material: VerificationMaterial::Multibase {
773 public_key_multibase: multibase_encoded.clone(),
774 },
775 };
776
777 let did_doc = crate::did::DIDDoc {
779 id: did.clone(),
780 verification_method: vec![verification_method],
781 authentication: vec![vm_id],
782 key_agreement: Vec::new(),
783 assertion_method: Vec::new(),
784 capability_invocation: Vec::new(),
785 capability_delegation: Vec::new(),
786 service: Vec::new(),
787 };
788
789 GeneratedKey {
791 key_type: crate::did::KeyType::P256,
792 did: did.clone(),
793 public_key,
794 private_key: private_key.to_vec(),
795 did_doc,
796 }
797 }
798 #[cfg(feature = "crypto-secp256k1")]
799 crate::did::KeyType::Secp256k1 => {
800 if private_key.len() != 32 {
801 return Err(Error::Validation(format!(
802 "Invalid Secp256k1 private key length: {}, expected 32 bytes",
803 private_key.len()
804 )));
805 }
806
807 let signing_key = match k256::ecdsa::SigningKey::from_slice(private_key) {
809 Ok(key) => key,
810 Err(e) => {
811 return Err(Error::Cryptography(format!(
812 "Failed to create Secp256k1 signing key: {:?}",
813 e
814 )))
815 }
816 };
817
818 let public_key = signing_key
820 .verifying_key()
821 .to_encoded_point(false)
822 .to_bytes()
823 .to_vec();
824
825 let mut prefixed_key = vec![0xe7, 0x01];
828 prefixed_key.extend_from_slice(&public_key);
829
830 let multibase_encoded = encode(Base::Base58Btc, &prefixed_key);
832 let did = format!("did:key:{}", multibase_encoded);
833
834 let vm_id = format!("{}#{}", did, multibase_encoded);
836
837 let verification_method = VerificationMethod {
839 id: vm_id.clone(),
840 type_: VerificationMethodType::EcdsaSecp256k1VerificationKey2019,
841 controller: did.clone(),
842 verification_material: VerificationMaterial::Multibase {
843 public_key_multibase: multibase_encoded.clone(),
844 },
845 };
846
847 let did_doc = crate::did::DIDDoc {
849 id: did.clone(),
850 verification_method: vec![verification_method],
851 authentication: vec![vm_id],
852 key_agreement: Vec::new(),
853 assertion_method: Vec::new(),
854 capability_invocation: Vec::new(),
855 capability_delegation: Vec::new(),
856 service: Vec::new(),
857 };
858
859 GeneratedKey {
861 key_type: crate::did::KeyType::Secp256k1,
862 did: did.clone(),
863 public_key,
864 private_key: private_key.to_vec(),
865 did_doc,
866 }
867 }
868 };
869
870 let did_generator = DIDKeyGenerator::new();
872 let _secret = did_generator.create_secret_from_key(&generated_key);
873
874 key_manager.add_key(&generated_key)?;
876
877 let config = AgentConfig::new(generated_key.did.clone()).with_debug(debug);
879
880 #[cfg(all(not(target_arch = "wasm32"), test))]
882 {
883 let resolver = Arc::new(crate::did::MultiResolver::default());
885 let agent = Self::new_with_resolver(config, Arc::new(key_manager), resolver);
886 Ok((agent, generated_key.did))
887 }
888
889 #[cfg(all(not(target_arch = "wasm32"), not(test)))]
890 {
891 let agent = Self::new(config, Arc::new(key_manager));
892 Ok((agent, generated_key.did))
893 }
894
895 #[cfg(target_arch = "wasm32")]
896 {
897 let agent = Self::new(config, Arc::new(key_manager));
898 Ok((agent, generated_key.did))
899 }
900 }
901
902 #[cfg(not(target_arch = "wasm32"))]
917 fn determine_security_mode<T: TapMessageBody>(&self) -> SecurityMode {
918 if let Some(ref mode) = self.config.security_mode {
920 match mode.to_uppercase().as_str() {
921 "AUTHCRYPT" => return SecurityMode::AuthCrypt,
922 "ANONCRYPT" => return SecurityMode::AnonCrypt,
923 _ => return SecurityMode::Signed,
924 }
925 }
926
927 let message_type = T::message_type();
929 if message_type == crate::message::PRESENTATION_MESSAGE_TYPE {
930 SecurityMode::AuthCrypt
931 } else {
932 SecurityMode::Signed
933 }
934 }
935
936 pub async fn get_signing_kid(&self) -> Result<String> {
940 let did = &self.config.agent_did;
941
942 if let Ok(agent_key) = self.key_manager.get_generated_key(did) {
944 if let Some(auth_method_id) = agent_key.did_doc.authentication.first() {
946 return Ok(auth_method_id.clone());
947 }
948
949 if let Some(vm) = agent_key.did_doc.verification_method.first() {
951 return Ok(vm.id.clone());
952 }
953 }
954
955 if did.starts_with("did:key:") {
957 let multibase = did.strip_prefix("did:key:").unwrap_or("");
958 Ok(format!("{}#{}", did, multibase))
959 } else if did.starts_with("did:web:") {
960 Ok(format!("{}#keys-1", did))
961 } else {
962 Ok(format!("{}#key-1", did))
963 }
964 }
965
966 pub async fn get_encryption_kid(&self, recipient_did: &str) -> Result<String> {
970 if recipient_did == self.config.agent_did {
971 if let Ok(agent_key) = self.key_manager.get_generated_key(recipient_did) {
973 if let Some(agreement_method_id) = agent_key.did_doc.key_agreement.first() {
975 return Ok(agreement_method_id.clone());
976 }
977
978 if let Some(auth_method_id) = agent_key.did_doc.authentication.first() {
980 return Ok(auth_method_id.clone());
981 }
982
983 if let Some(vm) = agent_key.did_doc.verification_method.first() {
985 return Ok(vm.id.clone());
986 }
987 }
988
989 return self.get_signing_kid().await;
991 }
992
993 #[cfg(all(not(target_arch = "wasm32"), test))]
995 if let Some(resolver) = &self.resolver {
996 if let Ok(Some(did_doc)) = resolver.resolve(recipient_did).await {
997 if let Some(agreement_method_id) = did_doc.key_agreement.first() {
999 return Ok(agreement_method_id.clone());
1000 }
1001
1002 if let Some(auth_method_id) = did_doc.authentication.first() {
1004 return Ok(auth_method_id.clone());
1005 }
1006
1007 if let Some(vm) = did_doc.verification_method.first() {
1009 return Ok(vm.id.clone());
1010 }
1011 }
1012 }
1013
1014 if recipient_did.starts_with("did:key:") {
1016 let multibase = recipient_did.strip_prefix("did:key:").unwrap_or("");
1017 Ok(format!("{}#{}", recipient_did, multibase))
1018 } else if recipient_did.starts_with("did:web:") {
1019 Ok(format!("{}#keys-1", recipient_did))
1020 } else {
1021 Ok(format!("{}#key-1", recipient_did))
1022 }
1023 }
1024
1025 #[cfg(all(feature = "native", not(target_arch = "wasm32")))]
1034 pub async fn send_to_endpoint(&self, packed_message: &str, endpoint: &str) -> Result<u16> {
1035 let client = self
1037 .http_client
1038 .as_ref()
1039 .ok_or_else(|| Error::Networking("HTTP client not available".to_string()))?;
1040
1041 let response = client
1043 .post(endpoint)
1044 .header("Content-Type", "application/didcomm-encrypted+json")
1045 .body(packed_message.to_string())
1046 .send()
1047 .await
1048 .map_err(|e| Error::Networking(format!("Failed to send message to endpoint: {}", e)))?;
1049
1050 let status = response.status().as_u16();
1052
1053 debug!("Message sent to endpoint {}, status: {}", endpoint, status);
1055
1056 Ok(status)
1057 }
1058
1059 #[cfg(any(not(feature = "native"), target_arch = "wasm32"))]
1060 pub async fn send_to_endpoint(&self, _packed_message: &str, _endpoint: &str) -> Result<u16> {
1061 Err(crate::error::Error::NotImplemented(
1063 "HTTP client not available".to_string(),
1064 ))
1065 }
1066
1067 pub async fn create_enhanced_agent(
1069 agent_id: String,
1070 policies: Vec<String>,
1071 metadata: std::collections::HashMap<String, String>,
1072 save_to_storage: bool,
1073 ) -> Result<(Self, String)> {
1074 Self::create_enhanced_agent_with_path(agent_id, policies, metadata, save_to_storage, None)
1075 .await
1076 }
1077
1078 pub async fn create_enhanced_agent_with_path(
1080 agent_id: String,
1081 policies: Vec<String>,
1082 metadata: std::collections::HashMap<String, String>,
1083 save_to_storage: bool,
1084 storage_path: Option<PathBuf>,
1085 ) -> Result<(Self, String)> {
1086 use crate::did::{DIDGenerationOptions, KeyType};
1087 use crate::storage::KeyStorage;
1088
1089 let key_manager = AgentKeyManager::new();
1091 let generated_key = key_manager.generate_key_without_save(DIDGenerationOptions {
1092 key_type: KeyType::Ed25519,
1093 })?;
1094
1095 let config = AgentConfig::new(agent_id.clone()).with_debug(true);
1097
1098 let mut custom_generated_key = generated_key.clone();
1101 custom_generated_key.did = agent_id.clone();
1102 key_manager.add_key_without_save(&custom_generated_key)?;
1103
1104 #[cfg(all(not(target_arch = "wasm32"), test))]
1106 let agent = {
1107 let resolver = Arc::new(crate::did::MultiResolver::default());
1108 Self::new_with_resolver(config, Arc::new(key_manager), resolver)
1109 };
1110
1111 #[cfg(all(not(target_arch = "wasm32"), not(test)))]
1112 let agent = Self::new(config, Arc::new(key_manager));
1113
1114 #[cfg(target_arch = "wasm32")]
1115 let agent = Self::new(config, Arc::new(key_manager));
1116
1117 if save_to_storage {
1118 let mut key_storage = if let Some(path) = &storage_path {
1120 KeyStorage::load_from_path(path)?
1121 } else {
1122 KeyStorage::load_default()?
1123 };
1124
1125 let mut stored_key = KeyStorage::from_generated_key(&custom_generated_key);
1127 stored_key.label = format!(
1128 "agent-{}",
1129 agent_id.split(':').next_back().unwrap_or("agent")
1130 );
1131
1132 key_storage.add_key(stored_key);
1133
1134 if let Some(path) = &storage_path {
1135 key_storage.save_to_path(path)?;
1136 } else {
1137 key_storage.save_default()?;
1138 }
1139
1140 key_storage.create_agent_directory(&agent_id, &policies, &metadata)?;
1142 }
1143
1144 Ok((agent, agent_id))
1145 }
1146
1147 pub async fn load_enhanced_agent(
1149 did: &str,
1150 ) -> Result<(Self, Vec<String>, std::collections::HashMap<String, String>)> {
1151 use crate::storage::KeyStorage;
1152
1153 let key_storage = KeyStorage::load_default()?;
1155
1156 let agent = if key_storage.keys.contains_key(did) {
1158 Self::from_stored_keys(Some(did.to_string()), true).await?
1160 } else {
1161 let (mut agent, _) = Self::from_ephemeral_key().await?;
1164 agent.config.agent_did = did.to_string();
1165 agent
1166 };
1167
1168 let policies = key_storage.load_agent_policies(did).unwrap_or_default();
1170 let metadata = key_storage.load_agent_metadata(did).unwrap_or_default();
1171
1172 Ok((agent, policies, metadata))
1173 }
1174
1175 pub fn list_enhanced_agents() -> Result<Vec<EnhancedAgentInfo>> {
1177 Self::list_enhanced_agents_with_path(None)
1178 }
1179
1180 pub fn list_enhanced_agents_with_path(
1182 storage_path: Option<PathBuf>,
1183 ) -> Result<Vec<EnhancedAgentInfo>> {
1184 use crate::storage::KeyStorage;
1185 use std::fs;
1186
1187 let key_storage = if let Some(path) = &storage_path {
1188 KeyStorage::load_from_path(path)?
1189 } else {
1190 KeyStorage::load_default()?
1191 };
1192 let mut agents = Vec::new();
1193
1194 let tap_dir = if let Some(path) = &storage_path {
1196 path.parent()
1198 .ok_or_else(|| Error::Storage("Invalid storage path".to_string()))?
1199 .to_path_buf()
1200 } else {
1201 let home = dirs::home_dir()
1202 .ok_or_else(|| Error::Storage("Could not determine home directory".to_string()))?;
1203 home.join(crate::storage::DEFAULT_TAP_DIR)
1204 };
1205
1206 if !tap_dir.exists() {
1207 return Ok(agents);
1208 }
1209
1210 for entry in fs::read_dir(&tap_dir)? {
1212 let entry = entry?;
1213 let path = entry.path();
1214
1215 if path.is_dir() {
1216 let dir_name = path.file_name().and_then(|n| n.to_str()).unwrap_or("");
1217
1218 if dir_name == "keys.json" || dir_name.is_empty() {
1220 continue;
1221 }
1222
1223 let did = dir_name.replace('_', ":");
1225
1226 let policies = key_storage.load_agent_policies(&did).unwrap_or_default();
1228 let metadata = key_storage.load_agent_metadata(&did).unwrap_or_default();
1229
1230 if !policies.is_empty() || !metadata.is_empty() {
1232 agents.push((did, policies, metadata));
1233 }
1234 }
1235 }
1236
1237 Ok(agents)
1238 }
1239}
1240
1241#[async_trait]
1242#[cfg(not(target_arch = "wasm32"))]
1243impl crate::agent::Agent for TapAgent {
1244 fn get_agent_did(&self) -> &str {
1245 &self.config.agent_did
1246 }
1247
1248 async fn get_service_endpoint(&self, to: &str) -> Result<Option<String>> {
1249 if to.starts_with("http://") || to.starts_with("https://") {
1251 return Ok(Some(to.to_string()));
1252 }
1253
1254 if to.starts_with("did:") {
1256 #[cfg(test)]
1261 if let Some(resolver) = self.resolver.as_ref() {
1262 if let Ok(Some(did_doc)) = resolver.resolve(to).await {
1263 if let Some(service) = did_doc
1265 .service
1266 .iter()
1267 .find(|s| s.type_ == "DIDCommMessaging")
1268 {
1269 return Ok(Some(service.service_endpoint.clone()));
1270 }
1271
1272 if let Some(service) = did_doc.service.iter().find(|s| s.type_ == "Web") {
1274 return Ok(Some(service.service_endpoint.clone()));
1275 }
1276
1277 if !did_doc.service.is_empty() {
1279 return Ok(Some(did_doc.service[0].service_endpoint.clone()));
1281 }
1282 }
1283 }
1284
1285 return Ok(Some(format!(
1287 "https://example.com/did/{}",
1288 to.replace(":", "_")
1289 )));
1290 }
1291
1292 Ok(None)
1294 }
1295
1296 async fn send_message<
1297 T: TapMessageBody + serde::Serialize + Send + Sync + std::fmt::Debug + 'static,
1298 >(
1299 &self,
1300 message: &T,
1301 to: Vec<&str>,
1302 deliver: bool,
1303 ) -> Result<(String, Vec<DeliveryResult>)> {
1304 if to.is_empty() {
1305 return Err(Error::Validation("No recipients specified".to_string()));
1306 }
1307
1308 debug!("\n==== SENDING TAP MESSAGE ====");
1310 debug!("Message Type: {}", T::message_type());
1311 debug!("Recipients: {:?}", to);
1312
1313 let plain_message =
1315 message.to_didcomm_with_route(self.get_agent_did(), to.iter().copied())?;
1316
1317 let security_mode = self.determine_security_mode::<T>();
1319 debug!("Security Mode: {:?}", security_mode);
1320
1321 for recipient in &to {
1323 if let Ok(Some(endpoint)) = self.get_service_endpoint(recipient).await {
1324 debug!("Found service endpoint for {}: {}", recipient, endpoint);
1325 }
1326 }
1327
1328 let sender_kid = self.get_signing_kid().await?;
1330 let recipient_kid = if to.len() == 1
1331 && (security_mode == SecurityMode::AuthCrypt
1332 || security_mode == SecurityMode::AnonCrypt)
1333 {
1334 Some(self.get_encryption_kid(to[0]).await?)
1335 } else {
1336 None
1337 };
1338
1339 let pack_options = PackOptions {
1341 security_mode,
1342 sender_kid: if security_mode == SecurityMode::AnonCrypt {
1343 None
1344 } else {
1345 Some(sender_kid)
1346 },
1347 recipient_kid,
1348 };
1349
1350 let packed = plain_message.pack(&*self.key_manager, pack_options).await?;
1352
1353 debug!("--- PACKED MESSAGE ---");
1355 debug!(
1356 "{}",
1357 serde_json::from_str::<serde_json::Value>(&packed)
1358 .map(|v| serde_json::to_string_pretty(&v).unwrap_or(packed.clone()))
1359 .unwrap_or(packed.clone())
1360 );
1361 debug!("=====================");
1362
1363 if !deliver {
1365 return Ok((packed, Vec::new()));
1366 }
1367
1368 let mut delivery_results = Vec::new();
1370
1371 for recipient in &to {
1372 match self.get_service_endpoint(recipient).await {
1373 Ok(Some(endpoint)) => {
1374 debug!("Delivering message to {} at {}", recipient, endpoint);
1375
1376 let message_id = match serde_json::from_str::<Value>(&packed) {
1378 Ok(json) => json
1379 .get("id")
1380 .and_then(|id| id.as_str())
1381 .map(String::from)
1382 .unwrap_or_else(|| "unknown".to_string()),
1383 Err(_) => "unknown".to_string(),
1384 };
1385
1386 match self.send_to_endpoint(&packed, &endpoint).await {
1388 Ok(status) => {
1389 info!(
1390 "✅ Delivered message {} to {} at {}",
1391 message_id, recipient, endpoint
1392 );
1393
1394 delivery_results.push(DeliveryResult {
1395 did: recipient.to_string(),
1396 endpoint: endpoint.clone(),
1397 status: Some(status),
1398 error: None,
1399 });
1400 }
1401 Err(e) => {
1402 let error_msg = format!(
1404 "Failed to deliver message {} to {} at {}: {}",
1405 message_id, recipient, endpoint, e
1406 );
1407 error!("❌ {}", error_msg);
1408
1409 delivery_results.push(DeliveryResult {
1410 did: recipient.to_string(),
1411 endpoint: endpoint.clone(),
1412 status: None,
1413 error: Some(error_msg),
1414 });
1415 }
1416 }
1417 }
1418 Ok(None) => {
1419 warn!(
1420 "⚠️ No service endpoint found for {}, skipping delivery",
1421 recipient
1422 );
1423 }
1424 Err(e) => {
1425 let error_msg = format!(
1427 "Failed to resolve service endpoint for {}: {}",
1428 recipient, e
1429 );
1430 error!("❌ {}", error_msg);
1431 }
1432 }
1433 }
1434
1435 Ok((packed, delivery_results))
1436 }
1437
1438 async fn receive_encrypted_message(&self, jwe_value: &Value) -> Result<()> {
1439 debug!("\n==== RECEIVING ENCRYPTED MESSAGE ====");
1441 debug!("Agent DID: {}", self.get_agent_did());
1442
1443 let jwe: crate::message::Jwe = serde_json::from_value(jwe_value.clone())
1445 .map_err(|e| Error::Serialization(format!("Failed to parse JWE: {}", e)))?;
1446
1447 let our_kid = self.get_signing_kid().await.ok();
1449
1450 let unpack_options = UnpackOptions {
1452 expected_security_mode: SecurityMode::Any,
1453 expected_recipient_kid: our_kid,
1454 require_signature: false,
1455 };
1456
1457 let plain_message: PlainMessage<Value> =
1459 crate::message::Jwe::unpack(&jwe, &*self.key_manager, unpack_options).await?;
1460
1461 debug!(
1462 "Processed encrypted message: {} of type {}",
1463 plain_message.id, plain_message.type_
1464 );
1465 Ok(())
1466 }
1467
1468 async fn receive_plain_message(&self, message: PlainMessage) -> Result<()> {
1469 debug!("\n==== RECEIVING PLAIN MESSAGE ====");
1471 debug!("Message ID: {}", message.id);
1472 debug!("Message Type: {}", message.type_);
1473
1474 Ok(())
1475 }
1476
1477 async fn receive_message(&self, raw_message: &str) -> Result<PlainMessage> {
1478 debug!("\n==== RECEIVING RAW MESSAGE ====");
1480 debug!("Agent DID: {}", self.get_agent_did());
1481
1482 let json_value: Value = serde_json::from_str(raw_message)
1484 .map_err(|e| Error::Serialization(format!("Failed to parse message as JSON: {}", e)))?;
1485
1486 let is_encrypted =
1488 json_value.get("protected").is_some() && json_value.get("recipients").is_some();
1489 let is_signed = json_value.get("payload").is_some()
1490 && (json_value.get("signatures").is_some() || json_value.get("signature").is_some());
1491
1492 debug!(
1493 "Message type detection: encrypted={}, signed={}",
1494 is_encrypted, is_signed
1495 );
1496
1497 if is_signed {
1498 debug!("Detected signed message");
1499 debug!("--- SIGNED MESSAGE ---");
1500 debug!(
1501 "{}",
1502 serde_json::to_string_pretty(&json_value).unwrap_or(raw_message.to_string())
1503 );
1504 debug!("---------------------");
1505
1506 let jws: crate::message::Jws = serde_json::from_value(json_value)
1508 .map_err(|e| Error::Serialization(format!("Failed to parse JWS: {}", e)))?;
1509
1510 #[cfg(test)]
1512 let plain_message = if let Some(resolver) = &self.resolver {
1513 crate::verification::verify_jws(&jws, &**resolver).await?
1514 } else {
1515 let unpack_options = UnpackOptions {
1517 expected_security_mode: SecurityMode::Signed,
1518 expected_recipient_kid: None,
1519 require_signature: true,
1520 };
1521 crate::message::Jws::unpack(&jws, &*self.key_manager, unpack_options).await?
1522 };
1523
1524 #[cfg(not(test))]
1525 let plain_message = {
1526 let unpack_options = UnpackOptions {
1528 expected_security_mode: SecurityMode::Signed,
1529 expected_recipient_kid: None,
1530 require_signature: true,
1531 };
1532 crate::message::Jws::unpack(&jws, &*self.key_manager, unpack_options).await?
1533 };
1534
1535 debug!("--- UNPACKED CONTENT ---");
1537 debug!(
1538 "{}",
1539 serde_json::to_string_pretty(&plain_message)
1540 .unwrap_or_else(|_| format!("{:?}", plain_message))
1541 );
1542 debug!("------------------------");
1543
1544 Ok(plain_message)
1545 } else if is_encrypted {
1546 debug!("Detected encrypted message");
1547 debug!("--- ENCRYPTED MESSAGE ---");
1548 debug!(
1549 "{}",
1550 serde_json::to_string_pretty(&json_value).unwrap_or(raw_message.to_string())
1551 );
1552 debug!("---------------------");
1553
1554 let our_kid = self.get_signing_kid().await.ok();
1556
1557 let unpack_options = UnpackOptions {
1559 expected_security_mode: SecurityMode::Any,
1560 expected_recipient_kid: our_kid,
1561 require_signature: false,
1562 };
1563
1564 debug!("Unpacking with options: {:?}", unpack_options);
1565
1566 let plain_message: PlainMessage =
1568 match String::unpack(&raw_message.to_string(), &*self.key_manager, unpack_options)
1569 .await
1570 {
1571 Ok(msg) => msg,
1572 Err(e) => {
1573 error!("Failed to unpack message: {}", e);
1574 return Err(e);
1575 }
1576 };
1577
1578 debug!("--- UNPACKED CONTENT ---");
1580 debug!(
1581 "{}",
1582 serde_json::to_string_pretty(&plain_message)
1583 .unwrap_or_else(|_| format!("{:?}", plain_message))
1584 );
1585 debug!("------------------------");
1586
1587 Ok(plain_message)
1588 } else {
1589 debug!("Detected plain message");
1591 debug!("--- PLAIN MESSAGE ---");
1592 debug!(
1593 "{}",
1594 serde_json::to_string_pretty(&json_value).unwrap_or(raw_message.to_string())
1595 );
1596 debug!("---------------------");
1597
1598 serde_json::from_str::<PlainMessage>(raw_message)
1600 .map_err(|e| Error::Serialization(format!("Failed to parse PlainMessage: {}", e)))
1601 }
1602 }
1603
1604 async fn create_oob_invitation<T: TapMessageBody + serde::Serialize + Send + Sync>(
1605 &self,
1606 message: &T,
1607 goal_code: &str,
1608 goal: &str,
1609 service_url: &str,
1610 ) -> Result<String> {
1611 let plain_message = message.to_didcomm(self.get_agent_did())?;
1613
1614 let _message_json = serde_json::to_string(&plain_message)
1616 .map_err(|e| Error::Serialization(format!("Failed to serialize message: {}", e)))?;
1617
1618 let sender_kid = self.get_signing_kid().await?;
1620 let pack_options = crate::message_packing::PackOptions::new().with_sign(&sender_kid);
1621 let signed_message = plain_message.pack(&*self.key_manager, pack_options).await?;
1622
1623 let oob_invitation =
1625 crate::oob::OutOfBandInvitation::builder(self.get_agent_did(), goal_code, goal)
1626 .add_signed_attachment("tap-message", &signed_message, Some("Signed TAP message"))
1627 .build();
1628
1629 oob_invitation.to_url(service_url)
1631 }
1632
1633 async fn create_payment_link(
1634 &self,
1635 payment: &tap_msg::message::Payment,
1636 config: Option<crate::payment_link::PaymentLinkConfig>,
1637 ) -> Result<String> {
1638 let config = config.unwrap_or_default();
1639
1640 let key_manager = self.key_manager.clone();
1642 let agent_did = self.get_agent_did().to_string();
1643
1644 let sign_fn = move |message_json: String| {
1645 let key_manager = key_manager.clone();
1646 let agent_did = agent_did.clone();
1647
1648 async move {
1649 let plain_message: PlainMessage =
1651 serde_json::from_str(&message_json).map_err(|e| {
1652 Error::Serialization(format!("Failed to parse message for signing: {}", e))
1653 })?;
1654
1655 let temp_config = AgentConfig::new(agent_did.clone());
1657 let temp_agent = TapAgent::new(temp_config, key_manager.clone());
1658 let sender_kid = temp_agent.get_signing_kid().await?;
1659
1660 let pack_options =
1661 crate::message_packing::PackOptions::new().with_sign(&sender_kid);
1662 plain_message.pack(&*key_manager, pack_options).await
1663 }
1664 };
1665
1666 let payment_link =
1668 crate::payment_link::PaymentLink::builder(self.get_agent_did(), payment.clone())
1669 .with_config(config)
1670 .build_with_signer(sign_fn)
1671 .await?;
1672
1673 Ok(payment_link.url)
1674 }
1675
1676 fn parse_oob_invitation(&self, url: &str) -> Result<crate::oob::OutOfBandInvitation> {
1677 crate::oob::OutOfBandInvitation::from_url(url)
1678 }
1679
1680 async fn process_oob_invitation(
1681 &self,
1682 oob_invitation: &crate::oob::OutOfBandInvitation,
1683 ) -> Result<PlainMessage> {
1684 oob_invitation.validate()?;
1686
1687 let attachment = oob_invitation.get_signed_attachment().ok_or_else(|| {
1689 Error::Validation("No signed attachment found in OOB invitation".to_string())
1690 })?;
1691
1692 let signed_message_json = match &attachment.data {
1694 tap_msg::didcomm::AttachmentData::Json { value } => &value.json,
1695 _ => {
1696 return Err(Error::Validation(
1697 "Attachment does not contain JSON data".to_string(),
1698 ))
1699 }
1700 };
1701
1702 let signed_message_str = serde_json::to_string(signed_message_json).map_err(|e| {
1704 Error::Serialization(format!("Failed to serialize signed message: {}", e))
1705 })?;
1706
1707 self.receive_message(&signed_message_str).await
1709 }
1710}