LCOV - code coverage report
Current view: top level - lib - exchange_api_get-kyc-info-ACCESS_TOKEN.c (source / functions) Coverage Total Hit
Test: coverage.info Lines: 49.4 % 168 83
Test Date: 2026-10-29 19:05:17 Functions: 83.3 % 6 5

            Line data    Source code
       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           11 : parse_kyc_info_ok (struct TALER_EXCHANGE_GetKycInfoHandle *lh,
      95              :                    const json_t *json)
      96              : {
      97           11 :   const json_t *jrequirements = NULL;
      98           11 :   const json_t *jvoluntary_checks = NULL;
      99           11 :   struct TALER_EXCHANGE_GetKycInfoResponse lr = {
     100              :     .hr.reply = json,
     101              :     .hr.http_status = MHD_HTTP_OK
     102              :   };
     103              :   struct GNUNET_JSON_Specification spec[] = {
     104           11 :     GNUNET_JSON_spec_array_const ("requirements",
     105              :                                   &jrequirements),
     106           11 :     GNUNET_JSON_spec_bool ("is_and_combinator",
     107              :                            &lr.details.ok.is_and_combinator),
     108           11 :     GNUNET_JSON_spec_mark_optional (
     109              :       GNUNET_JSON_spec_object_const ("voluntary_checks",
     110              :                                      &jvoluntary_checks),
     111              :       NULL),
     112           11 :     GNUNET_JSON_spec_end ()
     113              :   };
     114              : 
     115           11 :   if (GNUNET_OK !=
     116           11 :       GNUNET_JSON_parse (json,
     117              :                          spec,
     118              :                          NULL, NULL))
     119              :   {
     120            0 :     GNUNET_break_op (0);
     121            0 :     return GNUNET_SYSERR;
     122              :   }
     123              : 
     124           11 :   lr.details.ok.vci_length = json_object_size (jvoluntary_checks);
     125           11 :   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           11 :     if ( (lr.details.ok.vci_length >
     136           11 :           GNUNET_MAX_MALLOC_CHECKED / sizeof (*vci)) ||
     137           11 :          (lr.details.ok.requirements_length >
     138              :           GNUNET_MAX_MALLOC_CHECKED / sizeof (*requirements)) )
     139              :     {
     140            0 :       GNUNET_break_op (0);
     141            0 :       return GNUNET_SYSERR;
     142              :     }
     143           11 :     vci = GNUNET_new_array (
     144              :       GNUNET_NZL (lr.details.ok.vci_length),
     145              :       struct TALER_EXCHANGE_VoluntaryCheckInformation);
     146           11 :     requirements = GNUNET_new_array (
     147              :       GNUNET_NZL (lr.details.ok.requirements_length),
     148              :       struct TALER_EXCHANGE_RequirementInformation);
     149           22 :     json_array_foreach ((json_t *) jrequirements, off, jreq)
     150              :     {
     151           11 :       struct TALER_EXCHANGE_RequirementInformation *req = &requirements[off];
     152              :       struct GNUNET_JSON_Specification ispec[] = {
     153           11 :         GNUNET_JSON_spec_string ("form",
     154              :                                  &req->form),
     155           11 :         GNUNET_JSON_spec_string ("description",
     156              :                                  &req->description),
     157           11 :         GNUNET_JSON_spec_mark_optional (
     158              :           GNUNET_JSON_spec_object_const ("description_i18n",
     159              :                                          &req->description_i18n),
     160              :           NULL),
     161           11 :         GNUNET_JSON_spec_mark_optional (
     162              :           GNUNET_JSON_spec_string ("id",
     163              :                                    &req->id),
     164              :           NULL),
     165           11 :         GNUNET_JSON_spec_end ()
     166              :       };
     167              : 
     168           11 :       if (GNUNET_OK !=
     169           11 :           GNUNET_JSON_parse (jreq,
     170              :                              ispec,
     171              :                              NULL, NULL))
     172              :       {
     173            0 :         GNUNET_break_op (0);
     174            0 :         GNUNET_free (vci);
     175            0 :         GNUNET_free (requirements);
     176            0 :         return GNUNET_SYSERR;
     177              :       }
     178              :     }
     179           11 :     GNUNET_assert (off == lr.details.ok.requirements_length);
     180              : 
     181           11 :     off = 0;
     182           11 :     json_object_foreach ((json_t *) jvoluntary_checks, name, jvc)
     183              :     {
     184            0 :       struct TALER_EXCHANGE_VoluntaryCheckInformation *vc = &vci[off++];
     185              :       struct GNUNET_JSON_Specification ispec[] = {
     186            0 :         GNUNET_JSON_spec_string ("description",
     187              :                                  &vc->description),
     188            0 :         GNUNET_JSON_spec_mark_optional (
     189              :           GNUNET_JSON_spec_object_const ("description_i18n",
     190              :                                          &vc->description_i18n),
     191              :           NULL),
     192            0 :         GNUNET_JSON_spec_end ()
     193              :       };
     194              : 
     195            0 :       vc->name = name;
     196            0 :       if (GNUNET_OK !=
     197            0 :           GNUNET_JSON_parse (jvc,
     198              :                              ispec,
     199              :                              NULL, NULL))
     200              :       {
     201            0 :         GNUNET_break_op (0);
     202            0 :         GNUNET_free (vci);
     203            0 :         GNUNET_free (requirements);
     204            0 :         return GNUNET_SYSERR;
     205              :       }
     206              :     }
     207           11 :     GNUNET_assert (off == lr.details.ok.vci_length);
     208              : 
     209           11 :     lr.details.ok.vci = vci;
     210           11 :     lr.details.ok.requirements = requirements;
     211           11 :     lh->cb (lh->cb_cls,
     212              :             &lr);
     213           11 :     lh->cb = NULL;
     214           11 :     GNUNET_free (vci);
     215           11 :     GNUNET_free (requirements);
     216           11 :     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           11 : handle_kyc_info_finished (void *cls,
     231              :                           long response_code,
     232              :                           const void *response)
     233              : {
     234           11 :   struct TALER_EXCHANGE_GetKycInfoHandle *lh = cls;
     235           11 :   const json_t *j = response;
     236           11 :   struct TALER_EXCHANGE_GetKycInfoResponse lr = {
     237              :     .hr.reply = j,
     238           11 :     .hr.http_status = (unsigned int) response_code
     239              :   };
     240              : 
     241           11 :   lh->job = NULL;
     242           11 :   switch (response_code)
     243              :   {
     244            0 :   case 0:
     245            0 :     lr.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
     246            0 :     break;
     247           11 :   case MHD_HTTP_OK:
     248           11 :     if (GNUNET_OK !=
     249           11 :         parse_kyc_info_ok (lh,
     250              :                            j))
     251              :     {
     252            0 :       GNUNET_break_op (0);
     253            0 :       lr.hr.http_status = 0;
     254            0 :       lr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED;
     255            0 :       break;
     256              :     }
     257           11 :     GNUNET_assert (NULL == lh->cb);
     258           11 :     TALER_EXCHANGE_get_kyc_info_cancel (lh);
     259           11 :     return;
     260            0 :   case MHD_HTTP_NO_CONTENT:
     261            0 :     break;
     262            0 :   case MHD_HTTP_NOT_MODIFIED:
     263            0 :     break;
     264            0 :   case MHD_HTTP_BAD_REQUEST:
     265            0 :     lr.hr.ec = TALER_JSON_get_error_code (j);
     266            0 :     lr.hr.hint = TALER_JSON_get_error_hint (j);
     267            0 :     break;
     268            0 :   case MHD_HTTP_FORBIDDEN:
     269            0 :     lr.hr.ec = TALER_JSON_get_error_code (j);
     270            0 :     lr.hr.hint = TALER_JSON_get_error_hint (j);
     271            0 :     break;
     272            0 :   case MHD_HTTP_NOT_FOUND:
     273            0 :     lr.hr.ec = TALER_JSON_get_error_code (j);
     274            0 :     lr.hr.hint = TALER_JSON_get_error_hint (j);
     275            0 :     break;
     276            0 :   case MHD_HTTP_INTERNAL_SERVER_ERROR:
     277            0 :     lr.hr.ec = TALER_JSON_get_error_code (j);
     278            0 :     lr.hr.hint = TALER_JSON_get_error_hint (j);
     279            0 :     break;
     280            0 :   default:
     281              :     /* unexpected response code */
     282            0 :     GNUNET_break_op (0);
     283            0 :     lr.hr.ec = TALER_JSON_get_error_code (j);
     284            0 :     lr.hr.hint = TALER_JSON_get_error_hint (j);
     285            0 :     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            0 :     break;
     290              :   }
     291            0 :   if (NULL != lh->cb)
     292            0 :     lh->cb (lh->cb_cls,
     293              :             &lr);
     294            0 :   TALER_EXCHANGE_get_kyc_info_cancel (lh);
     295              : }
     296              : 
     297              : 
     298              : struct TALER_EXCHANGE_GetKycInfoHandle *
     299           11 : 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           11 :   lh = GNUNET_new (struct TALER_EXCHANGE_GetKycInfoHandle);
     307           11 :   lh->ctx = ctx;
     308           11 :   lh->base_url = GNUNET_strdup (url);
     309           11 :   lh->token = *token;
     310           11 :   return lh;
     311              : }
     312              : 
     313              : 
     314              : enum GNUNET_GenericReturnValue
     315            0 : 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            0 :   for (unsigned int i = 0; i < num_options; i++)
     321              :   {
     322            0 :     const struct TALER_EXCHANGE_GetKycInfoOptionValue *opt = &options[i];
     323              : 
     324            0 :     switch (opt->option)
     325              :     {
     326            0 :     case TALER_EXCHANGE_GET_KYC_INFO_OPTION_END:
     327            0 :       return GNUNET_OK;
     328            0 :     case TALER_EXCHANGE_GET_KYC_INFO_OPTION_IF_NONE_MATCH:
     329            0 :       gkih->if_none_match = opt->details.if_none_match;
     330            0 :       break;
     331            0 :     case TALER_EXCHANGE_GET_KYC_INFO_OPTION_TIMEOUT:
     332            0 :       gkih->timeout = opt->details.timeout;
     333            0 :       break;
     334            0 :     default:
     335            0 :       GNUNET_break (0);
     336            0 :       return GNUNET_SYSERR;
     337              :     }
     338              :   }
     339            0 :   return GNUNET_OK;
     340              : }
     341              : 
     342              : 
     343              : enum TALER_ErrorCode
     344           11 : 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           11 :   struct curl_slist *job_headers = NULL;
     353              : 
     354           11 :   gkih->cb = cb;
     355           11 :   gkih->cb_cls = cb_cls;
     356           22 :   tms = (unsigned int) (gkih->timeout.rel_value_us
     357           11 :                         / GNUNET_TIME_UNIT_MILLISECONDS.rel_value_us);
     358              :   {
     359              :     char at_str[sizeof (struct TALER_AccountAccessTokenP) * 2];
     360              :     char *end;
     361              : 
     362           11 :     end = GNUNET_STRINGS_data_to_string (
     363           11 :       &gkih->token,
     364              :       sizeof (gkih->token),
     365              :       at_str,
     366              :       sizeof (at_str));
     367           11 :     *end = '\0';
     368           11 :     GNUNET_snprintf (arg_str,
     369              :                      sizeof (arg_str),
     370              :                      "kyc-info/%s",
     371              :                      at_str);
     372              :   }
     373              :   {
     374              :     char timeout_str[32];
     375              : 
     376           11 :     GNUNET_snprintf (timeout_str,
     377              :                      sizeof (timeout_str),
     378              :                      "%u",
     379              :                      tms);
     380           11 :     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           11 :   if (NULL == gkih->url)
     389            0 :     return TALER_EC_GENERIC_CONFIGURATION_INVALID;
     390           11 :   eh = TALER_EXCHANGE_curl_easy_get_ (gkih->url);
     391           11 :   if (NULL == eh)
     392              :   {
     393            0 :     GNUNET_break (0);
     394            0 :     GNUNET_free (gkih->url);
     395            0 :     gkih->url = NULL;
     396            0 :     return TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE;
     397              :   }
     398           11 :   if (0 != tms)
     399              :   {
     400            0 :     GNUNET_break (CURLE_OK ==
     401              :                   curl_easy_setopt (eh,
     402              :                                     CURLOPT_TIMEOUT_MS,
     403              :                                     (long) (tms + 100L)));
     404              :   }
     405           11 :   if (NULL != gkih->if_none_match)
     406              :   {
     407              :     char *hdr;
     408              : 
     409            0 :     GNUNET_asprintf (&hdr,
     410              :                      "%s: %s",
     411              :                      MHD_HTTP_HEADER_IF_NONE_MATCH,
     412              :                      gkih->if_none_match);
     413            0 :     job_headers = curl_slist_append (job_headers,
     414              :                                      hdr);
     415            0 :     GNUNET_free (hdr);
     416              :   }
     417           11 :   gkih->job = GNUNET_CURL_job_add2 (gkih->ctx,
     418              :                                     eh,
     419              :                                     job_headers,
     420              :                                     &handle_kyc_info_finished,
     421              :                                     gkih);
     422           11 :   curl_slist_free_all (job_headers);
     423           11 :   if (NULL == gkih->job)
     424              :   {
     425            0 :     GNUNET_free (gkih->url);
     426            0 :     gkih->url = NULL;
     427            0 :     return TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE;
     428              :   }
     429           11 :   return TALER_EC_NONE;
     430              : }
     431              : 
     432              : 
     433              : void
     434           11 : TALER_EXCHANGE_get_kyc_info_cancel (
     435              :   struct TALER_EXCHANGE_GetKycInfoHandle *gkih)
     436              : {
     437           11 :   if (NULL != gkih->job)
     438              :   {
     439            0 :     GNUNET_CURL_job_cancel (gkih->job);
     440            0 :     gkih->job = NULL;
     441              :   }
     442           11 :   GNUNET_free (gkih->url);
     443           11 :   GNUNET_free (gkih->base_url);
     444           11 :   GNUNET_free (gkih);
     445           11 : }
     446              : 
     447              : 
     448              : /* end of exchange_api_get-kyc-info-ACCESS_TOKEN.c */
        

Generated by: LCOV version 2.0-1