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 % 163 0
Test Date: 2026-04-04 21:36:01 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 (
     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_bool ("by_aml_officer",
     130              :                              &by_aml_officer),
     131            0 :       GNUNET_JSON_spec_mark_optional (
     132              :         GNUNET_JSON_spec_object_const ("attributes",
     133              :                                        &detail->attributes),
     134              :         NULL),
     135            0 :       GNUNET_JSON_spec_timestamp ("collection_time",
     136              :                                   &detail->collection_time),
     137            0 :       GNUNET_JSON_spec_end ()
     138              :     };
     139              : 
     140            0 :     detail->by_aml_officer = false;
     141            0 :     detail->attributes = NULL;
     142            0 :     if (GNUNET_OK !=
     143            0 :         GNUNET_JSON_parse (obj,
     144              :                            spec,
     145              :                            NULL,
     146              :                            NULL))
     147              :     {
     148            0 :       GNUNET_break_op (0);
     149            0 :       return GNUNET_SYSERR;
     150              :     }
     151            0 :     detail->by_aml_officer = by_aml_officer;
     152              :   }
     153            0 :   return GNUNET_OK;
     154              : }
     155              : 
     156              : 
     157              : /**
     158              :  * Parse the provided data from the "200 OK" response.
     159              :  *
     160              :  * @param[in,out] aagh handle (callback may be zero'ed out)
     161              :  * @param json json reply with the data
     162              :  * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
     163              :  */
     164              : static enum GNUNET_GenericReturnValue
     165            0 : parse_get_aml_attributes_ok (
     166              :   struct TALER_EXCHANGE_GetAmlAttributesHandle *aagh,
     167              :   const json_t *json)
     168              : {
     169            0 :   struct TALER_EXCHANGE_GetAmlAttributesResponse lr = {
     170              :     .hr.reply = json,
     171              :     .hr.http_status = MHD_HTTP_OK
     172              :   };
     173              :   const json_t *jdetails;
     174              :   struct GNUNET_JSON_Specification spec[] = {
     175            0 :     GNUNET_JSON_spec_array_const ("details",
     176              :                                   &jdetails),
     177            0 :     GNUNET_JSON_spec_end ()
     178              :   };
     179              : 
     180            0 :   if (GNUNET_OK !=
     181            0 :       GNUNET_JSON_parse (json,
     182              :                          spec,
     183              :                          NULL,
     184              :                          NULL))
     185              :   {
     186            0 :     GNUNET_break_op (0);
     187            0 :     return GNUNET_SYSERR;
     188              :   }
     189            0 :   lr.details.ok.details_length = json_array_size (jdetails);
     190            0 :   {
     191            0 :     struct TALER_EXCHANGE_GetAmlAttributesCollectionEvent details[
     192            0 :       GNUNET_NZL (lr.details.ok.details_length)];
     193              : 
     194            0 :     memset (details,
     195              :             0,
     196              :             sizeof (details));
     197            0 :     lr.details.ok.details = details;
     198            0 :     if (GNUNET_OK !=
     199            0 :         parse_attributes (jdetails,
     200              :                           details))
     201              :     {
     202            0 :       GNUNET_break_op (0);
     203            0 :       return GNUNET_SYSERR;
     204              :     }
     205            0 :     aagh->cb (aagh->cb_cls,
     206              :               &lr);
     207            0 :     aagh->cb = NULL;
     208              :   }
     209            0 :   return GNUNET_OK;
     210              : }
     211              : 
     212              : 
     213              : /**
     214              :  * Function called when we're done processing the
     215              :  * HTTP GET /aml/$OFFICER_PUB/attributes/$H_NORMALIZED_PAYTO request (new API).
     216              :  *
     217              :  * @param cls the `struct TALER_EXCHANGE_GetAmlAttributesHandle`
     218              :  * @param response_code HTTP response code, 0 on error
     219              :  * @param response parsed JSON result, NULL on error
     220              :  */
     221              : static void
     222            0 : handle_get_aml_attributes_finished (void *cls,
     223              :                                     long response_code,
     224              :                                     const void *response)
     225              : {
     226            0 :   struct TALER_EXCHANGE_GetAmlAttributesHandle *aagh = cls;
     227            0 :   const json_t *j = response;
     228            0 :   struct TALER_EXCHANGE_GetAmlAttributesResponse lr = {
     229              :     .hr.reply = j,
     230            0 :     .hr.http_status = (unsigned int) response_code
     231              :   };
     232              : 
     233            0 :   aagh->job = NULL;
     234            0 :   switch (response_code)
     235              :   {
     236            0 :   case 0:
     237            0 :     lr.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
     238            0 :     break;
     239            0 :   case MHD_HTTP_OK:
     240            0 :     if (GNUNET_OK !=
     241            0 :         parse_get_aml_attributes_ok (aagh,
     242              :                                      j))
     243              :     {
     244            0 :       GNUNET_break_op (0);
     245            0 :       lr.hr.http_status = 0;
     246            0 :       lr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED;
     247            0 :       break;
     248              :     }
     249            0 :     GNUNET_assert (NULL == aagh->cb);
     250            0 :     TALER_EXCHANGE_get_aml_attributes_cancel (aagh);
     251            0 :     return;
     252            0 :   case MHD_HTTP_NO_CONTENT:
     253            0 :     break;
     254            0 :   case MHD_HTTP_NOT_IMPLEMENTED:
     255            0 :     lr.hr.ec = TALER_JSON_get_error_code (j);
     256            0 :     lr.hr.hint = TALER_JSON_get_error_hint (j);
     257            0 :     break;
     258            0 :   case MHD_HTTP_BAD_REQUEST:
     259            0 :     lr.hr.ec = TALER_JSON_get_error_code (j);
     260            0 :     lr.hr.hint = TALER_JSON_get_error_hint (j);
     261              :     /* This should never happen, either us or the exchange is buggy
     262              :        (or API version conflict); just pass JSON reply to the application */
     263            0 :     break;
     264            0 :   case MHD_HTTP_FORBIDDEN:
     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_NOT_FOUND:
     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_INTERNAL_SERVER_ERROR:
     273            0 :     lr.hr.ec = TALER_JSON_get_error_code (j);
     274            0 :     lr.hr.hint = TALER_JSON_get_error_hint (j);
     275              :     /* Server had an internal issue; we should retry, but this API
     276              :        leaves this to the application */
     277            0 :     break;
     278            0 :   default:
     279              :     /* unexpected response code */
     280            0 :     GNUNET_break_op (0);
     281            0 :     lr.hr.ec = TALER_JSON_get_error_code (j);
     282            0 :     lr.hr.hint = TALER_JSON_get_error_hint (j);
     283            0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     284              :                 "Unexpected response code %u/%d for get AML attributes\n",
     285              :                 (unsigned int) response_code,
     286              :                 (int) lr.hr.ec);
     287            0 :     break;
     288              :   }
     289            0 :   if (NULL != aagh->cb)
     290            0 :     aagh->cb (aagh->cb_cls,
     291              :               &lr);
     292            0 :   TALER_EXCHANGE_get_aml_attributes_cancel (aagh);
     293              : }
     294              : 
     295              : 
     296              : struct TALER_EXCHANGE_GetAmlAttributesHandle *
     297            0 : TALER_EXCHANGE_get_aml_attributes_create (
     298              :   struct GNUNET_CURL_Context *ctx,
     299              :   const char *url,
     300              :   const struct TALER_AmlOfficerPrivateKeyP *officer_priv,
     301              :   const struct TALER_NormalizedPaytoHashP *h_payto)
     302              : {
     303              :   struct TALER_EXCHANGE_GetAmlAttributesHandle *aagh;
     304              : 
     305            0 :   aagh = GNUNET_new (struct TALER_EXCHANGE_GetAmlAttributesHandle);
     306            0 :   aagh->ctx = ctx;
     307            0 :   aagh->base_url = GNUNET_strdup (url);
     308            0 :   aagh->h_payto = *h_payto;
     309            0 :   aagh->officer_priv = *officer_priv;
     310            0 :   GNUNET_CRYPTO_eddsa_key_get_public (&officer_priv->eddsa_priv,
     311              :                                       &aagh->officer_pub.eddsa_pub);
     312            0 :   aagh->options.limit = -20;
     313            0 :   aagh->options.offset = INT64_MAX;
     314            0 :   return aagh;
     315              : }
     316              : 
     317              : 
     318              : enum GNUNET_GenericReturnValue
     319            0 : TALER_EXCHANGE_get_aml_attributes_set_options_ (
     320              :   struct TALER_EXCHANGE_GetAmlAttributesHandle *aagh,
     321              :   unsigned int num_options,
     322              :   const struct TALER_EXCHANGE_GetAmlAttributesOptionValue *options)
     323              : {
     324            0 :   for (unsigned int i = 0; i < num_options; i++)
     325              :   {
     326            0 :     const struct TALER_EXCHANGE_GetAmlAttributesOptionValue *opt = &options[i];
     327              : 
     328            0 :     switch (opt->option)
     329              :     {
     330            0 :     case TALER_EXCHANGE_GET_AML_ATTRIBUTES_OPTION_END:
     331            0 :       return GNUNET_OK;
     332            0 :     case TALER_EXCHANGE_GET_AML_ATTRIBUTES_OPTION_LIMIT:
     333            0 :       aagh->options.limit = opt->details.limit;
     334            0 :       break;
     335            0 :     case TALER_EXCHANGE_GET_AML_ATTRIBUTES_OPTION_OFFSET:
     336            0 :       if (opt->details.offset > INT64_MAX)
     337              :       {
     338            0 :         GNUNET_break (0);
     339            0 :         return GNUNET_NO;
     340              :       }
     341            0 :       aagh->options.offset = opt->details.offset;
     342            0 :       break;
     343              :     }
     344              :   }
     345            0 :   return GNUNET_OK;
     346              : }
     347              : 
     348              : 
     349              : enum TALER_ErrorCode
     350            0 : TALER_EXCHANGE_get_aml_attributes_start (
     351              :   struct TALER_EXCHANGE_GetAmlAttributesHandle *aagh,
     352              :   TALER_EXCHANGE_GetAmlAttributesCallback cb,
     353              :   TALER_EXCHANGE_GET_AML_ATTRIBUTES_RESULT_CLOSURE *cb_cls)
     354              : {
     355              :   struct TALER_AmlOfficerSignatureP officer_sig;
     356              :   char arg_str[sizeof (aagh->officer_pub) * 2
     357              :                + sizeof (aagh->h_payto) * 2
     358              :                + 32];
     359              :   CURL *eh;
     360              : 
     361            0 :   if (NULL != aagh->job)
     362              :   {
     363            0 :     GNUNET_break (0);
     364            0 :     return TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE;
     365              :   }
     366            0 :   aagh->cb = cb;
     367            0 :   aagh->cb_cls = cb_cls;
     368            0 :   TALER_officer_aml_query_sign (&aagh->officer_priv,
     369              :                                 &officer_sig);
     370              :   {
     371              :     char payto_s[sizeof (aagh->h_payto) * 2];
     372              :     char pub_str[sizeof (aagh->officer_pub) * 2];
     373              :     char *end;
     374              : 
     375            0 :     end = GNUNET_STRINGS_data_to_string (
     376            0 :       &aagh->h_payto,
     377              :       sizeof (aagh->h_payto),
     378              :       payto_s,
     379              :       sizeof (payto_s));
     380            0 :     *end = '\0';
     381            0 :     end = GNUNET_STRINGS_data_to_string (
     382            0 :       &aagh->officer_pub,
     383              :       sizeof (aagh->officer_pub),
     384              :       pub_str,
     385              :       sizeof (pub_str));
     386            0 :     *end = '\0';
     387            0 :     GNUNET_snprintf (arg_str,
     388              :                      sizeof (arg_str),
     389              :                      "aml/%s/attributes/%s",
     390              :                      pub_str,
     391              :                      payto_s);
     392              :   }
     393              :   {
     394              :     char limit_s[24];
     395              :     char offset_s[24];
     396              : 
     397            0 :     GNUNET_snprintf (limit_s,
     398              :                      sizeof (limit_s),
     399              :                      "%lld",
     400            0 :                      (long long) aagh->options.limit);
     401            0 :     GNUNET_snprintf (offset_s,
     402              :                      sizeof (offset_s),
     403              :                      "%llu",
     404            0 :                      (unsigned long long) aagh->options.offset);
     405            0 :     aagh->url = TALER_url_join (aagh->base_url,
     406              :                                 arg_str,
     407              :                                 "limit",
     408              :                                 limit_s,
     409              :                                 "offset",
     410              :                                 offset_s,
     411              :                                 NULL);
     412              :   }
     413            0 :   if (NULL == aagh->url)
     414            0 :     return TALER_EC_GENERIC_CONFIGURATION_INVALID;
     415            0 :   eh = TALER_EXCHANGE_curl_easy_get_ (aagh->url);
     416            0 :   if (NULL == eh)
     417              :   {
     418            0 :     GNUNET_free (aagh->url);
     419            0 :     aagh->url = NULL;
     420            0 :     return TALER_EC_GENERIC_CONFIGURATION_INVALID;
     421              :   }
     422              :   {
     423            0 :     struct curl_slist *job_headers = NULL;
     424              :     char *hdr;
     425              :     char sig_str[sizeof (officer_sig) * 2];
     426              :     char *end;
     427              : 
     428            0 :     end = GNUNET_STRINGS_data_to_string (
     429              :       &officer_sig,
     430              :       sizeof (officer_sig),
     431              :       sig_str,
     432              :       sizeof (sig_str));
     433            0 :     *end = '\0';
     434            0 :     GNUNET_asprintf (&hdr,
     435              :                      "%s: %s",
     436              :                      TALER_AML_OFFICER_SIGNATURE_HEADER,
     437              :                      sig_str);
     438            0 :     job_headers = curl_slist_append (NULL,
     439              :                                      hdr);
     440            0 :     GNUNET_free (hdr);
     441            0 :     aagh->job = GNUNET_CURL_job_add2 (aagh->ctx,
     442              :                                       eh,
     443              :                                       job_headers,
     444              :                                       &handle_get_aml_attributes_finished,
     445              :                                       aagh);
     446            0 :     curl_slist_free_all (job_headers);
     447              :   }
     448            0 :   if (NULL == aagh->job)
     449              :   {
     450            0 :     GNUNET_free (aagh->url);
     451            0 :     aagh->url = NULL;
     452            0 :     return TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE;
     453              :   }
     454            0 :   return TALER_EC_NONE;
     455              : }
     456              : 
     457              : 
     458              : void
     459            0 : TALER_EXCHANGE_get_aml_attributes_cancel (
     460              :   struct TALER_EXCHANGE_GetAmlAttributesHandle *aagh)
     461              : {
     462            0 :   if (NULL != aagh->job)
     463              :   {
     464            0 :     GNUNET_CURL_job_cancel (aagh->job);
     465            0 :     aagh->job = NULL;
     466              :   }
     467            0 :   GNUNET_free (aagh->url);
     468            0 :   GNUNET_free (aagh->base_url);
     469            0 :   GNUNET_free (aagh);
     470            0 : }
     471              : 
     472              : 
     473              : /* end of exchange_api_lookup_kyc_attributes.c */
        

Generated by: LCOV version 2.0-1