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
//! Seeds slice trust-task handlers.
//!
//! Auth: **super-admin** for list/rotate. Seed state is instance-wide
//! (FTL-29904). The gate lives in `operations::seeds`, not here, so REST, Trust
//! Task and DIDComm share one audited refusal. There is deliberately no role
//! pre-check in this file: a role-only check (`require_admin`) is exactly the
//! defect that let a context-scoped admin rotate the seed.
//!
//! The per-key secret export that used to live here has moved to
//! `keys/export-secret/0.1`, in the family it belongs to. It was never a
//! mnemonic or a seed export — no task in this slice releases either, and seed
//! material leaves only through `vta/backup/*`.
use super::helpers::TrustTaskOutcome;
use serde_json::Value;
use trust_tasks_rs::TrustTask;
use vta_sdk::protocols::seed_management::list::ListSeedsBody;
use vta_sdk::protocols::seed_management::rotate::RotateSeedBody;
use crate::auth::AuthClaims;
use crate::operations;
use crate::server::AppState;
use super::helpers::{TRANSPORT_TRUST_TASK, app_error_to_reject, parse_payload, success_response};
/// Handler for `spec/vta/seeds/list/1.0`. Super-admin only (gated in the operation).
pub(super) async fn handle_list(
state: &AppState,
auth: &AuthClaims,
doc: TrustTask<Value>,
) -> TrustTaskOutcome {
let _req: ListSeedsBody = match parse_payload(&doc) {
Ok(r) => r,
Err(resp) => return resp,
};
match operations::seeds::list_seeds(
&state.keys_ks,
auth,
&state.audit_sink,
TRANSPORT_TRUST_TASK,
)
.await
{
Ok(body) => success_response(&doc, body),
Err(e) => app_error_to_reject(&doc, e),
}
}
/// Handler for `spec/vta/seeds/rotate/1.0`. Super-admin only (gated in the operation).
pub(super) async fn handle_rotate(
state: &AppState,
auth: &AuthClaims,
doc: TrustTask<Value>,
) -> TrustTaskOutcome {
let req: RotateSeedBody = match parse_payload(&doc) {
Ok(r) => r,
Err(resp) => return resp,
};
match operations::seeds::rotate_seed(
&state.keys_ks,
&state.imported_ks,
&state.seed_store,
&state.audit_sink,
auth,
req.mnemonic.as_deref(),
TRANSPORT_TRUST_TASK,
)
.await
{
Ok(body) => success_response(&doc, body),
Err(e) => app_error_to_reject(&doc, e),
}
}