kych

OAuth 2.0 API for Swiyu to enable Taler integration of Swiyu for KYC (experimental)
Log | Files | Refs | README

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 }