models.rs (8401B)
1 use serde::{Deserialize, Serialize}; 2 use uuid::Uuid; 3 use std::collections::HashMap; 4 use axum::{ 5 response::{IntoResponse, Response}, 6 http::{StatusCode, header}, 7 }; 8 9 pub struct PrettyJson<T>(pub T); 10 11 impl<T> IntoResponse for PrettyJson<T> 12 where 13 T: Serialize, 14 { 15 fn into_response(self) -> Response { 16 match serde_json::to_string_pretty(&self.0) { 17 Ok(json) => ( 18 StatusCode::OK, 19 [(header::CONTENT_TYPE, "application/json")], 20 json, 21 ).into_response(), 22 Err(e) => ( 23 StatusCode::INTERNAL_SERVER_ERROR, 24 format!("Serialization error: {}", e), 25 ).into_response(), 26 } 27 } 28 } 29 30 #[derive(Debug, Deserialize, Serialize)] 31 pub struct SetupResponse { 32 pub nonce: String, 33 } 34 35 #[derive(Debug, Deserialize)] 36 pub struct AuthorizeQuery { 37 pub response_type: String, 38 pub client_id: String, 39 pub redirect_uri: String, 40 pub state: String, 41 pub scope: String, 42 } 43 44 #[derive(Debug, Deserialize, Serialize)] 45 pub struct AuthorizeResponse { 46 #[serde(rename = "verificationId")] 47 pub verification_id: Uuid, 48 pub verification_url: String, 49 #[serde(skip_serializing_if = "Option::is_none")] 50 pub verification_deeplink: Option<String>, 51 pub state: String, 52 } 53 54 #[derive(Debug, Deserialize, Serialize)] 55 pub struct TokenRequest { 56 pub grant_type: String, 57 pub code: String, 58 pub client_id: String, 59 pub client_secret: String, 60 pub redirect_uri: String, 61 } 62 63 #[derive(Debug, Deserialize, Serialize)] 64 pub struct TokenResponse { 65 pub access_token: String, 66 pub token_type: String, 67 pub expires_in: u64, 68 } 69 70 // Info endpoint 71 #[derive(Debug, Deserialize, Serialize, Clone)] 72 pub struct VerifiableCredential { 73 #[serde(flatten)] 74 pub data: serde_json::Value, 75 } 76 77 // Notification webhook from Swiyu Verifier 78 #[derive(Debug, Deserialize, Serialize)] 79 pub struct NotificationRequest { 80 pub verification_id: Uuid, 81 pub timestamp: String, 82 } 83 84 // Status endpoint 85 #[derive(Debug, Deserialize)] 86 pub struct StatusQuery { 87 pub state: String, 88 } 89 90 #[derive(Debug, Serialize)] 91 pub struct StatusResponse { 92 pub status: String, 93 } 94 95 #[derive(Debug, Serialize)] 96 pub struct ConfigResponse { 97 pub name: String, 98 pub version: String, 99 pub status: String, 100 pub vc_type: String, 101 pub vc_format: String, 102 pub vc_algorithms: Vec<String>, 103 pub vc_claims: Vec<String>, 104 } 105 106 // Notification payload sent to Client (Exchange, etc.) 107 #[derive(Debug, Serialize)] 108 pub struct ClientNotification { 109 pub nonce: String, 110 pub status: String, 111 pub code: String, 112 pub verification_id: Uuid, 113 pub timestamp: String, 114 } 115 116 // Error response 117 #[derive(Debug, Serialize, Deserialize)] 118 pub struct ErrorResponse { 119 pub error: String, 120 } 121 122 impl ErrorResponse { 123 pub fn new(error: impl Into<String>) -> Self { 124 Self { 125 error: error.into(), 126 } 127 } 128 } 129 130 // Swiyu Verifier API models 131 132 /// Request body for creating a verification with Swiyu Verifier 133 /// POST /management/api/verifications 134 #[derive(Debug, Serialize, Deserialize)] 135 pub struct SwiyuCreateVerificationRequest { 136 pub accepted_issuer_dids: Vec<String>, 137 #[serde(skip_serializing_if = "Option::is_none")] 138 pub trust_anchors: Option<Vec<TrustAnchor>>, 139 140 /// If omitted, Swiyu defaults to true (beta requires true) 141 #[serde(skip_serializing_if = "Option::is_none")] 142 pub jwt_secured_authorization_request: Option<bool>, 143 144 /// Response mode: how the wallet sends the response back 145 /// REQUIRED - will throw NullPointerException if omitted 146 pub response_mode: ResponseMode, 147 148 /// Response type - must be "vp_token" for VP requests 149 pub response_type: String, 150 151 pub presentation_definition: PresentationDefinition, 152 153 pub configuration_override: ConfigurationOverride, 154 155 /// Optional - (wallet migration in progress) 156 #[serde(skip_serializing_if = "Option::is_none")] 157 pub dcql_query: Option<serde_json::Value>, 158 } 159 160 /// Trust anchor for credential verification 161 #[derive(Debug, Serialize, Deserialize, Clone)] 162 pub struct TrustAnchor { 163 pub did: String, 164 pub trust_registry_uri: String, 165 } 166 167 /// Response mode type 168 #[derive(Debug, Serialize, Deserialize, Clone)] 169 #[serde(rename_all = "snake_case")] 170 pub enum ResponseMode { 171 /// Wallet sends a clear text response 172 DirectPost, 173 174 /// Wallet sends an encrypted response 175 #[serde(rename = "direct_post.jwt")] 176 DirectPostJwt, 177 } 178 179 /// Configuration override for a specific verification 180 /// Can be empty object with all fields set to None 181 #[derive(Debug, Serialize, Deserialize, Clone, Default)] 182 pub struct ConfigurationOverride { 183 /// Override for the EXTERNAL_URL - the url the wallet should call 184 #[serde(skip_serializing_if = "Option::is_none")] 185 pub external_url: Option<String>, 186 187 #[serde(skip_serializing_if = "Option::is_none")] 188 pub verifier_did: Option<String>, 189 190 #[serde(skip_serializing_if = "Option::is_none")] 191 pub verification_method: Option<String>, 192 193 /// ID of the key in the HSM 194 #[serde(skip_serializing_if = "Option::is_none")] 195 pub key_id: Option<String>, 196 197 /// The pin which protects the key in the HSM 198 #[serde(skip_serializing_if = "Option::is_none")] 199 pub key_pin: Option<String>, 200 } 201 202 /// Presentation Definition according to DIF Presentation Exchange 203 #[derive(Debug, Serialize, Deserialize, Clone)] 204 pub struct PresentationDefinition { 205 pub id: String, 206 #[serde(skip_serializing_if = "Option::is_none")] 207 pub name: Option<String>, 208 #[serde(skip_serializing_if = "Option::is_none")] 209 pub purpose: Option<String>, 210 #[serde(skip_serializing_if = "Option::is_none")] 211 pub format: Option<HashMap<String, FormatAlgorithm>>, 212 pub input_descriptors: Vec<InputDescriptor>, 213 } 214 215 /// Input descriptor describing required credential attributes 216 #[derive(Debug, Serialize, Deserialize, Clone)] 217 pub struct InputDescriptor { 218 pub id: String, 219 #[serde(skip_serializing_if = "Option::is_none")] 220 pub name: Option<String>, 221 #[serde(skip_serializing_if = "Option::is_none")] 222 pub purpose: Option<String>, 223 #[serde(skip_serializing_if = "Option::is_none")] 224 pub format: Option<HashMap<String, FormatAlgorithm>>, 225 pub constraints: Constraint, 226 } 227 228 /// Constraints on credential fields 229 #[derive(Debug, Serialize, Deserialize, Clone)] 230 pub struct Constraint { 231 pub fields: Vec<Field>, 232 } 233 234 /// Field specification with JSONPath 235 #[derive(Debug, Serialize, Deserialize, Clone)] 236 pub struct Field { 237 pub path: Vec<String>, 238 #[serde(skip_serializing_if = "Option::is_none")] 239 pub id: Option<String>, 240 #[serde(skip_serializing_if = "Option::is_none")] 241 pub name: Option<String>, 242 #[serde(skip_serializing_if = "Option::is_none")] 243 pub purpose: Option<String>, 244 #[serde(skip_serializing_if = "Option::is_none")] 245 pub filter: Option<Filter>, 246 } 247 248 /// Filter for field constraints 249 #[derive(Debug, Serialize, Deserialize, Clone)] 250 pub struct Filter { 251 #[serde(rename = "type")] 252 pub filter_type: String, 253 #[serde(rename = "const", skip_serializing_if = "Option::is_none")] 254 pub const_value: Option<String>, 255 } 256 257 /// Format algorithm specification for SD-JWT 258 #[derive(Debug, Serialize, Deserialize, Clone)] 259 pub struct FormatAlgorithm { 260 #[serde(rename = "sd-jwt_alg_values")] 261 pub sd_jwt_alg_values: Vec<String>, 262 #[serde(rename = "kb-jwt_alg_values")] 263 pub kb_jwt_alg_values: Vec<String>, 264 } 265 266 /// Response from Swiyu Verifier Management API 267 /// Used for both POST /management/api/verifications and GET /management/api/verifications/{id} 268 #[derive(Debug, Serialize, Deserialize)] 269 pub struct SwiyuManagementResponse { 270 pub id: Uuid, 271 #[serde(skip_serializing_if = "Option::is_none")] 272 pub request_nonce: Option<String>, 273 pub state: SwiyuVerificationStatus, 274 pub verification_url: String, 275 #[serde(skip_serializing_if = "Option::is_none")] 276 pub verification_deeplink: Option<String>, 277 pub presentation_definition: PresentationDefinition, 278 #[serde(skip_serializing_if = "Option::is_none")] 279 pub dcql_query: Option<serde_json::Value>, 280 #[serde(skip_serializing_if = "Option::is_none")] 281 pub wallet_response: Option<serde_json::Value>, 282 } 283 284 #[derive(Debug, Serialize, Deserialize, Clone, PartialEq)] 285 #[serde(rename_all = "UPPERCASE")] 286 pub enum SwiyuVerificationStatus { 287 Pending, 288 Success, 289 Failed, 290 }