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

          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 "platform.h"
      23             : #include "taler_json_lib.h"
      24             : #include <microhttpd.h>
      25             : #include <gnunet/gnunet_curl_lib.h>
      26             : #include "taler_exchange_service.h"
      27             : #include "exchange_api_curl_defaults.h"
      28             : #include "taler_signatures.h"
      29             : #include "taler_curl_lib.h"
      30             : #include "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_string ("prog_name",
     218             :                                mi->prog_name),
     219             :       GNUNET_JSON_pack_allow_null (
     220             :         GNUNET_JSON_pack_object_incref ("context",
     221             :                                         (json_t *) mi->context))
     222             :       );
     223           1 :     GNUNET_break (0 ==
     224             :                   json_object_set_new (jmeasures,
     225             :                                        mi->measure_name,
     226             :                                        measure));
     227             :   }
     228             : 
     229           3 :   new_rules = GNUNET_JSON_PACK (
     230             :     GNUNET_JSON_pack_timestamp ("expiration_time",
     231             :                                 expiration_time),
     232             :     GNUNET_JSON_pack_allow_null (
     233             :       GNUNET_JSON_pack_string ("successor_measure",
     234             :                                successor_measure)),
     235             :     GNUNET_JSON_pack_array_steal ("rules",
     236             :                                   jrules),
     237             :     GNUNET_JSON_pack_object_steal ("custom_measures",
     238             :                                    jmeasures)
     239             :     );
     240             : 
     241           3 :   GNUNET_CRYPTO_eddsa_key_get_public (
     242             :     &officer_priv->eddsa_priv,
     243             :     &officer_pub.eddsa_pub);
     244           3 :   TALER_officer_aml_decision_sign (justification,
     245             :                                    decision_time,
     246             :                                    h_payto,
     247             :                                    new_rules,
     248             :                                    properties,
     249             :                                    new_measures,
     250             :                                    keep_investigating,
     251             :                                    officer_priv,
     252             :                                    &officer_sig);
     253           3 :   wh = GNUNET_new (struct TALER_EXCHANGE_AddAmlDecision);
     254           3 :   wh->cb = cb;
     255           3 :   wh->cb_cls = cb_cls;
     256           3 :   wh->ctx = ctx;
     257             :   {
     258             :     char *path;
     259             :     char opus[sizeof (officer_pub) * 2];
     260             :     char *end;
     261             : 
     262           3 :     end = GNUNET_STRINGS_data_to_string (
     263             :       &officer_pub,
     264             :       sizeof (officer_pub),
     265             :       opus,
     266             :       sizeof (opus));
     267           3 :     *end = '\0';
     268           3 :     GNUNET_asprintf (&path,
     269             :                      "aml/%s/decision",
     270             :                      opus);
     271           3 :     wh->url = TALER_url_join (url,
     272             :                               path,
     273             :                               NULL);
     274           3 :     GNUNET_free (path);
     275             :   }
     276           3 :   if (NULL == wh->url)
     277             :   {
     278           0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     279             :                 "Could not construct request URL.\n");
     280           0 :     GNUNET_free (wh);
     281           0 :     json_decref (new_rules);
     282           0 :     return NULL;
     283             :   }
     284           3 :   body = GNUNET_JSON_PACK (
     285             :     GNUNET_JSON_pack_string ("justification",
     286             :                              justification),
     287             :     GNUNET_JSON_pack_data_auto ("h_payto",
     288             :                                 h_payto),
     289             :     GNUNET_JSON_pack_allow_null (
     290             :       TALER_JSON_pack_full_payto ("payto_uri",
     291             :                                   payto_uri)),
     292             :     GNUNET_JSON_pack_object_steal ("new_rules",
     293             :                                    new_rules),
     294             :     GNUNET_JSON_pack_object_incref ("properties",
     295             :                                     (json_t *) properties),
     296             :     GNUNET_JSON_pack_allow_null (
     297             :       GNUNET_JSON_pack_string ("new_measures",
     298             :                                new_measures)),
     299             :     GNUNET_JSON_pack_bool ("keep_investigating",
     300             :                            keep_investigating),
     301             :     GNUNET_JSON_pack_data_auto ("officer_sig",
     302             :                                 &officer_sig),
     303             :     GNUNET_JSON_pack_timestamp ("decision_time",
     304             :                                 decision_time));
     305           3 :   eh = TALER_EXCHANGE_curl_easy_get_ (wh->url);
     306           6 :   if ( (NULL == eh) ||
     307             :        (GNUNET_OK !=
     308           3 :         TALER_curl_easy_post (&wh->post_ctx,
     309             :                               eh,
     310             :                               body)) )
     311             :   {
     312           0 :     GNUNET_break (0);
     313           0 :     if (NULL != eh)
     314           0 :       curl_easy_cleanup (eh);
     315           0 :     json_decref (body);
     316           0 :     GNUNET_free (wh->url);
     317           0 :     return NULL;
     318             :   }
     319           3 :   json_decref (body);
     320           3 :   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
     321             :               "Requesting URL '%s'\n",
     322             :               wh->url);
     323           6 :   wh->job = GNUNET_CURL_job_add2 (ctx,
     324             :                                   eh,
     325           3 :                                   wh->post_ctx.headers,
     326             :                                   &handle_add_aml_decision_finished,
     327             :                                   wh);
     328           3 :   if (NULL == wh->job)
     329             :   {
     330           0 :     TALER_EXCHANGE_post_aml_decision_cancel (wh);
     331           0 :     return NULL;
     332             :   }
     333           3 :   return wh;
     334             : }
     335             : 
     336             : 
     337             : void
     338           3 : TALER_EXCHANGE_post_aml_decision_cancel (
     339             :   struct TALER_EXCHANGE_AddAmlDecision *wh)
     340             : {
     341           3 :   if (NULL != wh->job)
     342             :   {
     343           0 :     GNUNET_CURL_job_cancel (wh->job);
     344           0 :     wh->job = NULL;
     345             :   }
     346           3 :   TALER_curl_easy_post_finished (&wh->post_ctx);
     347           3 :   GNUNET_free (wh->url);
     348           3 :   GNUNET_free (wh);
     349           3 : }

Generated by: LCOV version 1.16