LCOV - code coverage report
Current view: top level - lib - exchange_api_add_aml_decision.c (source / functions) Coverage Total Hit
Test: coverage.info Lines: 67.3 % 98 66
Test Date: 2025-12-28 14:06:02 Functions: 100.0 % 3 3

            Line data    Source code
       1              : /*
       2              :   This file is part of TALER
       3              :   Copyright (C) 2023, 2024 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_add_aml_decision.c
      19              :  * @brief functions to add an AML decision by an AML officer
      20              :  * @author Christian Grothoff
      21              :  */
      22              : #include "taler/platform.h"
      23              : #include "taler/taler_json_lib.h"
      24              : #include <microhttpd.h>
      25              : #include <gnunet/gnunet_curl_lib.h>
      26              : #include "taler/taler_exchange_service.h"
      27              : #include "exchange_api_curl_defaults.h"
      28              : #include "taler/taler_signatures.h"
      29              : #include "taler/taler_curl_lib.h"
      30              : #include "taler/taler_json_lib.h"
      31              : 
      32              : 
      33              : struct TALER_EXCHANGE_AddAmlDecision
      34              : {
      35              : 
      36              :   /**
      37              :    * The url for this request.
      38              :    */
      39              :   char *url;
      40              : 
      41              :   /**
      42              :    * Minor context that holds body and headers.
      43              :    */
      44              :   struct TALER_CURL_PostContext post_ctx;
      45              : 
      46              :   /**
      47              :    * Handle for the request.
      48              :    */
      49              :   struct GNUNET_CURL_Job *job;
      50              : 
      51              :   /**
      52              :    * Function to call with the result.
      53              :    */
      54              :   TALER_EXCHANGE_AddAmlDecisionCallback cb;
      55              : 
      56              :   /**
      57              :    * Closure for @a cb.
      58              :    */
      59              :   void *cb_cls;
      60              : 
      61              :   /**
      62              :    * Reference to the execution context.
      63              :    */
      64              :   struct GNUNET_CURL_Context *ctx;
      65              : };
      66              : 
      67              : 
      68              : /**
      69              :  * Function called when we're done processing the
      70              :  * HTTP POST /aml/$OFFICER_PUB/decision request.
      71              :  *
      72              :  * @param cls the `struct TALER_EXCHANGE_AddAmlDecision *`
      73              :  * @param response_code HTTP response code, 0 on error
      74              :  * @param response response body, NULL if not in JSON
      75              :  */
      76              : static void
      77            3 : handle_add_aml_decision_finished (void *cls,
      78              :                                   long response_code,
      79              :                                   const void *response)
      80              : {
      81            3 :   struct TALER_EXCHANGE_AddAmlDecision *wh = cls;
      82            3 :   const json_t *json = response;
      83            3 :   struct TALER_EXCHANGE_AddAmlDecisionResponse adr = {
      84            3 :     .hr.http_status = (unsigned int) response_code,
      85              :     .hr.reply = json
      86              :   };
      87              : 
      88            3 :   wh->job = NULL;
      89            3 :   switch (response_code)
      90              :   {
      91            0 :   case 0:
      92              :     /* no reply */
      93            0 :     adr.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
      94            0 :     adr.hr.hint = "server offline?";
      95            0 :     break;
      96            2 :   case MHD_HTTP_NO_CONTENT:
      97            2 :     break;
      98            1 :   case MHD_HTTP_FORBIDDEN:
      99            1 :     adr.hr.ec = TALER_JSON_get_error_code (json);
     100            1 :     adr.hr.hint = TALER_JSON_get_error_hint (json);
     101            1 :     break;
     102            0 :   case MHD_HTTP_CONFLICT:
     103            0 :     adr.hr.ec = TALER_JSON_get_error_code (json);
     104            0 :     adr.hr.hint = TALER_JSON_get_error_hint (json);
     105            0 :     break;
     106            0 :   default:
     107              :     /* unexpected response code */
     108            0 :     GNUNET_break_op (0);
     109            0 :     adr.hr.ec = TALER_JSON_get_error_code (json);
     110            0 :     adr.hr.hint = TALER_JSON_get_error_hint (json);
     111            0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     112              :                 "Unexpected response code %u/%d for exchange AML decision\n",
     113              :                 (unsigned int) response_code,
     114              :                 (int) adr.hr.ec);
     115            0 :     break;
     116              :   }
     117            3 :   if (NULL != wh->cb)
     118              :   {
     119            3 :     wh->cb (wh->cb_cls,
     120              :             &adr);
     121            3 :     wh->cb = NULL;
     122              :   }
     123            3 :   TALER_EXCHANGE_post_aml_decision_cancel (wh);
     124            3 : }
     125              : 
     126              : 
     127              : struct TALER_EXCHANGE_AddAmlDecision *
     128            3 : TALER_EXCHANGE_post_aml_decision (
     129              :   struct GNUNET_CURL_Context *ctx,
     130              :   const char *url,
     131              :   const struct TALER_NormalizedPaytoHashP *h_payto,
     132              :   const struct TALER_FullPayto payto_uri,
     133              :   struct GNUNET_TIME_Timestamp decision_time,
     134              :   const char *successor_measure,
     135              :   const char *new_measures,
     136              :   struct GNUNET_TIME_Timestamp expiration_time,
     137              :   unsigned int num_rules,
     138              :   const struct TALER_EXCHANGE_AccountRule *rules,
     139              :   unsigned int num_measures,
     140              :   const struct TALER_EXCHANGE_MeasureInformation *measures,
     141              :   const json_t *properties,
     142              :   bool keep_investigating,
     143              :   const char *justification,
     144              :   const struct TALER_AmlOfficerPrivateKeyP *officer_priv,
     145              :   unsigned int num_events,
     146              :   const char **events,
     147              :   TALER_EXCHANGE_AddAmlDecisionCallback cb,
     148              :   void *cb_cls)
     149              : {
     150              :   struct TALER_AmlOfficerPublicKeyP officer_pub;
     151              :   struct TALER_AmlOfficerSignatureP officer_sig;
     152              :   struct TALER_EXCHANGE_AddAmlDecision *wh;
     153              :   CURL *eh;
     154              :   json_t *body;
     155              :   json_t *new_rules;
     156              :   json_t *jrules;
     157              :   json_t *jmeasures;
     158            3 :   json_t *jevents = NULL;
     159              : 
     160            3 :   if (0 != num_events)
     161              :   {
     162            0 :     jevents = json_array ();
     163            0 :     GNUNET_assert (NULL != jevents);
     164            0 :     for (unsigned int i = 0; i<num_events; i++)
     165            0 :       GNUNET_assert (0 ==
     166              :                      json_array_append_new (jevents,
     167              :                                             json_string (events[i])));
     168              :   }
     169            3 :   jrules = json_array ();
     170            3 :   GNUNET_assert (NULL != jrules);
     171            6 :   for (unsigned int i = 0; i<num_rules; i++)
     172              :   {
     173            3 :     const struct TALER_EXCHANGE_AccountRule *al = &rules[i];
     174              :     json_t *rule;
     175              :     json_t *ameasures;
     176              : 
     177            3 :     ameasures = json_array ();
     178            3 :     GNUNET_assert (NULL != ameasures);
     179            4 :     for (unsigned int j = 0; j<al->num_measures; j++)
     180            1 :       GNUNET_assert (0 ==
     181              :                      json_array_append_new (ameasures,
     182              :                                             json_string (al->measures[j])));
     183            3 :     rule = GNUNET_JSON_PACK (
     184              :       TALER_JSON_pack_kycte ("operation_type",
     185              :                              al->operation_type),
     186              :       TALER_JSON_pack_amount ("threshold",
     187              :                               &al->threshold),
     188              :       GNUNET_JSON_pack_time_rel ("timeframe",
     189              :                                  al->timeframe),
     190              :       GNUNET_JSON_pack_array_steal ("measures",
     191              :                                     ameasures),
     192              :       GNUNET_JSON_pack_allow_null (
     193              :         GNUNET_JSON_pack_array_steal ("events",
     194              :                                       jevents)),
     195              :       GNUNET_JSON_pack_bool ("exposed",
     196              :                              al->exposed),
     197              :       GNUNET_JSON_pack_bool ("is_and_combinator",
     198              :                              al->is_and_combinator),
     199              :       GNUNET_JSON_pack_uint64 ("display_priority",
     200              :                                al->display_priority)
     201              :       );
     202            3 :     GNUNET_break (0 ==
     203              :                   json_array_append_new (jrules,
     204              :                                          rule));
     205              :   }
     206              : 
     207            3 :   jmeasures = json_object ();
     208            3 :   GNUNET_assert (NULL != jmeasures);
     209            4 :   for (unsigned int i = 0; i<num_measures; i++)
     210              :   {
     211            1 :     const struct TALER_EXCHANGE_MeasureInformation *mi = &measures[i];
     212              :     json_t *measure;
     213              : 
     214            1 :     measure = GNUNET_JSON_PACK (
     215              :       GNUNET_JSON_pack_string ("check_name",
     216              :                                mi->check_name),
     217              :       GNUNET_JSON_pack_allow_null (
     218              :         GNUNET_JSON_pack_string ("prog_name",
     219              :                                  mi->prog_name)),
     220              :       GNUNET_JSON_pack_allow_null (
     221              :         GNUNET_JSON_pack_object_incref ("context",
     222              :                                         (json_t *) mi->context))
     223              :       );
     224            1 :     GNUNET_break (0 ==
     225              :                   json_object_set_new (jmeasures,
     226              :                                        mi->measure_name,
     227              :                                        measure));
     228              :   }
     229              : 
     230            3 :   new_rules = GNUNET_JSON_PACK (
     231              :     GNUNET_JSON_pack_timestamp ("expiration_time",
     232              :                                 expiration_time),
     233              :     GNUNET_JSON_pack_allow_null (
     234              :       GNUNET_JSON_pack_string ("successor_measure",
     235              :                                successor_measure)),
     236              :     GNUNET_JSON_pack_array_steal ("rules",
     237              :                                   jrules),
     238              :     GNUNET_JSON_pack_object_steal ("custom_measures",
     239              :                                    jmeasures)
     240              :     );
     241              : 
     242            3 :   GNUNET_CRYPTO_eddsa_key_get_public (
     243              :     &officer_priv->eddsa_priv,
     244              :     &officer_pub.eddsa_pub);
     245            3 :   TALER_officer_aml_decision_sign (justification,
     246              :                                    decision_time,
     247              :                                    h_payto,
     248              :                                    new_rules,
     249              :                                    properties,
     250              :                                    new_measures,
     251              :                                    keep_investigating,
     252              :                                    officer_priv,
     253              :                                    &officer_sig);
     254            3 :   wh = GNUNET_new (struct TALER_EXCHANGE_AddAmlDecision);
     255            3 :   wh->cb = cb;
     256            3 :   wh->cb_cls = cb_cls;
     257            3 :   wh->ctx = ctx;
     258              :   {
     259              :     char *path;
     260              :     char opus[sizeof (officer_pub) * 2];
     261              :     char *end;
     262              : 
     263            3 :     end = GNUNET_STRINGS_data_to_string (
     264              :       &officer_pub,
     265              :       sizeof (officer_pub),
     266              :       opus,
     267              :       sizeof (opus));
     268            3 :     *end = '\0';
     269            3 :     GNUNET_asprintf (&path,
     270              :                      "aml/%s/decision",
     271              :                      opus);
     272            3 :     wh->url = TALER_url_join (url,
     273              :                               path,
     274              :                               NULL);
     275            3 :     GNUNET_free (path);
     276              :   }
     277            3 :   if (NULL == wh->url)
     278              :   {
     279            0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     280              :                 "Could not construct request URL.\n");
     281            0 :     GNUNET_free (wh);
     282            0 :     json_decref (new_rules);
     283            0 :     return NULL;
     284              :   }
     285            3 :   body = GNUNET_JSON_PACK (
     286              :     GNUNET_JSON_pack_string ("justification",
     287              :                              justification),
     288              :     GNUNET_JSON_pack_data_auto ("h_payto",
     289              :                                 h_payto),
     290              :     GNUNET_JSON_pack_allow_null (
     291              :       TALER_JSON_pack_full_payto ("payto_uri",
     292              :                                   payto_uri)),
     293              :     GNUNET_JSON_pack_object_steal ("new_rules",
     294              :                                    new_rules),
     295              :     GNUNET_JSON_pack_object_incref ("properties",
     296              :                                     (json_t *) properties),
     297              :     GNUNET_JSON_pack_allow_null (
     298              :       GNUNET_JSON_pack_string ("new_measures",
     299              :                                new_measures)),
     300              :     GNUNET_JSON_pack_bool ("keep_investigating",
     301              :                            keep_investigating),
     302              :     GNUNET_JSON_pack_data_auto ("officer_sig",
     303              :                                 &officer_sig),
     304              :     GNUNET_JSON_pack_timestamp ("decision_time",
     305              :                                 decision_time));
     306            3 :   eh = TALER_EXCHANGE_curl_easy_get_ (wh->url);
     307            6 :   if ( (NULL == eh) ||
     308              :        (GNUNET_OK !=
     309            3 :         TALER_curl_easy_post (&wh->post_ctx,
     310              :                               eh,
     311              :                               body)) )
     312              :   {
     313            0 :     GNUNET_break (0);
     314            0 :     if (NULL != eh)
     315            0 :       curl_easy_cleanup (eh);
     316            0 :     json_decref (body);
     317            0 :     GNUNET_free (wh->url);
     318            0 :     return NULL;
     319              :   }
     320            3 :   json_decref (body);
     321            3 :   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
     322              :               "Requesting URL '%s'\n",
     323              :               wh->url);
     324            6 :   wh->job = GNUNET_CURL_job_add2 (ctx,
     325              :                                   eh,
     326            3 :                                   wh->post_ctx.headers,
     327              :                                   &handle_add_aml_decision_finished,
     328              :                                   wh);
     329            3 :   if (NULL == wh->job)
     330              :   {
     331            0 :     TALER_EXCHANGE_post_aml_decision_cancel (wh);
     332            0 :     return NULL;
     333              :   }
     334            3 :   return wh;
     335              : }
     336              : 
     337              : 
     338              : void
     339            3 : TALER_EXCHANGE_post_aml_decision_cancel (
     340              :   struct TALER_EXCHANGE_AddAmlDecision *wh)
     341              : {
     342            3 :   if (NULL != wh->job)
     343              :   {
     344            0 :     GNUNET_CURL_job_cancel (wh->job);
     345            0 :     wh->job = NULL;
     346              :   }
     347            3 :   TALER_curl_easy_post_finished (&wh->post_ctx);
     348            3 :   GNUNET_free (wh->url);
     349            3 :   GNUNET_free (wh);
     350            3 : }
        

Generated by: LCOV version 2.0-1