1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
//! Convenience methods for paginating + bundling key secrets via [`VtaClient`].
use super::VtaClient;
use crate::error::VtaError;
impl VtaClient {
/// Fetch all secrets for a context, paginating through all keys.
///
/// Returns TDK `Secret` objects ready for use with DIDComm or signing.
pub async fn fetch_context_secrets(
&self,
context_id: &str,
) -> Result<Vec<affinidi_tdk::secrets_resolver::secrets::Secret>, VtaError> {
let page_size = 100u64;
let mut offset = 0u64;
let mut secrets = Vec::new();
loop {
let resp = self
.list_keys(offset, page_size, Some("active"), Some(context_id))
.await?;
if resp.keys.is_empty() {
break;
}
for key in &resp.keys {
let secret_resp = self.get_key_secret(&key.key_id).await?;
let secret = crate::did_key::secret_from_key_response(&secret_resp)?;
secrets.push(secret);
}
offset += resp.keys.len() as u64;
if offset >= resp.total {
break;
}
}
Ok(secrets)
}
/// Fetch all secrets for a context as a portable
/// [`DidSecretsBundle`](crate::did_secrets::DidSecretsBundle).
///
/// Resolves the context DID, paginates through all active keys,
/// fetches each secret, and returns a bundle ready for encoding/transport.
pub async fn fetch_did_secrets_bundle(
&self,
context_id: &str,
) -> Result<crate::did_secrets::DidSecretsBundle, VtaError> {
let ctx = self.get_context(context_id).await?;
let did = ctx.did.ok_or_else(|| {
VtaError::Validation(format!("context '{context_id}' has no DID assigned"))
})?;
let page_size = 100u64;
let mut offset = 0u64;
let mut secrets = Vec::new();
loop {
let resp = self
.list_keys(offset, page_size, Some("active"), Some(context_id))
.await?;
if resp.keys.is_empty() {
break;
}
for key in &resp.keys {
let secret_resp = self.get_key_secret(&key.key_id).await?;
let mut entry = crate::did_secrets::SecretEntry::from(secret_resp);
// Use the key's label as the secret ID when it looks like a DID
// verification method ID (e.g., "did:webvh:...#key-0"). The setup
// wizard and provisioning flows set labels to match the DID document,
// so this lets consumers use the bundle directly without remapping.
if let Some(label) = key.label.as_deref()
&& (label.contains('#') || label.starts_with("did:"))
{
entry.key_id = label.to_string();
}
secrets.push(entry);
}
offset += resp.keys.len() as u64;
if offset >= resp.total {
break;
}
}
Ok(crate::did_secrets::DidSecretsBundle { did, secrets })
}
}