exchange

Base system with REST service to issue digital coins, run by the payment service provider
Log | Files | Refs | Submodules | README | LICENSE

exchange_api_delete-purses-PURSE_PUB.c (7867B)


      1 /*
      2    This file is part of TALER
      3    Copyright (C) 2022-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_delete-purses-PURSE_PUB.c
     19  * @brief Implementation of the client to delete a purse
     20  * @author Christian Grothoff
     21  */
     22 #include "taler/platform.h"
     23 #include <jansson.h>
     24 #include <microhttpd.h> /* just for HTTP status codes */
     25 #include <gnunet/gnunet_util_lib.h>
     26 #include <gnunet/gnunet_json_lib.h>
     27 #include <gnunet/gnunet_curl_lib.h>
     28 #include "taler/taler_json_lib.h"
     29 #include "taler/taler_exchange_service.h"
     30 #include "exchange_api_handle.h"
     31 #include "exchange_api_common.h"
     32 #include "taler/taler_signatures.h"
     33 #include "exchange_api_curl_defaults.h"
     34 
     35 
     36 /**
     37  * @brief A purse delete handle
     38  */
     39 struct TALER_EXCHANGE_DeletePursesHandle
     40 {
     41 
     42   /**
     43    * The base url for this request.
     44    */
     45   char *base_url;
     46 
     47   /**
     48    * The full url for this request, set during _start.
     49    */
     50   char *url;
     51 
     52   /**
     53    * Handle for the request.
     54    */
     55   struct GNUNET_CURL_Job *job;
     56 
     57   /**
     58    * Function to call with the result.
     59    */
     60   TALER_EXCHANGE_DeletePursesCallback cb;
     61 
     62   /**
     63    * Closure for @a cb.
     64    */
     65   TALER_EXCHANGE_DELETE_PURSES_RESULT_CLOSURE *cb_cls;
     66 
     67   /**
     68    * Reference to the execution context.
     69    */
     70   struct GNUNET_CURL_Context *ctx;
     71 
     72   /**
     73    * Header with the purse_sig.
     74    */
     75   struct curl_slist *xhdr;
     76 
     77   /**
     78    * Public key of the purse (derived from private key in _create).
     79    */
     80   struct TALER_PurseContractPublicKeyP purse_pub;
     81 };
     82 
     83 
     84 /**
     85  * Function called when we're done processing the
     86  * HTTP DELETE /purse/$PID request.
     87  *
     88  * @param cls the `struct TALER_EXCHANGE_DeletePursesHandle`
     89  * @param response_code HTTP response code, 0 on error
     90  * @param response parsed JSON result, NULL on error
     91  */
     92 static void
     93 handle_purse_delete_finished (void *cls,
     94                               long response_code,
     95                               const void *response)
     96 {
     97   struct TALER_EXCHANGE_DeletePursesHandle *dph = cls;
     98   const json_t *j = response;
     99   struct TALER_EXCHANGE_DeletePursesResponse dr = {
    100     .hr.reply = j,
    101     .hr.http_status = (unsigned int) response_code
    102   };
    103 
    104   dph->job = NULL;
    105   switch (response_code)
    106   {
    107   case 0:
    108     dr.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
    109     break;
    110   case MHD_HTTP_NO_CONTENT:
    111     break;
    112   case MHD_HTTP_BAD_REQUEST:
    113     /* This should never happen, either us or the exchange is buggy
    114        (or API version conflict); just pass JSON reply to the application */
    115     dr.hr.ec = TALER_JSON_get_error_code (j);
    116     dr.hr.hint = TALER_JSON_get_error_hint (j);
    117     break;
    118   case MHD_HTTP_FORBIDDEN:
    119     dr.hr.ec = TALER_JSON_get_error_code (j);
    120     dr.hr.hint = TALER_JSON_get_error_hint (j);
    121     /* Nothing really to verify, exchange says one of the signatures is
    122        invalid; as we checked them, this should never happen, we
    123        should pass the JSON reply to the application */
    124     break;
    125   case MHD_HTTP_NOT_FOUND:
    126     dr.hr.ec = TALER_JSON_get_error_code (j);
    127     dr.hr.hint = TALER_JSON_get_error_hint (j);
    128     /* Nothing really to verify, this should never
    129        happen, we should pass the JSON reply to the application */
    130     break;
    131   case MHD_HTTP_CONFLICT:
    132     dr.hr.ec = TALER_JSON_get_error_code (j);
    133     dr.hr.hint = TALER_JSON_get_error_hint (j);
    134     break;
    135   case MHD_HTTP_INTERNAL_SERVER_ERROR:
    136     dr.hr.ec = TALER_JSON_get_error_code (j);
    137     dr.hr.hint = TALER_JSON_get_error_hint (j);
    138     /* Server had an internal issue; we should retry, but this API
    139        leaves this to the application */
    140     break;
    141   default:
    142     /* unexpected response code */
    143     dr.hr.ec = TALER_JSON_get_error_code (j);
    144     dr.hr.hint = TALER_JSON_get_error_hint (j);
    145     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    146                 "Unexpected response code %u/%d for exchange purse delete\n",
    147                 (unsigned int) response_code,
    148                 dr.hr.ec);
    149     GNUNET_break_op (0);
    150     break;
    151   }
    152   dph->cb (dph->cb_cls,
    153            &dr);
    154   TALER_EXCHANGE_delete_purses_cancel (dph);
    155 }
    156 
    157 
    158 struct TALER_EXCHANGE_DeletePursesHandle *
    159 TALER_EXCHANGE_delete_purses_create (
    160   struct GNUNET_CURL_Context *ctx,
    161   const char *url,
    162   const struct TALER_PurseContractPrivateKeyP *purse_priv)
    163 {
    164   struct TALER_EXCHANGE_DeletePursesHandle *dph;
    165   struct TALER_PurseContractSignatureP purse_sig;
    166 
    167   dph = GNUNET_new (struct TALER_EXCHANGE_DeletePursesHandle);
    168   dph->ctx = ctx;
    169   dph->base_url = GNUNET_strdup (url);
    170   GNUNET_CRYPTO_eddsa_key_get_public (&purse_priv->eddsa_priv,
    171                                       &dph->purse_pub.eddsa_pub);
    172   TALER_wallet_purse_delete_sign (purse_priv,
    173                                   &purse_sig);
    174   {
    175     char *delete_str;
    176     char *xhdr;
    177 
    178     delete_str =
    179       GNUNET_STRINGS_data_to_string_alloc (&purse_sig,
    180                                            sizeof (purse_sig));
    181     GNUNET_asprintf (&xhdr,
    182                      "Taler-Purse-Signature: %s",
    183                      delete_str);
    184     GNUNET_free (delete_str);
    185     dph->xhdr = curl_slist_append (NULL,
    186                                    xhdr);
    187     GNUNET_free (xhdr);
    188   }
    189   return dph;
    190 }
    191 
    192 
    193 enum TALER_ErrorCode
    194 TALER_EXCHANGE_delete_purses_start (
    195   struct TALER_EXCHANGE_DeletePursesHandle *dph,
    196   TALER_EXCHANGE_DeletePursesCallback cb,
    197   TALER_EXCHANGE_DELETE_PURSES_RESULT_CLOSURE *cb_cls)
    198 {
    199   CURL *eh;
    200   char arg_str[sizeof (dph->purse_pub) * 2 + 32];
    201 
    202   dph->cb = cb;
    203   dph->cb_cls = cb_cls;
    204   {
    205     char pub_str[sizeof (dph->purse_pub) * 2];
    206     char *end;
    207 
    208     end = GNUNET_STRINGS_data_to_string (&dph->purse_pub,
    209                                          sizeof (dph->purse_pub),
    210                                          pub_str,
    211                                          sizeof (pub_str));
    212     *end = '\0';
    213     GNUNET_snprintf (arg_str,
    214                      sizeof (arg_str),
    215                      "purses/%s",
    216                      pub_str);
    217   }
    218   dph->url = TALER_url_join (dph->base_url,
    219                              arg_str,
    220                              NULL);
    221   if (NULL == dph->url)
    222   {
    223     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    224                 "Could not construct request URL.\n");
    225     return TALER_EC_GENERIC_CONFIGURATION_INVALID;
    226   }
    227   eh = TALER_EXCHANGE_curl_easy_get_ (dph->url);
    228   if (NULL == eh)
    229   {
    230     GNUNET_break (0);
    231     return TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE;
    232   }
    233   GNUNET_assert (CURLE_OK ==
    234                  curl_easy_setopt (eh,
    235                                    CURLOPT_CUSTOMREQUEST,
    236                                    MHD_HTTP_METHOD_DELETE));
    237   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
    238               "URL for purse delete: `%s'\n",
    239               dph->url);
    240   dph->job = GNUNET_CURL_job_add2 (dph->ctx,
    241                                    eh,
    242                                    dph->xhdr,
    243                                    &handle_purse_delete_finished,
    244                                    dph);
    245   if (NULL == dph->job)
    246     return TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE;
    247   return TALER_EC_NONE;
    248 }
    249 
    250 
    251 void
    252 TALER_EXCHANGE_delete_purses_cancel (
    253   struct TALER_EXCHANGE_DeletePursesHandle *dph)
    254 {
    255   if (NULL != dph->job)
    256   {
    257     GNUNET_CURL_job_cancel (dph->job);
    258     dph->job = NULL;
    259   }
    260   curl_slist_free_all (dph->xhdr);
    261   GNUNET_free (dph->url);
    262   GNUNET_free (dph->base_url);
    263   GNUNET_free (dph);
    264 }
    265 
    266 
    267 /* end of exchange_api_delete-purses-PURSE_PUB.c */