models.rs (8341B)
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 // Token endpoint 55 // WARING: RFC 6749 also requires: 56 // - redirect_uri 57 #[derive(Debug, Deserialize, Serialize)] 58 pub struct TokenRequest { 59 pub grant_type: String, 60 pub code: String, 61 pub client_id: String, 62 pub client_secret: String, 63 } 64 65 #[derive(Debug, Deserialize, Serialize)] 66 pub struct TokenResponse { 67 pub access_token: String, 68 pub token_type: String, 69 pub expires_in: u64, 70 } 71 72 // Info endpoint 73 #[derive(Debug, Deserialize, Serialize, Clone)] 74 pub struct VerifiableCredential { 75 #[serde(flatten)] 76 pub data: serde_json::Value, 77 } 78 79 // Notification webhook from Swiyu Verifier 80 #[derive(Debug, Deserialize, Serialize)] 81 pub struct NotificationRequest { 82 pub verification_id: Uuid, 83 pub timestamp: String, 84 } 85 86 // Notification payload sent to Client (Exchange, etc.) 87 #[derive(Debug, Serialize)] 88 pub struct ClientNotification { 89 pub nonce: String, 90 pub status: String, 91 pub code: String, 92 pub verification_id: Uuid, 93 pub timestamp: String, 94 } 95 96 // Error response 97 #[derive(Debug, Serialize, Deserialize)] 98 pub struct ErrorResponse { 99 pub error: String, 100 } 101 102 impl ErrorResponse { 103 pub fn new(error: impl Into<String>) -> Self { 104 Self { 105 error: error.into(), 106 } 107 } 108 } 109 110 // Swiyu Verifier API models 111 112 /// Default issuer DID for Swiyu verification 113 pub fn default_accepted_issuer_dids() -> Vec<String> { 114 vec!["did:tdw:QmPEZPhDFR4nEYSFK5bMnvECqdpf1tPTPJuWs9QrMjCumw:identifier-reg.trust-infra.swiyu-int.admin.ch:api:v1:did:9a5559f0-b81c-4368-a170-e7b4ae424527".to_string()] 115 } 116 117 /// Request body for creating a verification with Swiyu Verifier 118 /// POST /management/api/verifications 119 #[derive(Debug, Serialize, Deserialize)] 120 pub struct SwiyuCreateVerificationRequest { 121 #[serde(default = "default_accepted_issuer_dids")] 122 pub accepted_issuer_dids: Vec<String>, 123 #[serde(skip_serializing_if = "Option::is_none")] 124 pub trust_anchors: Option<Vec<TrustAnchor>>, 125 126 /// If omitted, Swiyu defaults to true (beta requires true) 127 #[serde(skip_serializing_if = "Option::is_none")] 128 pub jwt_secured_authorization_request: Option<bool>, 129 130 /// Response mode: how the wallet sends the response back 131 /// REQUIRED - will throw NullPointerException if omitted 132 pub response_mode: ResponseMode, 133 134 /// Response type - must be "vp_token" for VP requests 135 pub response_type: String, 136 137 pub presentation_definition: PresentationDefinition, 138 139 pub configuration_override: ConfigurationOverride, 140 141 /// Optional - (wallet migration in progress) 142 #[serde(skip_serializing_if = "Option::is_none")] 143 pub dcql_query: Option<serde_json::Value>, 144 } 145 146 /// Trust anchor for credential verification 147 #[derive(Debug, Serialize, Deserialize, Clone)] 148 pub struct TrustAnchor { 149 pub did: String, 150 pub trust_registry_uri: String, 151 } 152 153 /// Response mode type 154 #[derive(Debug, Serialize, Deserialize, Clone)] 155 #[serde(rename_all = "snake_case")] 156 pub enum ResponseMode { 157 /// Wallet sends a clear text response 158 DirectPost, 159 160 /// Wallet sends an encrypted response 161 #[serde(rename = "direct_post.jwt")] 162 DirectPostJwt, 163 } 164 165 /// Configuration override for a specific verification 166 /// Can be empty object with all fields set to None 167 #[derive(Debug, Serialize, Deserialize, Clone, Default)] 168 pub struct ConfigurationOverride { 169 /// Override for the EXTERNAL_URL - the url the wallet should call 170 #[serde(skip_serializing_if = "Option::is_none")] 171 pub external_url: Option<String>, 172 173 #[serde(skip_serializing_if = "Option::is_none")] 174 pub verifier_did: Option<String>, 175 176 #[serde(skip_serializing_if = "Option::is_none")] 177 pub verification_method: Option<String>, 178 179 /// ID of the key in the HSM 180 #[serde(skip_serializing_if = "Option::is_none")] 181 pub key_id: Option<String>, 182 183 /// The pin which protects the key in the HSM 184 #[serde(skip_serializing_if = "Option::is_none")] 185 pub key_pin: Option<String>, 186 } 187 188 /// Presentation Definition according to DIF Presentation Exchange 189 #[derive(Debug, Serialize, Deserialize, Clone)] 190 pub struct PresentationDefinition { 191 pub id: String, 192 #[serde(skip_serializing_if = "Option::is_none")] 193 pub name: Option<String>, 194 #[serde(skip_serializing_if = "Option::is_none")] 195 pub purpose: Option<String>, 196 #[serde(skip_serializing_if = "Option::is_none")] 197 pub format: Option<HashMap<String, FormatAlgorithm>>, 198 pub input_descriptors: Vec<InputDescriptor>, 199 } 200 201 /// Input descriptor describing required credential attributes 202 #[derive(Debug, Serialize, Deserialize, Clone)] 203 pub struct InputDescriptor { 204 pub id: String, 205 #[serde(skip_serializing_if = "Option::is_none")] 206 pub name: Option<String>, 207 #[serde(skip_serializing_if = "Option::is_none")] 208 pub purpose: Option<String>, 209 #[serde(skip_serializing_if = "Option::is_none")] 210 pub format: Option<HashMap<String, FormatAlgorithm>>, 211 pub constraints: Constraint, 212 } 213 214 /// Constraints on credential fields 215 #[derive(Debug, Serialize, Deserialize, Clone)] 216 pub struct Constraint { 217 pub fields: Vec<Field>, 218 } 219 220 /// Field specification with JSONPath 221 #[derive(Debug, Serialize, Deserialize, Clone)] 222 pub struct Field { 223 pub path: Vec<String>, 224 #[serde(skip_serializing_if = "Option::is_none")] 225 pub id: Option<String>, 226 #[serde(skip_serializing_if = "Option::is_none")] 227 pub name: Option<String>, 228 #[serde(skip_serializing_if = "Option::is_none")] 229 pub purpose: Option<String>, 230 #[serde(skip_serializing_if = "Option::is_none")] 231 pub filter: Option<Filter>, 232 } 233 234 /// Filter for field constraints 235 #[derive(Debug, Serialize, Deserialize, Clone)] 236 pub struct Filter { 237 #[serde(rename = "type")] 238 pub filter_type: String, 239 #[serde(rename = "const", skip_serializing_if = "Option::is_none")] 240 pub const_value: Option<String>, 241 } 242 243 /// Format algorithm specification for SD-JWT 244 #[derive(Debug, Serialize, Deserialize, Clone)] 245 pub struct FormatAlgorithm { 246 #[serde(rename = "sd-jwt_alg_values")] 247 pub sd_jwt_alg_values: Vec<String>, 248 #[serde(rename = "kb-jwt_alg_values")] 249 pub kb_jwt_alg_values: Vec<String>, 250 } 251 252 /// Response from Swiyu Verifier Management API 253 /// Used for both POST /management/api/verifications and GET /management/api/verifications/{id} 254 #[derive(Debug, Serialize, Deserialize)] 255 pub struct SwiyuManagementResponse { 256 pub id: Uuid, 257 #[serde(skip_serializing_if = "Option::is_none")] 258 pub request_nonce: Option<String>, 259 pub state: SwiyuVerificationStatus, 260 pub verification_url: String, 261 #[serde(skip_serializing_if = "Option::is_none")] 262 pub verification_deeplink: Option<String>, 263 pub presentation_definition: PresentationDefinition, 264 #[serde(skip_serializing_if = "Option::is_none")] 265 pub dcql_query: Option<serde_json::Value>, 266 #[serde(skip_serializing_if = "Option::is_none")] 267 pub wallet_response: Option<serde_json::Value>, 268 } 269 270 #[derive(Debug, Serialize, Deserialize, Clone, PartialEq)] 271 #[serde(rename_all = "UPPERCASE")] 272 pub enum SwiyuVerificationStatus { 273 Pending, 274 Success, 275 Failed, 276 }