vta_cli_common/commands/
vault.rs1use serde_json::{Value, json};
15use vta_sdk::client::VtaClient;
16
17use crate::render::{DIM, RESET, is_json_output, print_json};
18
19fn print_result(label: &str, value: &Value) -> Result<(), Box<dyn std::error::Error>> {
20 if is_json_output() {
21 print_json(value)?;
22 } else {
23 println!("{label}");
24 println!("{}", serde_json::to_string_pretty(value)?);
25 }
26 Ok(())
27}
28
29pub async fn cmd_vault_list(
34 client: &VtaClient,
35 filters: Option<Value>,
36 status: Option<String>,
37) -> Result<(), Box<dyn std::error::Error>> {
38 let mut filters = filters.unwrap_or_else(|| json!({}));
39 if let Some(s) = status
40 && let Some(obj) = filters.as_object_mut()
41 {
42 obj.insert("status".to_string(), json!(s));
43 }
44 let result = client.vault_list(filters).await?;
45 print_result("Vault entries:", &result)
46}
47
48pub async fn cmd_vault_get(
50 client: &VtaClient,
51 id: String,
52) -> Result<(), Box<dyn std::error::Error>> {
53 let result = client.vault_get(&id).await?;
54 print_result("Vault entry:", &result)
55}
56
57pub async fn cmd_vault_delete(
60 client: &VtaClient,
61 id: String,
62 expected_version: Option<u32>,
63 force: bool,
64 reason: Option<String>,
65) -> Result<(), Box<dyn std::error::Error>> {
66 let result = client
67 .vault_delete(&id, expected_version, force, reason.as_deref())
68 .await?;
69 if force {
70 println!("{DIM}Vault entry {id} permanently hard-deleted (no recovery).{RESET}");
71 } else {
72 let grace = result.get("graceUntil").and_then(Value::as_str);
73 match grace {
74 Some(g) => println!(
75 "{DIM}Vault entry {id} moved to trash — recoverable with `vault restore {id}` until {g}.{RESET}"
76 ),
77 None => println!(
78 "{DIM}Vault entry {id} soft-deleted — recoverable with `vault restore {id}`.{RESET}"
79 ),
80 }
81 }
82 print_result("Result:", &result)
83}
84
85pub async fn cmd_vault_archive(
87 client: &VtaClient,
88 id: String,
89 expected_version: Option<u32>,
90 reason: Option<String>,
91) -> Result<(), Box<dyn std::error::Error>> {
92 let result = client
93 .vault_archive(&id, expected_version, reason.as_deref())
94 .await?;
95 println!("{DIM}Vault entry {id} archived — restore with `vault unarchive {id}`.{RESET}");
96 print_result("Result:", &result)
97}
98
99pub async fn cmd_vault_unarchive(
101 client: &VtaClient,
102 id: String,
103 expected_version: Option<u32>,
104 reason: Option<String>,
105) -> Result<(), Box<dyn std::error::Error>> {
106 let result = client
107 .vault_unarchive(&id, expected_version, reason.as_deref())
108 .await?;
109 println!("{DIM}Vault entry {id} unarchived.{RESET}");
110 print_result("Result:", &result)
111}
112
113pub async fn cmd_vault_restore(
116 client: &VtaClient,
117 id: String,
118 expected_version: Option<u32>,
119 reason: Option<String>,
120) -> Result<(), Box<dyn std::error::Error>> {
121 let result = client
122 .vault_restore(&id, expected_version, reason.as_deref())
123 .await?;
124 println!("{DIM}Vault entry {id} restored to active.{RESET}");
125 print_result("Result:", &result)
126}
127
128pub async fn cmd_vault_purge(
131 client: &VtaClient,
132 id: String,
133 expected_version: Option<u32>,
134 reason: Option<String>,
135) -> Result<(), Box<dyn std::error::Error>> {
136 let result = client
137 .vault_purge(&id, expected_version, reason.as_deref())
138 .await?;
139 println!("{DIM}Vault entry {id} permanently purged (no recovery).{RESET}");
140 print_result("Result:", &result)
141}
142
143pub async fn cmd_vault_upsert(
149 client: &VtaClient,
150 entry: Value,
151 secret: Option<Value>,
152) -> Result<(), Box<dyn std::error::Error>> {
153 let sealed_secret = match secret {
154 Some(s) => {
155 let jwe = client.seal_vault_secret(s).await?;
156 Some(json!({ "envelope": "didcomm-authcrypt", "jwe": jwe }))
157 }
158 None => None,
159 };
160 let result = client.vault_upsert(entry, sealed_secret).await?;
161 print_result("Upserted entry:", &result)
162}
163
164pub async fn cmd_vault_release(
168 client: &VtaClient,
169 id: String,
170 target: Option<Value>,
171) -> Result<(), Box<dyn std::error::Error>> {
172 let mut payload = json!({ "id": id });
173 if let Some(t) = target {
174 payload["target"] = t;
175 }
176 let response = client.vault_release(payload).await?;
177
178 let jwe = response
183 .get("sealedSecret")
184 .and_then(|s| s.get("jwe"))
185 .and_then(|j| j.as_str());
186 match jwe {
187 Some(jwe) => {
188 let secret = client.open_sealed_secret(jwe).await?;
189 print_result("Released secret (cleartext):", &secret)
190 }
191 None => {
192 eprintln!("{DIM}(no didcomm-authcrypt sealedSecret in response — printing raw){RESET}");
193 print_result("Release response:", &response)
194 }
195 }
196}
197
198pub async fn cmd_vault_proxy_login(
201 client: &VtaClient,
202 payload: Value,
203) -> Result<(), Box<dyn std::error::Error>> {
204 let result = client.vault_proxy_login(payload).await?;
205 print_result("Proxy-login result:", &result)
206}
207
208pub async fn cmd_vault_sign_trust_task(
211 client: &VtaClient,
212 payload: Value,
213) -> Result<(), Box<dyn std::error::Error>> {
214 let result = client.vault_sign_trust_task(payload).await?;
215 print_result("Signed envelope:", &result)
216}