LCOV - code coverage report
Current view: top level - lib - exchange_api_get-aml-OFFICER_PUB-attributes-H_NORMALIZED_PAYTO.c (source / functions) Coverage Total Hit
Test: coverage.info Lines: 0.0 % 161 0
Test Date: 2026-03-10 12:10:57 Functions: 0.0 % 7 0

            Line data    Source code
       1              : /*
       2              :   This file is part of TALER
       3              :   Copyright (C) 2023, 2024, 2025, 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-aml-OFFICER_PUB-attributes-H_NORMALIZED_PAYTO.c
      19              :  * @brief Implementation of the /aml/$OFFICER_PUB/attributes request
      20              :  * @author Christian Grothoff
      21              :  */
      22              : #include "taler/platform.h"
      23              : #include <microhttpd.h> /* just for HTTP status codes */
      24              : #include <gnunet/gnunet_util_lib.h>
      25              : #include <gnunet/gnunet_curl_lib.h>
      26              : #include "taler/taler_exchange_service.h"
      27              : #include "taler/taler_json_lib.h"
      28              : #include "exchange_api_handle.h"
      29              : #include "taler/taler_signatures.h"
      30              : #include "exchange_api_curl_defaults.h"
      31              : #include \
      32              :   "taler/taler-exchange/get-aml-OFFICER_PUB-attributes-H_NORMALIZED_PAYTO.h"
      33              : 
      34              : 
      35              : /**
      36              :  * @brief A GET /aml/$OFFICER_PUB/attributes/$H_NORMALIZED_PAYTO Handle
      37              :  */
      38              : struct TALER_EXCHANGE_GetAmlAttributesHandle
      39              : {
      40              : 
      41              :   /**
      42              :    * Base URL of the exchange.
      43              :    */
      44              :   char *base_url;
      45              : 
      46              :   /**
      47              :    * The url for this request.
      48              :    */
      49              :   char *url;
      50              : 
      51              :   /**
      52              :    * Handle for the request.
      53              :    */
      54              :   struct GNUNET_CURL_Job *job;
      55              : 
      56              :   /**
      57              :    * Function to call with the result.
      58              :    */
      59              :   TALER_EXCHANGE_GetAmlAttributesCallback cb;
      60              : 
      61              :   /**
      62              :    * Closure for @e cb.
      63              :    */
      64              :   TALER_EXCHANGE_GET_AML_ATTRIBUTES_RESULT_CLOSURE *cb_cls;
      65              : 
      66              :   /**
      67              :    * CURL context to use.
      68              :    */
      69              :   struct GNUNET_CURL_Context *ctx;
      70              : 
      71              :   /**
      72              :    * Public key of the AML officer (computed from officer_priv in _create).
      73              :    */
      74              :   struct TALER_AmlOfficerPublicKeyP officer_pub;
      75              : 
      76              :   /**
      77              :    * Private key of the AML officer (stored for signing in _start).
      78              :    */
      79              :   struct TALER_AmlOfficerPrivateKeyP officer_priv;
      80              : 
      81              :   /**
      82              :    * Hash of the normalized payto URI for the account.
      83              :    */
      84              :   struct TALER_NormalizedPaytoHashP h_payto;
      85              : 
      86              :   /**
      87              :    * Options set for this request.
      88              :    */
      89              :   struct
      90              :   {
      91              :     /**
      92              :      * Limit on the number of results (negative = before offset, positive = after).
      93              :      * Default: -20.
      94              :      */
      95              :     int64_t limit;
      96              : 
      97              :     /**
      98              :      * Row offset threshold. Default: UINT64_MAX.
      99              :      */
     100              :     uint64_t offset;
     101              :   } options;
     102              : 
     103              : };
     104              : 
     105              : 
     106              : /**
     107              :  * Parse AML attribute collection events from a JSON array.
     108              :  *
     109              :  * @param jdetails JSON array with AML attribute collection events
     110              :  * @param[out] detail_ar where to write the results
     111              :  * @return #GNUNET_OK on success
     112              :  */
     113              : static enum GNUNET_GenericReturnValue
     114            0 : parse_attributes_new (
     115              :   const json_t *jdetails,
     116              :   struct TALER_EXCHANGE_GetAmlAttributesCollectionEvent *detail_ar)
     117              : {
     118              :   json_t *obj;
     119              :   size_t idx;
     120              : 
     121            0 :   json_array_foreach (jdetails, idx, obj)
     122              :   {
     123            0 :     struct TALER_EXCHANGE_GetAmlAttributesCollectionEvent *detail
     124            0 :       = &detail_ar[idx];
     125            0 :     bool by_aml_officer = false;
     126              :     struct GNUNET_JSON_Specification spec[] = {
     127            0 :       GNUNET_JSON_spec_uint64 ("rowid",
     128              :                                &detail->rowid),
     129            0 :       GNUNET_JSON_spec_mark_optional (
     130              :         GNUNET_JSON_spec_bool ("by_aml_officer",
     131              :                                &by_aml_officer),
     132              :         NULL),
     133            0 :       GNUNET_JSON_spec_mark_optional (
     134              :         GNUNET_JSON_spec_object_const ("attributes",
     135              :                                        &detail->attributes),
     136              :         NULL),
     137            0 :       GNUNET_JSON_spec_timestamp ("collection_time",
     138              :                                   &detail->collection_time),
     139            0 :       GNUNET_JSON_spec_end ()
     140              :     };
     141              : 
     142            0 :     detail->by_aml_officer = false;
     143            0 :     detail->attributes = NULL;
     144            0 :     if (GNUNET_OK !=
     145            0 :         GNUNET_JSON_parse (obj,
     146              :                            spec,
     147              :                            NULL,
     148              :                            NULL))
     149              :     {
     150            0 :       GNUNET_break_op (0);
     151            0 :       return GNUNET_SYSERR;
     152              :     }
     153            0 :     detail->by_aml_officer = by_aml_officer;
     154              :   }
     155            0 :   return GNUNET_OK;
     156              : }
     157              : 
     158              : 
     159              : /**
     160              :  * Parse the provided data from the "200 OK" response.
     161              :  *
     162              :  * @param[in,out] aagh handle (callback may be zero'ed out)
     163              :  * @param json json reply with the data
     164              :  * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
     165              :  */
     166              : static enum GNUNET_GenericReturnValue
     167            0 : parse_get_aml_attributes_ok_new (
     168              :   struct TALER_EXCHANGE_GetAmlAttributesHandle *aagh,
     169              :   const json_t *json)
     170              : {
     171            0 :   struct TALER_EXCHANGE_GetAmlAttributesResponse lr = {
     172              :     .hr.reply = json,
     173              :     .hr.http_status = MHD_HTTP_OK
     174              :   };
     175              :   const json_t *jdetails;
     176              :   struct GNUNET_JSON_Specification spec[] = {
     177            0 :     GNUNET_JSON_spec_array_const ("details",
     178              :                                   &jdetails),
     179            0 :     GNUNET_JSON_spec_end ()
     180              :   };
     181              : 
     182            0 :   if (GNUNET_OK !=
     183            0 :       GNUNET_JSON_parse (json,
     184              :                          spec,
     185              :                          NULL,
     186              :                          NULL))
     187              :   {
     188            0 :     GNUNET_break_op (0);
     189            0 :     return GNUNET_SYSERR;
     190              :   }
     191            0 :   lr.details.ok.details_length = json_array_size (jdetails);
     192            0 :   {
     193            0 :     struct TALER_EXCHANGE_GetAmlAttributesCollectionEvent details[
     194            0 :       GNUNET_NZL (lr.details.ok.details_length)];
     195              : 
     196            0 :     memset (details,
     197              :             0,
     198              :             sizeof (details));
     199            0 :     lr.details.ok.details = details;
     200            0 :     if (GNUNET_OK !=
     201            0 :         parse_attributes_new (jdetails,
     202              :                               details))
     203              :     {
     204            0 :       GNUNET_break_op (0);
     205            0 :       return GNUNET_SYSERR;
     206              :     }
     207            0 :     aagh->cb (aagh->cb_cls,
     208              :               &lr);
     209            0 :     aagh->cb = NULL;
     210              :   }
     211            0 :   return GNUNET_OK;
     212              : }
     213              : 
     214              : 
     215              : /**
     216              :  * Function called when we're done processing the
     217              :  * HTTP GET /aml/$OFFICER_PUB/attributes/$H_NORMALIZED_PAYTO request (new API).
     218              :  *
     219              :  * @param cls the `struct TALER_EXCHANGE_GetAmlAttributesHandle`
     220              :  * @param response_code HTTP response code, 0 on error
     221              :  * @param response parsed JSON result, NULL on error
     222              :  */
     223              : static void
     224            0 : handle_get_aml_attributes_finished (void *cls,
     225              :                                     long response_code,
     226              :                                     const void *response)
     227              : {
     228            0 :   struct TALER_EXCHANGE_GetAmlAttributesHandle *aagh = cls;
     229            0 :   const json_t *j = response;
     230            0 :   struct TALER_EXCHANGE_GetAmlAttributesResponse lr = {
     231              :     .hr.reply = j,
     232            0 :     .hr.http_status = (unsigned int) response_code
     233              :   };
     234              : 
     235            0 :   aagh->job = NULL;
     236            0 :   switch (response_code)
     237              :   {
     238            0 :   case 0:
     239            0 :     lr.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
     240            0 :     break;
     241            0 :   case MHD_HTTP_OK:
     242            0 :     if (GNUNET_OK !=
     243            0 :         parse_get_aml_attributes_ok_new (aagh,
     244              :                                          j))
     245              :     {
     246            0 :       GNUNET_break_op (0);
     247            0 :       lr.hr.http_status = 0;
     248            0 :       lr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED;
     249            0 :       break;
     250              :     }
     251            0 :     GNUNET_assert (NULL == aagh->cb);
     252            0 :     TALER_EXCHANGE_get_aml_attributes_cancel (aagh);
     253            0 :     return;
     254            0 :   case MHD_HTTP_NO_CONTENT:
     255            0 :     break;
     256            0 :   case MHD_HTTP_NOT_IMPLEMENTED:
     257            0 :     lr.hr.ec = TALER_JSON_get_error_code (j);
     258            0 :     lr.hr.hint = TALER_JSON_get_error_hint (j);
     259            0 :     break;
     260            0 :   case MHD_HTTP_BAD_REQUEST:
     261            0 :     lr.hr.ec = TALER_JSON_get_error_code (j);
     262            0 :     lr.hr.hint = TALER_JSON_get_error_hint (j);
     263              :     /* This should never happen, either us or the exchange is buggy
     264              :        (or API version conflict); just pass JSON reply to the application */
     265            0 :     break;
     266            0 :   case MHD_HTTP_FORBIDDEN:
     267            0 :     lr.hr.ec = TALER_JSON_get_error_code (j);
     268            0 :     lr.hr.hint = TALER_JSON_get_error_hint (j);
     269            0 :     break;
     270            0 :   case MHD_HTTP_NOT_FOUND:
     271            0 :     lr.hr.ec = TALER_JSON_get_error_code (j);
     272            0 :     lr.hr.hint = TALER_JSON_get_error_hint (j);
     273            0 :     break;
     274            0 :   case MHD_HTTP_INTERNAL_SERVER_ERROR:
     275            0 :     lr.hr.ec = TALER_JSON_get_error_code (j);
     276            0 :     lr.hr.hint = TALER_JSON_get_error_hint (j);
     277              :     /* Server had an internal issue; we should retry, but this API
     278              :        leaves this to the application */
     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 get AML attributes\n",
     287              :                 (unsigned int) response_code,
     288              :                 (int) lr.hr.ec);
     289            0 :     break;
     290              :   }
     291            0 :   if (NULL != aagh->cb)
     292            0 :     aagh->cb (aagh->cb_cls,
     293              :               &lr);
     294            0 :   TALER_EXCHANGE_get_aml_attributes_cancel (aagh);
     295              : }
     296              : 
     297              : 
     298              : struct TALER_EXCHANGE_GetAmlAttributesHandle *
     299            0 : TALER_EXCHANGE_get_aml_attributes_create (
     300              :   struct GNUNET_CURL_Context *ctx,
     301              :   const char *url,
     302              :   const struct TALER_AmlOfficerPrivateKeyP *officer_priv,
     303              :   const struct TALER_NormalizedPaytoHashP *h_payto)
     304              : {
     305              :   struct TALER_EXCHANGE_GetAmlAttributesHandle *aagh;
     306              : 
     307            0 :   aagh = GNUNET_new (struct TALER_EXCHANGE_GetAmlAttributesHandle);
     308            0 :   aagh->ctx = ctx;
     309            0 :   aagh->base_url = GNUNET_strdup (url);
     310            0 :   aagh->h_payto = *h_payto;
     311            0 :   aagh->officer_priv = *officer_priv;
     312            0 :   GNUNET_CRYPTO_eddsa_key_get_public (&officer_priv->eddsa_priv,
     313              :                                       &aagh->officer_pub.eddsa_pub);
     314            0 :   aagh->options.limit = -20;
     315            0 :   aagh->options.offset = UINT64_MAX;
     316            0 :   return aagh;
     317              : }
     318              : 
     319              : 
     320              : enum GNUNET_GenericReturnValue
     321            0 : TALER_EXCHANGE_get_aml_attributes_set_options_ (
     322              :   struct TALER_EXCHANGE_GetAmlAttributesHandle *aagh,
     323              :   unsigned int num_options,
     324              :   const struct TALER_EXCHANGE_GetAmlAttributesOptionValue *options)
     325              : {
     326            0 :   for (unsigned int i = 0; i < num_options; i++)
     327              :   {
     328            0 :     const struct TALER_EXCHANGE_GetAmlAttributesOptionValue *opt = &options[i];
     329              : 
     330            0 :     switch (opt->option)
     331              :     {
     332            0 :     case TALER_EXCHANGE_GET_AML_ATTRIBUTES_OPTION_END:
     333            0 :       return GNUNET_OK;
     334            0 :     case TALER_EXCHANGE_GET_AML_ATTRIBUTES_OPTION_LIMIT:
     335            0 :       aagh->options.limit = opt->details.limit;
     336            0 :       break;
     337            0 :     case TALER_EXCHANGE_GET_AML_ATTRIBUTES_OPTION_OFFSET:
     338            0 :       aagh->options.offset = opt->details.offset;
     339            0 :       break;
     340              :     }
     341              :   }
     342            0 :   return GNUNET_OK;
     343              : }
     344              : 
     345              : 
     346              : enum TALER_ErrorCode
     347            0 : TALER_EXCHANGE_get_aml_attributes_start (
     348              :   struct TALER_EXCHANGE_GetAmlAttributesHandle *aagh,
     349              :   TALER_EXCHANGE_GetAmlAttributesCallback cb,
     350              :   TALER_EXCHANGE_GET_AML_ATTRIBUTES_RESULT_CLOSURE *cb_cls)
     351              : {
     352              :   struct TALER_AmlOfficerSignatureP officer_sig;
     353              :   char arg_str[sizeof (aagh->officer_pub) * 2
     354              :                + sizeof (aagh->h_payto) * 2
     355              :                + 32];
     356              :   CURL *eh;
     357              : 
     358            0 :   if (NULL != aagh->job)
     359              :   {
     360            0 :     GNUNET_break (0);
     361            0 :     return TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE;
     362              :   }
     363            0 :   aagh->cb = cb;
     364            0 :   aagh->cb_cls = cb_cls;
     365            0 :   TALER_officer_aml_query_sign (&aagh->officer_priv,
     366              :                                 &officer_sig);
     367              :   {
     368              :     char payto_s[sizeof (aagh->h_payto) * 2];
     369              :     char pub_str[sizeof (aagh->officer_pub) * 2];
     370              :     char *end;
     371              : 
     372            0 :     end = GNUNET_STRINGS_data_to_string (
     373            0 :       &aagh->h_payto,
     374              :       sizeof (aagh->h_payto),
     375              :       payto_s,
     376              :       sizeof (payto_s));
     377            0 :     *end = '\0';
     378            0 :     end = GNUNET_STRINGS_data_to_string (
     379            0 :       &aagh->officer_pub,
     380              :       sizeof (aagh->officer_pub),
     381              :       pub_str,
     382              :       sizeof (pub_str));
     383            0 :     *end = '\0';
     384            0 :     GNUNET_snprintf (arg_str,
     385              :                      sizeof (arg_str),
     386              :                      "aml/%s/attributes/%s",
     387              :                      pub_str,
     388              :                      payto_s);
     389              :   }
     390              :   {
     391              :     char limit_s[24];
     392              :     char offset_s[24];
     393              : 
     394            0 :     GNUNET_snprintf (limit_s,
     395              :                      sizeof (limit_s),
     396              :                      "%lld",
     397            0 :                      (long long) aagh->options.limit);
     398            0 :     GNUNET_snprintf (offset_s,
     399              :                      sizeof (offset_s),
     400              :                      "%llu",
     401            0 :                      (unsigned long long) aagh->options.offset);
     402            0 :     aagh->url = TALER_url_join (aagh->base_url,
     403              :                                 arg_str,
     404              :                                 "limit",
     405              :                                 limit_s,
     406              :                                 "offset",
     407              :                                 offset_s,
     408              :                                 NULL);
     409              :   }
     410            0 :   if (NULL == aagh->url)
     411            0 :     return TALER_EC_GENERIC_CONFIGURATION_INVALID;
     412            0 :   eh = TALER_EXCHANGE_curl_easy_get_ (aagh->url);
     413            0 :   if (NULL == eh)
     414              :   {
     415            0 :     GNUNET_free (aagh->url);
     416            0 :     aagh->url = NULL;
     417            0 :     return TALER_EC_GENERIC_CONFIGURATION_INVALID;
     418              :   }
     419              :   {
     420            0 :     struct curl_slist *job_headers = NULL;
     421              :     char *hdr;
     422              :     char sig_str[sizeof (officer_sig) * 2];
     423              :     char *end;
     424              : 
     425            0 :     end = GNUNET_STRINGS_data_to_string (
     426              :       &officer_sig,
     427              :       sizeof (officer_sig),
     428              :       sig_str,
     429              :       sizeof (sig_str));
     430            0 :     *end = '\0';
     431            0 :     GNUNET_asprintf (&hdr,
     432              :                      "%s: %s",
     433              :                      TALER_AML_OFFICER_SIGNATURE_HEADER,
     434              :                      sig_str);
     435            0 :     job_headers = curl_slist_append (NULL,
     436              :                                      hdr);
     437            0 :     GNUNET_free (hdr);
     438            0 :     job_headers = curl_slist_append (job_headers,
     439              :                                      "Content-type: application/json");
     440            0 :     aagh->job = GNUNET_CURL_job_add2 (aagh->ctx,
     441              :                                       eh,
     442              :                                       job_headers,
     443              :                                       &handle_get_aml_attributes_finished,
     444              :                                       aagh);
     445            0 :     curl_slist_free_all (job_headers);
     446              :   }
     447            0 :   if (NULL == aagh->job)
     448              :   {
     449            0 :     GNUNET_free (aagh->url);
     450            0 :     aagh->url = NULL;
     451            0 :     return TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE;
     452              :   }
     453            0 :   return TALER_EC_NONE;
     454              : }
     455              : 
     456              : 
     457              : void
     458            0 : TALER_EXCHANGE_get_aml_attributes_cancel (
     459              :   struct TALER_EXCHANGE_GetAmlAttributesHandle *aagh)
     460              : {
     461            0 :   if (NULL != aagh->job)
     462              :   {
     463            0 :     GNUNET_CURL_job_cancel (aagh->job);
     464            0 :     aagh->job = NULL;
     465              :   }
     466            0 :   GNUNET_free (aagh->url);
     467            0 :   GNUNET_free (aagh->base_url);
     468            0 :   GNUNET_free (aagh);
     469            0 : }
     470              : 
     471              : 
     472              : /* end of exchange_api_lookup_kyc_attributes.c */
        

Generated by: LCOV version 2.0-1