exchange

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

exchange_api_get-kyc-info-ACCESS_TOKEN.c (12609B)


      1 /*
      2   This file is part of TALER
      3   Copyright (C) 2015-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_get-kyc-info-ACCESS_TOKEN.c
     19  * @brief Implementation of the /kyc-info/$AT request
     20  * @author Christian Grothoff
     21  */
     22 #include <microhttpd.h> /* just for HTTP status codes */
     23 #include <gnunet/gnunet_util_lib.h>
     24 #include <gnunet/gnunet_curl_lib.h>
     25 #include "taler/taler_json_lib.h"
     26 #include "taler/exchange/get-kyc-info-ACCESS_TOKEN.h"
     27 #include "taler/taler_signatures.h"
     28 #include "exchange_api_curl_defaults.h"
     29 
     30 
     31 /**
     32  * @brief A GET /kyc-info/$AT handle
     33  */
     34 struct TALER_EXCHANGE_GetKycInfoHandle
     35 {
     36 
     37   /**
     38    * The base URL for this request.
     39    */
     40   char *base_url;
     41 
     42   /**
     43    * The full URL for this request, set during _start.
     44    */
     45   char *url;
     46 
     47   /**
     48    * Handle for the request.
     49    */
     50   struct GNUNET_CURL_Job *job;
     51 
     52   /**
     53    * Function to call with the result.
     54    */
     55   TALER_EXCHANGE_GetKycInfoCallback cb;
     56 
     57   /**
     58    * Closure for @e cb.
     59    */
     60   TALER_EXCHANGE_GET_KYC_INFO_RESULT_CLOSURE *cb_cls;
     61 
     62   /**
     63    * Reference to the execution context.
     64    */
     65   struct GNUNET_CURL_Context *ctx;
     66 
     67   /**
     68    * Access token for the KYC process.
     69    */
     70   struct TALER_AccountAccessTokenP token;
     71 
     72   /**
     73    * ETag from a previous response for conditional requests.
     74    * Borrowed pointer, not owned.
     75    */
     76   const char *if_none_match;
     77 
     78   /**
     79    * Long polling timeout.
     80    */
     81   struct GNUNET_TIME_Relative timeout;
     82 
     83 };
     84 
     85 
     86 /**
     87  * Parse the provided kyc-info data from the "200 OK" response.
     88  *
     89  * @param[in,out] lh handle (callback may be zero'ed out)
     90  * @param json json reply with the data
     91  * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
     92  */
     93 static enum GNUNET_GenericReturnValue
     94 parse_kyc_info_ok (struct TALER_EXCHANGE_GetKycInfoHandle *lh,
     95                    const json_t *json)
     96 {
     97   const json_t *jrequirements = NULL;
     98   const json_t *jvoluntary_checks = NULL;
     99   struct TALER_EXCHANGE_GetKycInfoResponse lr = {
    100     .hr.reply = json,
    101     .hr.http_status = MHD_HTTP_OK
    102   };
    103   struct GNUNET_JSON_Specification spec[] = {
    104     GNUNET_JSON_spec_array_const ("requirements",
    105                                   &jrequirements),
    106     GNUNET_JSON_spec_bool ("is_and_combinator",
    107                            &lr.details.ok.is_and_combinator),
    108     GNUNET_JSON_spec_mark_optional (
    109       GNUNET_JSON_spec_object_const ("voluntary_checks",
    110                                      &jvoluntary_checks),
    111       NULL),
    112     GNUNET_JSON_spec_end ()
    113   };
    114 
    115   if (GNUNET_OK !=
    116       GNUNET_JSON_parse (json,
    117                          spec,
    118                          NULL, NULL))
    119   {
    120     GNUNET_break_op (0);
    121     return GNUNET_SYSERR;
    122   }
    123 
    124   lr.details.ok.vci_length = json_object_size (jvoluntary_checks);
    125   lr.details.ok.requirements_length = json_array_size (jrequirements);
    126 
    127   {
    128     struct TALER_EXCHANGE_VoluntaryCheckInformation *vci;
    129     struct TALER_EXCHANGE_RequirementInformation *requirements;
    130     const char *name;
    131     const json_t *jreq;
    132     const json_t *jvc;
    133     size_t off;
    134 
    135     if ( (lr.details.ok.vci_length >
    136           GNUNET_MAX_MALLOC_CHECKED / sizeof (*vci)) ||
    137          (lr.details.ok.requirements_length >
    138           GNUNET_MAX_MALLOC_CHECKED / sizeof (*requirements)) )
    139     {
    140       GNUNET_break_op (0);
    141       return GNUNET_SYSERR;
    142     }
    143     vci = GNUNET_new_array (
    144       GNUNET_NZL (lr.details.ok.vci_length),
    145       struct TALER_EXCHANGE_VoluntaryCheckInformation);
    146     requirements = GNUNET_new_array (
    147       GNUNET_NZL (lr.details.ok.requirements_length),
    148       struct TALER_EXCHANGE_RequirementInformation);
    149     json_array_foreach ((json_t *) jrequirements, off, jreq)
    150     {
    151       struct TALER_EXCHANGE_RequirementInformation *req = &requirements[off];
    152       struct GNUNET_JSON_Specification ispec[] = {
    153         GNUNET_JSON_spec_string ("form",
    154                                  &req->form),
    155         GNUNET_JSON_spec_string ("description",
    156                                  &req->description),
    157         GNUNET_JSON_spec_mark_optional (
    158           GNUNET_JSON_spec_object_const ("description_i18n",
    159                                          &req->description_i18n),
    160           NULL),
    161         GNUNET_JSON_spec_mark_optional (
    162           GNUNET_JSON_spec_string ("id",
    163                                    &req->id),
    164           NULL),
    165         GNUNET_JSON_spec_end ()
    166       };
    167 
    168       if (GNUNET_OK !=
    169           GNUNET_JSON_parse (jreq,
    170                              ispec,
    171                              NULL, NULL))
    172       {
    173         GNUNET_break_op (0);
    174         GNUNET_free (vci);
    175         GNUNET_free (requirements);
    176         return GNUNET_SYSERR;
    177       }
    178     }
    179     GNUNET_assert (off == lr.details.ok.requirements_length);
    180 
    181     off = 0;
    182     json_object_foreach ((json_t *) jvoluntary_checks, name, jvc)
    183     {
    184       struct TALER_EXCHANGE_VoluntaryCheckInformation *vc = &vci[off++];
    185       struct GNUNET_JSON_Specification ispec[] = {
    186         GNUNET_JSON_spec_string ("description",
    187                                  &vc->description),
    188         GNUNET_JSON_spec_mark_optional (
    189           GNUNET_JSON_spec_object_const ("description_i18n",
    190                                          &vc->description_i18n),
    191           NULL),
    192         GNUNET_JSON_spec_end ()
    193       };
    194 
    195       vc->name = name;
    196       if (GNUNET_OK !=
    197           GNUNET_JSON_parse (jvc,
    198                              ispec,
    199                              NULL, NULL))
    200       {
    201         GNUNET_break_op (0);
    202         GNUNET_free (vci);
    203         GNUNET_free (requirements);
    204         return GNUNET_SYSERR;
    205       }
    206     }
    207     GNUNET_assert (off == lr.details.ok.vci_length);
    208 
    209     lr.details.ok.vci = vci;
    210     lr.details.ok.requirements = requirements;
    211     lh->cb (lh->cb_cls,
    212             &lr);
    213     lh->cb = NULL;
    214     GNUNET_free (vci);
    215     GNUNET_free (requirements);
    216     return GNUNET_OK;
    217   }
    218 }
    219 
    220 
    221 /**
    222  * Function called when we're done processing the
    223  * HTTP GET /kyc-info/$AT request.
    224  *
    225  * @param cls the `struct TALER_EXCHANGE_GetKycInfoHandle`
    226  * @param response_code HTTP response code, 0 on error
    227  * @param response parsed JSON result, NULL on error
    228  */
    229 static void
    230 handle_kyc_info_finished (void *cls,
    231                           long response_code,
    232                           const void *response)
    233 {
    234   struct TALER_EXCHANGE_GetKycInfoHandle *lh = cls;
    235   const json_t *j = response;
    236   struct TALER_EXCHANGE_GetKycInfoResponse lr = {
    237     .hr.reply = j,
    238     .hr.http_status = (unsigned int) response_code
    239   };
    240 
    241   lh->job = NULL;
    242   switch (response_code)
    243   {
    244   case 0:
    245     lr.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
    246     break;
    247   case MHD_HTTP_OK:
    248     if (GNUNET_OK !=
    249         parse_kyc_info_ok (lh,
    250                            j))
    251     {
    252       GNUNET_break_op (0);
    253       lr.hr.http_status = 0;
    254       lr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED;
    255       break;
    256     }
    257     GNUNET_assert (NULL == lh->cb);
    258     TALER_EXCHANGE_get_kyc_info_cancel (lh);
    259     return;
    260   case MHD_HTTP_NO_CONTENT:
    261     break;
    262   case MHD_HTTP_NOT_MODIFIED:
    263     break;
    264   case MHD_HTTP_BAD_REQUEST:
    265     lr.hr.ec = TALER_JSON_get_error_code (j);
    266     lr.hr.hint = TALER_JSON_get_error_hint (j);
    267     break;
    268   case MHD_HTTP_FORBIDDEN:
    269     lr.hr.ec = TALER_JSON_get_error_code (j);
    270     lr.hr.hint = TALER_JSON_get_error_hint (j);
    271     break;
    272   case MHD_HTTP_NOT_FOUND:
    273     lr.hr.ec = TALER_JSON_get_error_code (j);
    274     lr.hr.hint = TALER_JSON_get_error_hint (j);
    275     break;
    276   case MHD_HTTP_INTERNAL_SERVER_ERROR:
    277     lr.hr.ec = TALER_JSON_get_error_code (j);
    278     lr.hr.hint = TALER_JSON_get_error_hint (j);
    279     break;
    280   default:
    281     /* unexpected response code */
    282     GNUNET_break_op (0);
    283     lr.hr.ec = TALER_JSON_get_error_code (j);
    284     lr.hr.hint = TALER_JSON_get_error_hint (j);
    285     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    286                 "Unexpected response code %u/%d for exchange /kyc-info\n",
    287                 (unsigned int) response_code,
    288                 (int) lr.hr.ec);
    289     break;
    290   }
    291   if (NULL != lh->cb)
    292     lh->cb (lh->cb_cls,
    293             &lr);
    294   TALER_EXCHANGE_get_kyc_info_cancel (lh);
    295 }
    296 
    297 
    298 struct TALER_EXCHANGE_GetKycInfoHandle *
    299 TALER_EXCHANGE_get_kyc_info_create (
    300   struct GNUNET_CURL_Context *ctx,
    301   const char *url,
    302   const struct TALER_AccountAccessTokenP *token)
    303 {
    304   struct TALER_EXCHANGE_GetKycInfoHandle *lh;
    305 
    306   lh = GNUNET_new (struct TALER_EXCHANGE_GetKycInfoHandle);
    307   lh->ctx = ctx;
    308   lh->base_url = GNUNET_strdup (url);
    309   lh->token = *token;
    310   return lh;
    311 }
    312 
    313 
    314 enum GNUNET_GenericReturnValue
    315 TALER_EXCHANGE_get_kyc_info_set_options_ (
    316   struct TALER_EXCHANGE_GetKycInfoHandle *gkih,
    317   unsigned int num_options,
    318   const struct TALER_EXCHANGE_GetKycInfoOptionValue *options)
    319 {
    320   for (unsigned int i = 0; i < num_options; i++)
    321   {
    322     const struct TALER_EXCHANGE_GetKycInfoOptionValue *opt = &options[i];
    323 
    324     switch (opt->option)
    325     {
    326     case TALER_EXCHANGE_GET_KYC_INFO_OPTION_END:
    327       return GNUNET_OK;
    328     case TALER_EXCHANGE_GET_KYC_INFO_OPTION_IF_NONE_MATCH:
    329       gkih->if_none_match = opt->details.if_none_match;
    330       break;
    331     case TALER_EXCHANGE_GET_KYC_INFO_OPTION_TIMEOUT:
    332       gkih->timeout = opt->details.timeout;
    333       break;
    334     default:
    335       GNUNET_break (0);
    336       return GNUNET_SYSERR;
    337     }
    338   }
    339   return GNUNET_OK;
    340 }
    341 
    342 
    343 enum TALER_ErrorCode
    344 TALER_EXCHANGE_get_kyc_info_start (
    345   struct TALER_EXCHANGE_GetKycInfoHandle *gkih,
    346   TALER_EXCHANGE_GetKycInfoCallback cb,
    347   TALER_EXCHANGE_GET_KYC_INFO_RESULT_CLOSURE *cb_cls)
    348 {
    349   CURL *eh;
    350   char arg_str[sizeof (struct TALER_AccountAccessTokenP) * 2 + 32];
    351   unsigned int tms;
    352   struct curl_slist *job_headers = NULL;
    353 
    354   gkih->cb = cb;
    355   gkih->cb_cls = cb_cls;
    356   tms = (unsigned int) (gkih->timeout.rel_value_us
    357                         / GNUNET_TIME_UNIT_MILLISECONDS.rel_value_us);
    358   {
    359     char at_str[sizeof (struct TALER_AccountAccessTokenP) * 2];
    360     char *end;
    361 
    362     end = GNUNET_STRINGS_data_to_string (
    363       &gkih->token,
    364       sizeof (gkih->token),
    365       at_str,
    366       sizeof (at_str));
    367     *end = '\0';
    368     GNUNET_snprintf (arg_str,
    369                      sizeof (arg_str),
    370                      "kyc-info/%s",
    371                      at_str);
    372   }
    373   {
    374     char timeout_str[32];
    375 
    376     GNUNET_snprintf (timeout_str,
    377                      sizeof (timeout_str),
    378                      "%u",
    379                      tms);
    380     gkih->url = TALER_url_join (gkih->base_url,
    381                                 arg_str,
    382                                 "timeout_ms",
    383                                 (0 == tms)
    384                                 ? NULL
    385                                 : timeout_str,
    386                                 NULL);
    387   }
    388   if (NULL == gkih->url)
    389     return TALER_EC_GENERIC_CONFIGURATION_INVALID;
    390   eh = TALER_EXCHANGE_curl_easy_get_ (gkih->url);
    391   if (NULL == eh)
    392   {
    393     GNUNET_break (0);
    394     GNUNET_free (gkih->url);
    395     gkih->url = NULL;
    396     return TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE;
    397   }
    398   if (0 != tms)
    399   {
    400     GNUNET_break (CURLE_OK ==
    401                   curl_easy_setopt (eh,
    402                                     CURLOPT_TIMEOUT_MS,
    403                                     (long) (tms + 100L)));
    404   }
    405   if (NULL != gkih->if_none_match)
    406   {
    407     char *hdr;
    408 
    409     GNUNET_asprintf (&hdr,
    410                      "%s: %s",
    411                      MHD_HTTP_HEADER_IF_NONE_MATCH,
    412                      gkih->if_none_match);
    413     job_headers = curl_slist_append (job_headers,
    414                                      hdr);
    415     GNUNET_free (hdr);
    416   }
    417   gkih->job = GNUNET_CURL_job_add2 (gkih->ctx,
    418                                     eh,
    419                                     job_headers,
    420                                     &handle_kyc_info_finished,
    421                                     gkih);
    422   curl_slist_free_all (job_headers);
    423   if (NULL == gkih->job)
    424   {
    425     GNUNET_free (gkih->url);
    426     gkih->url = NULL;
    427     return TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE;
    428   }
    429   return TALER_EC_NONE;
    430 }
    431 
    432 
    433 void
    434 TALER_EXCHANGE_get_kyc_info_cancel (
    435   struct TALER_EXCHANGE_GetKycInfoHandle *gkih)
    436 {
    437   if (NULL != gkih->job)
    438   {
    439     GNUNET_CURL_job_cancel (gkih->job);
    440     gkih->job = NULL;
    441   }
    442   GNUNET_free (gkih->url);
    443   GNUNET_free (gkih->base_url);
    444   GNUNET_free (gkih);
    445 }
    446 
    447 
    448 /* end of exchange_api_get-kyc-info-ACCESS_TOKEN.c */