exchange

Base system with REST service to issue digital coins, run by the payment service provider
Log | Files | Refs | Submodules | README | LICENSE

exchange_api_post-kyc-upload-ID.c (7693B)


      1 /*
      2   This file is part of TALER
      3   Copyright (C) 2024-2026 Taler Systems SA
      4 
      5   TALER is free software; you can redistribute it and/or modify it under the
      6   terms of the GNU General Public License as published by the Free Software
      7   Foundation; either version 3, or (at your option) any later version.
      8 
      9   TALER is distributed in the hope that it will be useful, but WITHOUT ANY
     10   WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
     11   A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
     12 
     13   You should have received a copy of the GNU General Public License along with
     14   TALER; see the file COPYING.  If not, see
     15   <http://www.gnu.org/licenses/>
     16 */
     17 /**
     18  * @file lib/exchange_api_post-kyc-upload-ID.c
     19  * @brief functions to upload client-provided KYC evidence
     20  * @author Christian Grothoff
     21  */
     22 #include "taler/taler_json_lib.h"
     23 #include <microhttpd.h>
     24 #include <gnunet/gnunet_curl_lib.h>
     25 #include "taler/exchange/post-kyc-upload-ID.h"
     26 #include "exchange_api_curl_defaults.h"
     27 #include "taler/taler_signatures.h"
     28 #include "taler/taler_curl_lib.h"
     29 
     30 
     31 struct TALER_EXCHANGE_PostKycUploadHandle
     32 {
     33 
     34   /**
     35    * The base URL for this request.
     36    */
     37   char *base_url;
     38 
     39   /**
     40    * The full URL for this request.
     41    */
     42   char *url;
     43 
     44   /**
     45    * Minor context that holds body and headers.
     46    */
     47   struct TALER_CURL_PostContext post_ctx;
     48 
     49   /**
     50    * Handle for the request.
     51    */
     52   struct GNUNET_CURL_Job *job;
     53 
     54   /**
     55    * Function to call with the result.
     56    */
     57   TALER_EXCHANGE_PostKycUploadCallback cb;
     58 
     59   /**
     60    * Closure for @e cb.
     61    */
     62   TALER_EXCHANGE_POST_KYC_UPLOAD_RESULT_CLOSURE *cb_cls;
     63 
     64   /**
     65    * Reference to the execution context.
     66    */
     67   struct GNUNET_CURL_Context *ctx;
     68 
     69   /**
     70    * Identifier for the KYC process the upload is for.
     71    */
     72   char *id;
     73 
     74   /**
     75    * Client-provided evidence to upload (`CustomerKycAttributes`).
     76    */
     77   json_t *attributes;
     78 
     79 };
     80 
     81 
     82 /**
     83  * Function called when we're done processing the
     84  * HTTP POST /kyc-upload/$ID request.
     85  *
     86  * @param cls the `struct TALER_EXCHANGE_PostKycUploadHandle *`
     87  * @param response_code HTTP response code, 0 on error
     88  * @param response response body, NULL if not in JSON
     89  */
     90 static void
     91 handle_kyc_upload_finished (void *cls,
     92                             long response_code,
     93                             const void *response)
     94 {
     95   struct TALER_EXCHANGE_PostKycUploadHandle *pksh = cls;
     96   const json_t *json = response;
     97   struct TALER_EXCHANGE_PostKycUploadResponse adr = {
     98     .hr.http_status = (unsigned int) response_code,
     99     .hr.reply = json
    100   };
    101 
    102   pksh->job = NULL;
    103   switch (response_code)
    104   {
    105   case 0:
    106     /* no reply */
    107     adr.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
    108     adr.hr.hint = "server offline?";
    109     break;
    110   case MHD_HTTP_NO_CONTENT:
    111     /* success, nothing to parse */
    112     break;
    113   case MHD_HTTP_BAD_REQUEST:
    114     adr.hr.ec = TALER_JSON_get_error_code (json);
    115     adr.hr.hint = TALER_JSON_get_error_hint (json);
    116     break;
    117   case MHD_HTTP_NOT_FOUND:
    118     adr.hr.ec = TALER_JSON_get_error_code (json);
    119     adr.hr.hint = TALER_JSON_get_error_hint (json);
    120     break;
    121   case MHD_HTTP_CONFLICT:
    122     adr.hr.ec = TALER_JSON_get_error_code (json);
    123     adr.hr.hint = TALER_JSON_get_error_hint (json);
    124     break;
    125   case MHD_HTTP_CONTENT_TOO_LARGE:
    126     adr.hr.ec = TALER_JSON_get_error_code (json);
    127     adr.hr.hint = TALER_JSON_get_error_hint (json);
    128     break;
    129   case MHD_HTTP_INTERNAL_SERVER_ERROR:
    130     adr.hr.ec = TALER_JSON_get_error_code (json);
    131     adr.hr.hint = TALER_JSON_get_error_hint (json);
    132     break;
    133   default:
    134     /* unexpected response code */
    135     GNUNET_break_op (0);
    136     adr.hr.ec = TALER_JSON_get_error_code (json);
    137     adr.hr.hint = TALER_JSON_get_error_hint (json);
    138     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    139                 "Unexpected response code %u/%d for exchange POST kyc-upload\n",
    140                 (unsigned int) response_code,
    141                 (int) adr.hr.ec);
    142     break;
    143   }
    144   if (NULL != pksh->cb)
    145   {
    146     pksh->cb (pksh->cb_cls,
    147               &adr);
    148     pksh->cb = NULL;
    149   }
    150   TALER_EXCHANGE_post_kyc_upload_cancel (pksh);
    151 }
    152 
    153 
    154 struct TALER_EXCHANGE_PostKycUploadHandle *
    155 TALER_EXCHANGE_post_kyc_upload_create (
    156   struct GNUNET_CURL_Context *ctx,
    157   const char *url,
    158   const char *id,
    159   const json_t *attributes)
    160 {
    161   struct TALER_EXCHANGE_PostKycUploadHandle *pksh;
    162 
    163   pksh = GNUNET_new (struct TALER_EXCHANGE_PostKycUploadHandle);
    164   pksh->ctx = ctx;
    165   pksh->base_url = GNUNET_strdup (url);
    166   pksh->id = GNUNET_strdup (id);
    167   pksh->attributes = json_incref ((json_t *) attributes);
    168   return pksh;
    169 }
    170 
    171 
    172 struct TALER_EXCHANGE_PostKycUploadHandle *
    173 TALER_EXCHANGE_post_kyc_upload_accept_tos_create (
    174   struct GNUNET_CURL_Context *ctx,
    175   const char *url,
    176   const char *id,
    177   const char *tos_etag)
    178 {
    179   struct TALER_EXCHANGE_PostKycUploadHandle *pksh;
    180   json_t *attributes;
    181 
    182   attributes = GNUNET_JSON_PACK (
    183     /* form ID of the terms-of-service acceptance form */
    184     GNUNET_JSON_pack_string ("FORM_ID",
    185                              "accept-tos"),
    186     /* version (ETag) of the terms of service being accepted */
    187     GNUNET_JSON_pack_string ("ACCEPTED_TERMS_OF_SERVICE",
    188                              tos_etag),
    189     /* affirm that the terms of service were read/downloaded */
    190     GNUNET_JSON_pack_bool ("DOWNLOADED_TERMS_OF_SERVICE",
    191                            true));
    192   pksh = TALER_EXCHANGE_post_kyc_upload_create (ctx,
    193                                                 url,
    194                                                 id,
    195                                                 attributes);
    196   json_decref (attributes);
    197   return pksh;
    198 }
    199 
    200 
    201 enum TALER_ErrorCode
    202 TALER_EXCHANGE_post_kyc_upload_start (
    203   struct TALER_EXCHANGE_PostKycUploadHandle *pksh,
    204   TALER_EXCHANGE_PostKycUploadCallback cb,
    205   TALER_EXCHANGE_POST_KYC_UPLOAD_RESULT_CLOSURE *cb_cls)
    206 {
    207   CURL *eh;
    208   char *path;
    209 
    210   pksh->cb = cb;
    211   pksh->cb_cls = cb_cls;
    212   GNUNET_asprintf (&path,
    213                    "kyc-upload/%s",
    214                    pksh->id);
    215   pksh->url = TALER_url_join (pksh->base_url,
    216                               path,
    217                               NULL);
    218   GNUNET_free (path);
    219   if (NULL == pksh->url)
    220   {
    221     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    222                 "Could not construct request URL.\n");
    223     return TALER_EC_GENERIC_CONFIGURATION_INVALID;
    224   }
    225   eh = TALER_EXCHANGE_curl_easy_get_ (pksh->url);
    226   if ( (NULL == eh) ||
    227        (GNUNET_OK !=
    228         TALER_curl_easy_post (&pksh->post_ctx,
    229                               eh,
    230                               pksh->attributes)) )
    231   {
    232     GNUNET_break (0);
    233     if (NULL != eh)
    234       curl_easy_cleanup (eh);
    235     GNUNET_free (pksh->url);
    236     pksh->url = NULL;
    237     return TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE;
    238   }
    239   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
    240               "Requesting URL '%s'\n",
    241               pksh->url);
    242   pksh->job = GNUNET_CURL_job_add2 (pksh->ctx,
    243                                     eh,
    244                                     pksh->post_ctx.headers,
    245                                     &handle_kyc_upload_finished,
    246                                     pksh);
    247   if (NULL == pksh->job)
    248   {
    249     TALER_curl_easy_post_finished (&pksh->post_ctx);
    250     GNUNET_free (pksh->url);
    251     pksh->url = NULL;
    252     return TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE;
    253   }
    254   return TALER_EC_NONE;
    255 }
    256 
    257 
    258 void
    259 TALER_EXCHANGE_post_kyc_upload_cancel (
    260   struct TALER_EXCHANGE_PostKycUploadHandle *pksh)
    261 {
    262   if (NULL != pksh->job)
    263   {
    264     GNUNET_CURL_job_cancel (pksh->job);
    265     pksh->job = NULL;
    266   }
    267   TALER_curl_easy_post_finished (&pksh->post_ctx);
    268   json_decref (pksh->attributes);
    269   GNUNET_free (pksh->url);
    270   GNUNET_free (pksh->base_url);
    271   GNUNET_free (pksh->id);
    272   GNUNET_free (pksh);
    273 }
    274 
    275 
    276 /* end of exchange_api_post-kyc-upload-ID.c */