donau

Donation authority for GNU Taler (experimental)
Log | Files | Refs | Submodules | README | LICENSE

donau_api_batch_submit_receipts.c (7350B)


      1 /*
      2   This file is part of TALER
      3   Copyright (C) 2024 Taler Systems SA
      4 
      5   TALER is free software; you can redistribute it and/or modify it
      6   under the terms of the GNU General Public License as published
      7   by the Free Software Foundation; either version 3, or (at your
      8   option) any later version.
      9 
     10   TALER is distributed in the hope that it will be useful, but
     11   WITHOUT ANY WARRANTY; without even the implied warranty of
     12   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     13   GNU General Public License for more details.
     14 
     15   You should have received a copy of the GNU General Public
     16   License along with TALER; see the file COPYING.  If not, see
     17   <http://www.gnu.org/licenses/>
     18 */
     19 
     20 /**
     21  * @file lib/donau_api_batch_submit_receipts.c
     22  * @brief Implementation of the "handle" component of the donau's HTTP API
     23  * @author Lukas Matyja
     24  */
     25 #include <gnunet/gnunet_curl_lib.h>
     26 #include <taler/taler_json_lib.h>
     27 #include <taler/taler_curl_lib.h>
     28 #include "donau_service.h"
     29 #include "donau_util.h"
     30 #include "donau_api_curl_defaults.h"
     31 #include "donau_json_lib.h"
     32 
     33 
     34 /**
     35  * Handle for a POST /batch-submit request.
     36  */
     37 struct DONAU_DonorReceiptsToStatementHandle
     38 {
     39   /**
     40    * The url for the /batch-submit request.
     41    */
     42   char *url;
     43 
     44   /**
     45    * Minor context that holds body and headers.
     46    */
     47   struct TALER_CURL_PostContext post_ctx;
     48 
     49   /**
     50    * Entry for this request with the `struct GNUNET_CURL_Context`.
     51    */
     52   struct GNUNET_CURL_Job *job;
     53 
     54   /**
     55    * Function to call with the result.
     56    */
     57   DONAU_DonorReceiptsToStatementResultCallback cb;
     58 
     59   /**
     60    * Closure to pass to @e cb.
     61    */
     62   void *cb_cls;
     63 
     64   /**
     65    * Reference to the execution context.
     66    */
     67   struct GNUNET_CURL_Context *ctx;
     68 
     69 };
     70 
     71 /**
     72  * Transform submit receipt request into JSON.
     73  *
     74  * @param num_drs number of donation receipts in @drs
     75  * @param drs donation receipts array
     76  * @param year corresponding year
     77  * @param h_tax_id salted and hashed tax id
     78  */
     79 static json_t *
     80 submit_request_body_to_json (
     81   const size_t num_drs,
     82   const struct DONAU_DonationReceipt drs[num_drs],
     83   const uint64_t year,
     84   const struct DONAU_HashDonorTaxId *h_tax_id)
     85 {
     86   json_t *donation_receipts = json_array ();
     87 
     88   GNUNET_assert (NULL != donation_receipts);
     89   for (size_t i = 0; i < num_drs; i++)
     90   {
     91     json_t *receipt = GNUNET_JSON_PACK (
     92       GNUNET_JSON_pack_data_auto ("h_donation_unit_pub",
     93                                   &drs[i].h_donation_unit_pub),
     94       GNUNET_JSON_pack_data_auto ("nonce",
     95                                   &drs[i].nonce),
     96       DONAU_JSON_pack_donation_unit_sig ("donation_unit_sig",
     97                                          &drs[i].donation_unit_sig));
     98 
     99     GNUNET_assert (0 ==
    100                    json_array_append_new (donation_receipts,
    101                                           receipt));
    102   }
    103   return GNUNET_JSON_PACK (
    104     GNUNET_JSON_pack_array_steal ("donation_receipts",
    105                                   donation_receipts),
    106     GNUNET_JSON_pack_data_auto ("h_donor_tax_id",
    107                                 h_tax_id),
    108     GNUNET_JSON_pack_uint64 ("donation_year",
    109                              year));
    110 }
    111 
    112 
    113 /**
    114  * Function called when we're done processing the
    115  * HTTP POST /batch-submit request.
    116  *
    117  * @param cls the `struct KeysRequest`
    118  * @param response_code HTTP response code, 0 on error
    119  * @param resp_obj parsed JSON result, NULL on error
    120  */
    121 static void
    122 handle_batch_submit_finished (void *cls,
    123                               long response_code,
    124                               const void *resp_obj)
    125 {
    126   struct DONAU_DonorReceiptsToStatementHandle *birh = cls;
    127   const json_t *j = resp_obj;
    128   struct DONAU_DonorReceiptsToStatementResult biresp = {
    129     .hr.reply = j,
    130     .hr.http_status = (unsigned int) response_code
    131   };
    132 
    133   birh->job = NULL;
    134   switch (response_code)
    135   {
    136   case MHD_HTTP_OK:
    137     break;
    138   case MHD_HTTP_NO_CONTENT:
    139     biresp.hr.ec = TALER_JSON_get_error_code (j);
    140     biresp.hr.hint = TALER_JSON_get_error_hint (j);
    141     break;
    142   // One of the signatures is invalid.
    143   case MHD_HTTP_FORBIDDEN:
    144     biresp.hr.ec = TALER_JSON_get_error_code (j);
    145     biresp.hr.hint = TALER_JSON_get_error_hint (j);
    146     break;
    147   // At least one of the donation unit keys is not known to the Donau.
    148   case MHD_HTTP_NOT_FOUND:
    149     biresp.hr.ec = TALER_JSON_get_error_code (j);
    150     biresp.hr.hint = TALER_JSON_get_error_hint (j);
    151     break;
    152   // At least one of the corresponding private keys is deprecated/leaked.
    153   case MHD_HTTP_GONE:
    154     biresp.hr.ec = TALER_JSON_get_error_code (j);
    155     biresp.hr.hint = TALER_JSON_get_error_hint (j);
    156     break;
    157   case MHD_HTTP_CONTENT_TOO_LARGE:
    158     biresp.hr.ec = TALER_JSON_get_error_code (j);
    159     biresp.hr.hint = TALER_JSON_get_error_hint (j);
    160     break;
    161   default:
    162     /* unexpected response code */
    163     GNUNET_break_op (0);
    164     biresp.hr.ec = TALER_JSON_get_error_code (j);
    165     biresp.hr.hint = TALER_JSON_get_error_hint (j);
    166     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    167                 "Unexpected response code %u/%d for POST %s\n",
    168                 (unsigned int) response_code,
    169                 (int) biresp.hr.ec,
    170                 birh->url);
    171     break;
    172   }
    173   if (NULL != birh->cb)
    174   {
    175     birh->cb (birh->cb_cls,
    176               &biresp);
    177     birh->cb = NULL;
    178   }
    179   DONAU_donor_receipts_to_statement_cancel (birh);
    180 }
    181 
    182 
    183 struct DONAU_DonorReceiptsToStatementHandle *
    184 DONAU_donor_receipts_to_statement (
    185   struct GNUNET_CURL_Context *ctx,
    186   const char *url,
    187   const size_t num_drs,
    188   const struct DONAU_DonationReceipt drs[num_drs],
    189   const uint64_t year,
    190   const struct DONAU_HashDonorTaxId *h_tax_id,
    191   DONAU_DonorReceiptsToStatementResultCallback cb,
    192   void *cls)
    193 {
    194   struct DONAU_DonorReceiptsToStatementHandle *birh;
    195   CURL *eh;
    196   json_t *body;
    197 
    198   TALER_LOG_DEBUG ("Connecting to the donau (%s)\n",
    199                    url);
    200   birh = GNUNET_new (struct DONAU_DonorReceiptsToStatementHandle);
    201   birh->url = GNUNET_strdup (url);
    202   birh->cb = cb;
    203   birh->cb_cls = cls;
    204   birh->ctx = ctx;
    205   birh->url = TALER_url_join (url,
    206                               "batch-submit",
    207                               NULL);
    208   if (NULL == birh->url)
    209   {
    210     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    211                 "Could not construct request URL.\n");
    212     GNUNET_free (birh);
    213     return NULL;
    214   }
    215   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
    216               "submit_receipts_with_URL `%s'.\n",
    217               birh->url);
    218   body = submit_request_body_to_json (num_drs, drs, year, h_tax_id);
    219   eh = DONAU_curl_easy_get_ (birh->url);
    220   if ( (NULL == eh) ||
    221        (GNUNET_OK !=
    222         TALER_curl_easy_post (&birh->post_ctx,
    223                               eh,
    224                               body)) )
    225   {
    226     GNUNET_break (0);
    227     if (NULL != eh)
    228       curl_easy_cleanup (eh);
    229     json_decref (body);
    230     GNUNET_free (birh->url);
    231     return NULL;
    232   }
    233   json_decref (body);
    234   birh->job = GNUNET_CURL_job_add2 (ctx,
    235                                     eh,
    236                                     birh->post_ctx.headers,
    237                                     &handle_batch_submit_finished,
    238                                     birh);
    239   return birh;
    240 }
    241 
    242 
    243 void
    244 DONAU_donor_receipts_to_statement_cancel (
    245   struct DONAU_DonorReceiptsToStatementHandle *drsh)
    246 {
    247   if (NULL != drsh->job)
    248   {
    249     GNUNET_CURL_job_cancel (drsh->job);
    250     drsh->job = NULL;
    251   }
    252   TALER_curl_easy_post_finished (&drsh->post_ctx);
    253   GNUNET_free (drsh->url);
    254   GNUNET_free (drsh);
    255 }