donau

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

donau_api_batch_submit_receipts.c (7489B)


      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 @a 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_CREATED:
    137     /* Success: a donation statement is now available (empty body). */
    138     break;
    139   case MHD_HTTP_CONFLICT:
    140     /* A duplicate donor identifier nonce was detected. */
    141     biresp.hr.ec = TALER_JSON_get_error_code (j);
    142     biresp.hr.hint = TALER_JSON_get_error_hint (j);
    143     break;
    144   case MHD_HTTP_FORBIDDEN:
    145     /* One of the signatures is invalid. */
    146     biresp.hr.ec = TALER_JSON_get_error_code (j);
    147     biresp.hr.hint = TALER_JSON_get_error_hint (j);
    148     break;
    149   case MHD_HTTP_NOT_FOUND:
    150     /* At least one of the donation unit keys is not known to the Donau. */
    151     biresp.hr.ec = TALER_JSON_get_error_code (j);
    152     biresp.hr.hint = TALER_JSON_get_error_hint (j);
    153     break;
    154   case MHD_HTTP_GONE:
    155     /* At least one of the corresponding private keys is deprecated/leaked. */
    156     biresp.hr.ec = TALER_JSON_get_error_code (j);
    157     biresp.hr.hint = TALER_JSON_get_error_hint (j);
    158     break;
    159   case MHD_HTTP_CONTENT_TOO_LARGE:
    160     biresp.hr.ec = TALER_JSON_get_error_code (j);
    161     biresp.hr.hint = TALER_JSON_get_error_hint (j);
    162     break;
    163   default:
    164     /* unexpected response code */
    165     GNUNET_break_op (0);
    166     biresp.hr.ec = TALER_JSON_get_error_code (j);
    167     biresp.hr.hint = TALER_JSON_get_error_hint (j);
    168     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    169                 "Unexpected response code %u/%d for POST %s\n",
    170                 (unsigned int) response_code,
    171                 (int) biresp.hr.ec,
    172                 birh->url);
    173     break;
    174   }
    175   if (NULL != birh->cb)
    176   {
    177     birh->cb (birh->cb_cls,
    178               &biresp);
    179     birh->cb = NULL;
    180   }
    181   DONAU_donor_receipts_to_statement_cancel (birh);
    182 }
    183 
    184 
    185 struct DONAU_DonorReceiptsToStatementHandle *
    186 DONAU_donor_receipts_to_statement (
    187   struct GNUNET_CURL_Context *ctx,
    188   const char *url,
    189   const size_t num_drs,
    190   const struct DONAU_DonationReceipt drs[num_drs],
    191   const uint64_t year,
    192   const struct DONAU_HashDonorTaxId *h_tax_id,
    193   DONAU_DonorReceiptsToStatementResultCallback cb,
    194   void *cls)
    195 {
    196   struct DONAU_DonorReceiptsToStatementHandle *birh;
    197   CURL *eh;
    198   json_t *body;
    199 
    200   TALER_LOG_DEBUG ("Connecting to the donau (%s)\n",
    201                    url);
    202   birh = GNUNET_new (struct DONAU_DonorReceiptsToStatementHandle);
    203   birh->cb = cb;
    204   birh->cb_cls = cls;
    205   birh->ctx = ctx;
    206   birh->url = TALER_url_join (url,
    207                               "batch-submit",
    208                               NULL);
    209   if (NULL == birh->url)
    210   {
    211     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    212                 "Could not construct request URL.\n");
    213     GNUNET_free (birh);
    214     return NULL;
    215   }
    216   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
    217               "submit_receipts_with_URL `%s'.\n",
    218               birh->url);
    219   body = submit_request_body_to_json (num_drs, drs, year, h_tax_id);
    220   eh = DONAU_curl_easy_get_ (birh->url);
    221   if ( (NULL == eh) ||
    222        (GNUNET_OK !=
    223         TALER_curl_easy_post (&birh->post_ctx,
    224                               eh,
    225                               body)) )
    226   {
    227     GNUNET_break (0);
    228     if (NULL != eh)
    229       curl_easy_cleanup (eh);
    230     json_decref (body);
    231     GNUNET_free (birh->url);
    232     GNUNET_free (birh);
    233     return NULL;
    234   }
    235   json_decref (body);
    236   birh->job = GNUNET_CURL_job_add2 (ctx,
    237                                     eh,
    238                                     birh->post_ctx.headers,
    239                                     &handle_batch_submit_finished,
    240                                     birh);
    241   return birh;
    242 }
    243 
    244 
    245 void
    246 DONAU_donor_receipts_to_statement_cancel (
    247   struct DONAU_DonorReceiptsToStatementHandle *drsh)
    248 {
    249   if (NULL != drsh->job)
    250   {
    251     GNUNET_CURL_job_cancel (drsh->job);
    252     drsh->job = NULL;
    253   }
    254   TALER_curl_easy_post_finished (&drsh->post_ctx);
    255   GNUNET_free (drsh->url);
    256   GNUNET_free (drsh);
    257 }