1use super::{Ap2Error, Result};
4use crate::ap2::credentials::VerificationMethod;
5use chrono::{DateTime, Utc};
6use serde::{Deserialize, Serialize};
7use std::collections::HashMap;
8
9#[derive(Debug, Clone, Serialize, Deserialize)]
11#[serde(rename_all = "camelCase")]
12pub struct DidDocument {
13 #[serde(rename = "@context")]
14 pub context: Vec<String>,
15 pub id: String,
16 #[serde(skip_serializing_if = "Option::is_none")]
17 pub controller: Option<Vec<String>>,
18 pub verification_method: Vec<VerificationMethod>,
19 #[serde(skip_serializing_if = "Option::is_none")]
20 pub authentication: Option<Vec<String>>,
21 #[serde(skip_serializing_if = "Option::is_none")]
22 pub assertion_method: Option<Vec<String>>,
23 #[serde(skip_serializing_if = "Option::is_none")]
24 pub key_agreement: Option<Vec<String>>,
25 #[serde(skip_serializing_if = "Option::is_none")]
26 pub capability_invocation: Option<Vec<String>>,
27 #[serde(skip_serializing_if = "Option::is_none")]
28 pub capability_delegation: Option<Vec<String>>,
29 #[serde(skip_serializing_if = "Option::is_none")]
30 pub service: Option<Vec<ServiceEndpoint>>,
31 #[serde(skip_serializing_if = "Option::is_none")]
32 pub created: Option<DateTime<Utc>>,
33 #[serde(skip_serializing_if = "Option::is_none")]
34 pub updated: Option<DateTime<Utc>>,
35}
36
37#[derive(Debug, Clone, Serialize, Deserialize)]
39#[serde(rename_all = "camelCase")]
40pub struct ServiceEndpoint {
41 pub id: String,
42 #[serde(rename = "type")]
43 pub service_type: String,
44 pub service_endpoint: String,
45 #[serde(skip_serializing_if = "Option::is_none")]
46 pub description: Option<String>,
47}
48
49impl DidDocument {
50 pub fn new(id: String, verification_method: VerificationMethod) -> Self {
52 let verification_method_id = verification_method.id.clone();
53
54 Self {
55 context: vec![
56 "https://www.w3.org/ns/did/v1".to_string(),
57 "https://w3id.org/security/suites/ed25519-2020/v1".to_string(),
58 ],
59 id,
60 controller: None,
61 verification_method: vec![verification_method],
62 authentication: Some(vec![verification_method_id.clone()]),
63 assertion_method: Some(vec![verification_method_id.clone()]),
64 key_agreement: None,
65 capability_invocation: Some(vec![verification_method_id.clone()]),
66 capability_delegation: None,
67 service: None,
68 created: Some(Utc::now()),
69 updated: None,
70 }
71 }
72
73 pub fn add_service(&mut self, service: ServiceEndpoint) {
75 if let Some(ref mut services) = self.service {
76 services.push(service);
77 } else {
78 self.service = Some(vec![service]);
79 }
80 self.updated = Some(Utc::now());
81 }
82
83 pub fn add_verification_method(&mut self, method: VerificationMethod) {
85 self.verification_method.push(method);
86 self.updated = Some(Utc::now());
87 }
88
89 pub fn get_verification_method(&self, id: &str) -> Option<&VerificationMethod> {
91 self.verification_method.iter().find(|m| m.id == id)
92 }
93
94 pub fn get_service_by_type(&self, service_type: &str) -> Option<&ServiceEndpoint> {
96 self.service
97 .as_ref()?
98 .iter()
99 .find(|s| s.service_type == service_type)
100 }
101}
102
103#[derive(Debug, Clone)]
105pub struct DidResolver {
106 cache: HashMap<String, DidDocument>,
107}
108
109impl DidResolver {
110 pub fn new() -> Self {
111 Self {
112 cache: HashMap::new(),
113 }
114 }
115
116 pub fn resolve(&self, did: &str) -> Result<DidDocument> {
118 if let Some(doc) = self.cache.get(did) {
120 return Ok(doc.clone());
121 }
122
123 Err(Ap2Error::DidResolutionFailed(format!(
126 "DID not found: {}",
127 did
128 )))
129 }
130
131 pub fn register(&mut self, did_doc: DidDocument) {
133 self.cache.insert(did_doc.id.clone(), did_doc);
134 }
135
136 pub fn exists(&self, did: &str) -> bool {
138 self.cache.contains_key(did)
139 }
140
141 pub fn deregister(&mut self, did: &str) -> bool {
143 self.cache.remove(did).is_some()
144 }
145
146 pub fn clear_cache(&mut self) {
148 self.cache.clear();
149 }
150}
151
152impl Default for DidResolver {
153 fn default() -> Self {
154 Self::new()
155 }
156}
157
158#[derive(Debug)]
160pub struct DidManager {
161 resolver: DidResolver,
162 method: String,
163}
164
165impl DidManager {
166 pub fn new() -> Self {
167 Self {
168 resolver: DidResolver::new(),
169 method: "ap2".to_string(),
170 }
171 }
172
173 pub fn with_method(mut self, method: String) -> Self {
174 self.method = method;
175 self
176 }
177
178 pub fn create_did(&mut self, identifier: &str, public_key: Vec<u8>) -> Result<String> {
180 let did = format!("did:{}:{}", self.method, identifier);
181
182 let verification_method = VerificationMethod {
183 id: format!("{}#key-1", did),
184 method_type: "Ed25519VerificationKey2020".to_string(),
185 controller: did.clone(),
186 public_key_multibase: base64_url::encode(&public_key),
187 };
188
189 let did_doc = DidDocument::new(did.clone(), verification_method);
190 self.resolver.register(did_doc);
191
192 Ok(did)
193 }
194
195 pub fn create_did_with_method(
197 &mut self,
198 identifier: &str,
199 verification_method: VerificationMethod,
200 ) -> Result<String> {
201 let did = format!("did:{}:{}", self.method, identifier);
202 let did_doc = DidDocument::new(did.clone(), verification_method);
203 self.resolver.register(did_doc);
204
205 Ok(did)
206 }
207
208 pub fn update_did(&mut self, did: &str, mut did_doc: DidDocument) -> Result<()> {
210 if !self.resolver.exists(did) {
211 return Err(Ap2Error::DidResolutionFailed(format!(
212 "DID not found: {}",
213 did
214 )));
215 }
216
217 did_doc.updated = Some(Utc::now());
218 self.resolver.register(did_doc);
219 Ok(())
220 }
221
222 pub fn get_did_document(&self, did: &str) -> Result<DidDocument> {
224 self.resolver.resolve(did)
225 }
226
227 pub fn add_service_to_did(&mut self, did: &str, service: ServiceEndpoint) -> Result<()> {
229 let mut did_doc = self.resolver.resolve(did)?;
230 did_doc.add_service(service);
231 self.resolver.register(did_doc);
232 Ok(())
233 }
234
235 pub fn deactivate_did(&mut self, did: &str) -> Result<()> {
237 if !self.resolver.deregister(did) {
238 return Err(Ap2Error::DidResolutionFailed(format!(
239 "DID not found: {}",
240 did
241 )));
242 }
243 Ok(())
244 }
245
246 pub fn resolver(&self) -> &DidResolver {
248 &self.resolver
249 }
250
251 pub fn resolver_mut(&mut self) -> &mut DidResolver {
253 &mut self.resolver
254 }
255}
256
257impl Default for DidManager {
258 fn default() -> Self {
259 Self::new()
260 }
261}
262
263pub struct DidUrlParser;
265
266impl DidUrlParser {
267 pub fn parse(did_url: &str) -> Result<DidUrlComponents> {
269 let parts: Vec<&str> = did_url.split(':').collect();
270
271 if parts.len() < 3 || parts[0] != "did" {
272 return Err(Ap2Error::InvalidCredential(format!(
273 "Invalid DID format: {}",
274 did_url
275 )));
276 }
277
278 let method = parts[1].to_string();
279 let method_specific_id = parts[2..].join(":");
280
281 let (identifier, fragment) = if let Some(pos) = method_specific_id.find('#') {
283 (
284 method_specific_id[..pos].to_string(),
285 Some(method_specific_id[pos + 1..].to_string()),
286 )
287 } else {
288 (method_specific_id, None)
289 };
290
291 Ok(DidUrlComponents {
292 did: format!("did:{}:{}", method, identifier),
293 method,
294 method_specific_id: identifier,
295 fragment,
296 query: None,
297 })
298 }
299}
300
301#[derive(Debug, Clone)]
303pub struct DidUrlComponents {
304 pub did: String,
305 pub method: String,
306 pub method_specific_id: String,
307 pub fragment: Option<String>,
308 pub query: Option<String>,
309}
310
311#[cfg(test)]
312mod tests {
313 use super::*;
314
315 #[test]
316 fn test_did_creation() {
317 let mut manager = DidManager::new();
318 let public_key = vec![1, 2, 3, 4];
319
320 let did = manager.create_did("test-agent", public_key);
321 assert!(did.is_ok());
322
323 let did_str = did.unwrap();
324 assert!(did_str.starts_with("did:ap2:"));
325 }
326
327 #[test]
328 fn test_did_resolution() {
329 let mut manager = DidManager::new();
330 let public_key = vec![1, 2, 3, 4];
331 let did = manager.create_did("test-agent", public_key).unwrap();
332
333 let did_doc = manager.get_did_document(&did);
334 assert!(did_doc.is_ok());
335
336 let doc = did_doc.unwrap();
337 assert_eq!(doc.id, did);
338 assert!(!doc.verification_method.is_empty());
339 }
340
341 #[test]
342 fn test_service_endpoint_addition() {
343 let mut manager = DidManager::new();
344 let public_key = vec![1, 2, 3, 4];
345 let did = manager.create_did("test-agent", public_key).unwrap();
346
347 let service = ServiceEndpoint {
348 id: format!("{}#payment-service", did),
349 service_type: "PaymentService".to_string(),
350 service_endpoint: "https://payment.example.com".to_string(),
351 description: Some("Agent payment endpoint".to_string()),
352 };
353
354 let result = manager.add_service_to_did(&did, service);
355 assert!(result.is_ok());
356
357 let did_doc = manager.get_did_document(&did).unwrap();
358 assert!(did_doc.service.is_some());
359 }
360
361 #[test]
362 fn test_did_url_parsing() {
363 let did_url = "did:ap2:agent123#key-1";
364 let components = DidUrlParser::parse(did_url).unwrap();
365
366 assert_eq!(components.method, "ap2");
367 assert_eq!(components.method_specific_id, "agent123");
368 assert_eq!(components.fragment, Some("key-1".to_string()));
369 }
370}