merchant

Merchant backend to process payments, run by merchants
Log | Files | Refs | Submodules | README | LICENSE

merchant_api_post-private-donau.c (7523B)


      1 /*
      2   This file is part of TALER
      3   Copyright (C) 2024-2026 Taler Systems SA
      4 
      5   TALER is free software; you can redistribute it and/or modify
      6   it under the terms of the GNU Lesser General Public License as
      7   published by the Free Software Foundation; either version 2.1,
      8   or (at your option) any later version.
      9 
     10   TALER is distributed in the hope that it will be useful,
     11   but WITHOUT ANY WARRANTY; without even the implied warranty of
     12   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     13   GNU Lesser General Public License for more details.
     14 
     15   You should have received a copy of the GNU Lesser General
     16   Public License along with TALER; see the file COPYING.LGPL.
     17   If not, see <http://www.gnu.org/licenses/>
     18 */
     19 /**
     20  * @file merchant_api_post-private-donau.c
     21  * @brief Implementation of the POST /private/donau request
     22  * @author Christian Grothoff
     23  */
     24 #include "taler/platform.h"
     25 #include <curl/curl.h>
     26 #include <jansson.h>
     27 #include <microhttpd.h> /* just for HTTP status codes */
     28 #include <gnunet/gnunet_util_lib.h>
     29 #include <gnunet/gnunet_curl_lib.h>
     30 #include <taler/taler-merchant/post-private-donau.h>
     31 #include "merchant_api_curl_defaults.h"
     32 #include "merchant_api_common.h"
     33 #include <taler/taler_json_lib.h>
     34 #include <taler/taler_curl_lib.h>
     35 
     36 
     37 /**
     38  * Handle for a POST /private/donau operation.
     39  */
     40 struct TALER_MERCHANT_PostPrivateDonauHandle
     41 {
     42   /**
     43    * Base URL of the merchant backend.
     44    */
     45   char *base_url;
     46 
     47   /**
     48    * The full URL for this request.
     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_MERCHANT_PostPrivateDonauCallback cb;
     61 
     62   /**
     63    * Closure for @a cb.
     64    */
     65   TALER_MERCHANT_POST_PRIVATE_DONAU_RESULT_CLOSURE *cb_cls;
     66 
     67   /**
     68    * Reference to the execution context.
     69    */
     70   struct GNUNET_CURL_Context *ctx;
     71 
     72   /**
     73    * Minor context that holds body and headers.
     74    */
     75   struct TALER_CURL_PostContext post_ctx;
     76 
     77   /**
     78    * Charity information to register.
     79    */
     80   struct TALER_MERCHANT_Charity charity;
     81 
     82   /**
     83    * Charity URL (owned copy).
     84    */
     85   char *charity_url;
     86 };
     87 
     88 
     89 /**
     90  * Function called when we're done processing the
     91  * HTTP POST /private/donau request.
     92  *
     93  * @param cls the `struct TALER_MERCHANT_PostPrivateDonauHandle`
     94  * @param response_code HTTP response code, 0 on error
     95  * @param response response body, NULL if not in JSON
     96  */
     97 static void
     98 handle_post_donau_finished (void *cls,
     99                             long response_code,
    100                             const void *response)
    101 {
    102   struct TALER_MERCHANT_PostPrivateDonauHandle *ppdh = cls;
    103   const json_t *json = response;
    104   struct TALER_MERCHANT_PostPrivateDonauResponse pdr = {
    105     .hr.http_status = (unsigned int) response_code,
    106     .hr.reply = json
    107   };
    108 
    109   ppdh->job = NULL;
    110   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    111               "POST /private/donau completed with response code %u\n",
    112               (unsigned int) response_code);
    113   switch (response_code)
    114   {
    115   case 0:
    116     pdr.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
    117     break;
    118   case MHD_HTTP_ACCEPTED:
    119     if (GNUNET_OK !=
    120         TALER_MERCHANT_parse_mfa_challenge_response_ (
    121           json,
    122           &pdr.details.accepted))
    123     {
    124       GNUNET_break_op (0);
    125       pdr.hr.http_status = 0;
    126       pdr.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
    127     }
    128     break;
    129   case MHD_HTTP_NO_CONTENT:
    130     break;
    131   case MHD_HTTP_BAD_REQUEST:
    132     pdr.hr.ec = TALER_JSON_get_error_code (json);
    133     pdr.hr.hint = TALER_JSON_get_error_hint (json);
    134     break;
    135   case MHD_HTTP_CONFLICT:
    136     pdr.hr.ec = TALER_JSON_get_error_code (json);
    137     pdr.hr.hint = TALER_JSON_get_error_hint (json);
    138     break;
    139   case MHD_HTTP_INTERNAL_SERVER_ERROR:
    140     pdr.hr.ec = TALER_JSON_get_error_code (json);
    141     pdr.hr.hint = TALER_JSON_get_error_hint (json);
    142     break;
    143   case MHD_HTTP_BAD_GATEWAY:
    144     pdr.hr.ec = TALER_JSON_get_error_code (json);
    145     pdr.hr.hint = TALER_JSON_get_error_hint (json);
    146     break;
    147   default:
    148     TALER_MERCHANT_parse_error_details_ (json,
    149                                          response_code,
    150                                          &pdr.hr);
    151     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    152                 "Unexpected response code %u/%d\n",
    153                 (unsigned int) response_code,
    154                 (int) pdr.hr.ec);
    155     GNUNET_break_op (0);
    156     break;
    157   }
    158   ppdh->cb (ppdh->cb_cls,
    159             &pdr);
    160   if (MHD_HTTP_ACCEPTED == response_code)
    161     TALER_MERCHANT_mfa_challenge_response_free (
    162       &pdr.details.accepted);
    163   TALER_MERCHANT_post_private_donau_cancel (ppdh);
    164 }
    165 
    166 
    167 struct TALER_MERCHANT_PostPrivateDonauHandle *
    168 TALER_MERCHANT_post_private_donau_create (
    169   struct GNUNET_CURL_Context *ctx,
    170   const char *url,
    171   const struct TALER_MERCHANT_Charity *charity)
    172 {
    173   struct TALER_MERCHANT_PostPrivateDonauHandle *ppdh;
    174 
    175   ppdh = GNUNET_new (struct TALER_MERCHANT_PostPrivateDonauHandle);
    176   ppdh->ctx = ctx;
    177   ppdh->base_url = GNUNET_strdup (url);
    178   ppdh->charity_url = GNUNET_strdup (charity->charity_url);
    179   ppdh->charity.charity_url = ppdh->charity_url;
    180   ppdh->charity.charity_id = charity->charity_id;
    181   return ppdh;
    182 }
    183 
    184 
    185 enum GNUNET_GenericReturnValue
    186 TALER_MERCHANT_post_private_donau_set_options_ (
    187   struct TALER_MERCHANT_PostPrivateDonauHandle *ppdh,
    188   unsigned int num_options,
    189   const struct TALER_MERCHANT_PostPrivateDonauOptionValue *options)
    190 {
    191   for (unsigned int i = 0; i < num_options; i++)
    192   {
    193     switch (options[i].option)
    194     {
    195     case TALER_MERCHANT_POST_PRIVATE_DONAU_OPTION_END:
    196       return GNUNET_OK;
    197     default:
    198       GNUNET_break (0);
    199       return GNUNET_SYSERR;
    200     }
    201   }
    202   return GNUNET_OK;
    203 }
    204 
    205 
    206 enum TALER_ErrorCode
    207 TALER_MERCHANT_post_private_donau_start (
    208   struct TALER_MERCHANT_PostPrivateDonauHandle *ppdh,
    209   TALER_MERCHANT_PostPrivateDonauCallback cb,
    210   TALER_MERCHANT_POST_PRIVATE_DONAU_RESULT_CLOSURE *cb_cls)
    211 {
    212   json_t *req_obj;
    213   CURL *eh;
    214 
    215   ppdh->cb = cb;
    216   ppdh->cb_cls = cb_cls;
    217   ppdh->url = TALER_url_join (ppdh->base_url,
    218                               "private/donau",
    219                               NULL);
    220   if (NULL == ppdh->url)
    221     return TALER_EC_GENERIC_CONFIGURATION_INVALID;
    222   req_obj = GNUNET_JSON_PACK (
    223     GNUNET_JSON_pack_string ("donau_url",
    224                              ppdh->charity.charity_url),
    225     GNUNET_JSON_pack_uint64 ("charity_id",
    226                              ppdh->charity.charity_id)
    227     );
    228   eh = TALER_MERCHANT_curl_easy_get_ (ppdh->url);
    229   if ( (NULL == eh) ||
    230        (GNUNET_OK !=
    231         TALER_curl_easy_post (&ppdh->post_ctx,
    232                               eh,
    233                               req_obj)) )
    234   {
    235     GNUNET_break (0);
    236     json_decref (req_obj);
    237     if (NULL != eh)
    238       curl_easy_cleanup (eh);
    239     return TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE;
    240   }
    241   json_decref (req_obj);
    242   ppdh->job = GNUNET_CURL_job_add2 (ppdh->ctx,
    243                                     eh,
    244                                     ppdh->post_ctx.headers,
    245                                     &handle_post_donau_finished,
    246                                     ppdh);
    247   if (NULL == ppdh->job)
    248     return TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE;
    249   return TALER_EC_NONE;
    250 }
    251 
    252 
    253 void
    254 TALER_MERCHANT_post_private_donau_cancel (
    255   struct TALER_MERCHANT_PostPrivateDonauHandle *ppdh)
    256 {
    257   if (NULL != ppdh->job)
    258   {
    259     GNUNET_CURL_job_cancel (ppdh->job);
    260     ppdh->job = NULL;
    261   }
    262   TALER_curl_easy_post_finished (&ppdh->post_ctx);
    263   GNUNET_free (ppdh->charity_url);
    264   GNUNET_free (ppdh->url);
    265   GNUNET_free (ppdh->base_url);
    266   GNUNET_free (ppdh);
    267 }
    268 
    269 
    270 /* end of merchant_api_post-private-donau.c */