1use auths_keri::Capability;
2use base64::{Engine, engine::general_purpose::URL_SAFE_NO_PAD};
3use serde::{Deserialize, Serialize};
4
5#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
7#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
8#[serde(transparent)]
9pub struct Base64UrlEncoded(String);
10
11impl Base64UrlEncoded {
12 pub fn from_raw(s: String) -> Self {
13 Self(s)
14 }
15
16 pub fn encode(bytes: &[u8]) -> Self {
17 Self(URL_SAFE_NO_PAD.encode(bytes))
18 }
19
20 pub fn decode(&self) -> Result<Vec<u8>, base64::DecodeError> {
21 URL_SAFE_NO_PAD.decode(&self.0)
22 }
23
24 pub fn as_str(&self) -> &str {
25 &self.0
26 }
27}
28
29impl std::ops::Deref for Base64UrlEncoded {
30 type Target = str;
31 fn deref(&self) -> &str {
32 &self.0
33 }
34}
35
36impl std::fmt::Display for Base64UrlEncoded {
37 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
38 f.write_str(&self.0)
39 }
40}
41
42#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
44#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
45#[serde(rename_all = "lowercase")]
46pub enum SessionStatus {
47 Pending,
48 Responded,
49 Confirmed,
50 Aborted,
51 Completed,
52 Cancelled,
53 Expired,
54}
55
56#[derive(Debug, Clone, Serialize, Deserialize)]
62#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
63pub struct CreateSessionRequest {
64 pub session_id: String,
65 pub controller_did: String,
66 pub ephemeral_pubkey: Base64UrlEncoded,
67 pub short_code: String,
68 #[serde(default)]
69 pub capabilities: Vec<Capability>,
70 pub expires_at: i64,
71 #[serde(default, skip_serializing_if = "Option::is_none")]
76 pub recovery_target: Option<String>,
77}
78
79#[derive(Debug, Serialize, Deserialize)]
81#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
82pub struct CreateSessionResponse {
83 pub session_id: String,
84 pub status: SessionStatus,
85 pub short_code: String,
86 pub uri: String,
87 pub ttl_seconds: u64,
88}
89
90#[derive(Debug, Clone, Serialize, Deserialize)]
92#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
93pub struct SubmitResponseRequest {
94 pub device_ephemeral_pubkey: Base64UrlEncoded,
95 pub device_signing_pubkey: Base64UrlEncoded,
96 #[serde(default)]
100 pub curve: crate::response::CurveTag,
101 pub device_did: String,
103 pub signature: Base64UrlEncoded,
104 #[serde(skip_serializing_if = "Option::is_none")]
105 pub device_name: Option<String>,
106 #[serde(default, skip_serializing_if = "Option::is_none")]
115 pub subkey_chain: Option<crate::subkey_chain::SubkeyChain>,
116 #[serde(default)]
125 pub initiator_inception_event: String,
126 #[serde(default)]
128 pub responder_inception_event: String,
129 #[serde(default, skip_serializing_if = "Option::is_none")]
135 pub shared_kel_inception_event: Option<String>,
136}
137
138pub const SHARED_KEL_INCEPTION_EVENT_MAX_BYTES: usize = 1024;
144
145impl SubmitResponseRequest {
146 pub fn validate(&self) -> Result<(), String> {
159 if let Some(ref inc) = self.shared_kel_inception_event
160 && inc.len() > SHARED_KEL_INCEPTION_EVENT_MAX_BYTES
161 {
162 return Err(format!(
163 "shared_kel_inception_event is {} bytes, exceeds cap of {} — multi-sig KEL inception would overflow QR capacity",
164 inc.len(),
165 SHARED_KEL_INCEPTION_EVENT_MAX_BYTES,
166 ));
167 }
168 Ok(())
169 }
170}
171
172#[derive(Debug, Serialize, Deserialize)]
174#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
175pub struct GetSessionResponse {
176 pub session_id: String,
177 pub status: SessionStatus,
178 pub ttl_seconds: u64,
179 #[serde(skip_serializing_if = "Option::is_none")]
180 pub token: Option<CreateSessionRequest>,
181 #[serde(skip_serializing_if = "Option::is_none")]
182 pub response: Option<SubmitResponseRequest>,
183}
184
185#[derive(Debug, Serialize, Deserialize)]
187#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
188pub struct SuccessResponse {
189 pub success: bool,
190 pub message: String,
191}
192
193#[derive(Debug, Clone, Serialize, Deserialize)]
195#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
196pub struct SubmitConfirmationRequest {
197 #[serde(skip_serializing_if = "Option::is_none")]
198 pub encrypted_attestation: Option<String>,
199 #[serde(default)]
200 pub aborted: bool,
201}
202
203#[derive(Debug, Serialize, Deserialize)]
205#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
206pub struct GetConfirmationResponse {
207 #[serde(skip_serializing_if = "Option::is_none")]
208 pub encrypted_attestation: Option<String>,
209 #[serde(default)]
210 pub aborted: bool,
211}