merchant

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

merchant_api_patch-private-accounts-H_WIRE.c (9382B)


      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
      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_patch-private-accounts-H_WIRE.c
     21  * @brief Implementation of the PATCH /private/accounts/$H_WIRE 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/patch-private-accounts-H_WIRE.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 PATCH /private/accounts/$H_WIRE operation.
     39  */
     40 struct TALER_MERCHANT_PatchPrivateAccountHandle
     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_PatchPrivateAccountCallback cb;
     61 
     62   /**
     63    * Closure for @a cb.
     64    */
     65   TALER_MERCHANT_PATCH_PRIVATE_ACCOUNT_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    * Hash of the wire details identifying the account.
     79    */
     80   struct TALER_MerchantWireHashP h_wire;
     81 
     82   /**
     83    * Optional credit facade URL.
     84    */
     85   char *credit_facade_url;
     86 
     87   /**
     88    * Optional credit facade credentials (JSON).
     89    */
     90   json_t *credit_facade_credentials;
     91 
     92   /**
     93    * Optional extra wire subject metadata (JSON).
     94    */
     95   char*extra_wire_subject_metadata;
     96 };
     97 
     98 
     99 /**
    100  * Function called when we're done processing the
    101  * HTTP PATCH /private/accounts/$H_WIRE request.
    102  *
    103  * @param cls the `struct TALER_MERCHANT_PatchPrivateAccountHandle`
    104  * @param response_code HTTP response code, 0 on error
    105  * @param response response body, NULL if not in JSON
    106  */
    107 static void
    108 handle_patch_account_finished (void *cls,
    109                                long response_code,
    110                                const void *response)
    111 {
    112   struct TALER_MERCHANT_PatchPrivateAccountHandle *pah = cls;
    113   const json_t *json = response;
    114   struct TALER_MERCHANT_PatchPrivateAccountResponse par = {
    115     .hr.http_status = (unsigned int) response_code,
    116     .hr.reply = json
    117   };
    118 
    119   pah->job = NULL;
    120   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    121               "PATCH /private/accounts/$H_WIRE completed with response code %u\n",
    122               (unsigned int) response_code);
    123   switch (response_code)
    124   {
    125   case 0:
    126     par.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
    127     break;
    128   case MHD_HTTP_NO_CONTENT:
    129     break;
    130   case MHD_HTTP_BAD_REQUEST:
    131     par.hr.ec = TALER_JSON_get_error_code (json);
    132     par.hr.hint = TALER_JSON_get_error_hint (json);
    133     GNUNET_break_op (0);
    134     break;
    135   case MHD_HTTP_UNAUTHORIZED:
    136     par.hr.ec = TALER_JSON_get_error_code (json);
    137     par.hr.hint = TALER_JSON_get_error_hint (json);
    138     break;
    139   case MHD_HTTP_FORBIDDEN:
    140     par.hr.ec = TALER_JSON_get_error_code (json);
    141     par.hr.hint = TALER_JSON_get_error_hint (json);
    142     break;
    143   case MHD_HTTP_NOT_FOUND:
    144     par.hr.ec = TALER_JSON_get_error_code (json);
    145     par.hr.hint = TALER_JSON_get_error_hint (json);
    146     break;
    147   case MHD_HTTP_CONFLICT:
    148     par.hr.ec = TALER_JSON_get_error_code (json);
    149     par.hr.hint = TALER_JSON_get_error_hint (json);
    150     break;
    151   case MHD_HTTP_INTERNAL_SERVER_ERROR:
    152     par.hr.ec = TALER_JSON_get_error_code (json);
    153     par.hr.hint = TALER_JSON_get_error_hint (json);
    154     break;
    155   default:
    156     TALER_MERCHANT_parse_error_details_ (json,
    157                                          response_code,
    158                                          &par.hr);
    159     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    160                 "Unexpected response code %u/%d\n",
    161                 (unsigned int) response_code,
    162                 (int) par.hr.ec);
    163     GNUNET_break_op (0);
    164     break;
    165   }
    166   pah->cb (pah->cb_cls,
    167            &par);
    168   TALER_MERCHANT_patch_private_account_cancel (pah);
    169 }
    170 
    171 
    172 struct TALER_MERCHANT_PatchPrivateAccountHandle *
    173 TALER_MERCHANT_patch_private_account_create (
    174   struct GNUNET_CURL_Context *ctx,
    175   const char *url,
    176   const struct TALER_MerchantWireHashP *h_wire)
    177 {
    178   struct TALER_MERCHANT_PatchPrivateAccountHandle *pah;
    179 
    180   pah = GNUNET_new (struct TALER_MERCHANT_PatchPrivateAccountHandle);
    181   pah->ctx = ctx;
    182   pah->base_url = GNUNET_strdup (url);
    183   pah->h_wire = *h_wire;
    184   return pah;
    185 }
    186 
    187 
    188 enum GNUNET_GenericReturnValue
    189 TALER_MERCHANT_patch_private_account_set_options_ (
    190   struct TALER_MERCHANT_PatchPrivateAccountHandle *pah,
    191   unsigned int num_options,
    192   const struct TALER_MERCHANT_PatchPrivateAccountOptionValue *options)
    193 {
    194   for (unsigned int i = 0; i < num_options; i++)
    195   {
    196     switch (options[i].option)
    197     {
    198     case TALER_MERCHANT_PATCH_PRIVATE_ACCOUNT_OPTION_END:
    199       return GNUNET_OK;
    200     case TALER_MERCHANT_PATCH_PRIVATE_ACCOUNT_OPTION_CREDIT_FACADE_URL:
    201       GNUNET_free (pah->credit_facade_url);
    202       pah->credit_facade_url = GNUNET_strdup (options[i].details.credit_facade_url);
    203       break;
    204     case TALER_MERCHANT_PATCH_PRIVATE_ACCOUNT_OPTION_CREDIT_FACADE_CREDENTIALS:
    205       json_decref (pah->credit_facade_credentials);
    206       pah->credit_facade_credentials
    207         = json_incref ((json_t *) options[i].details.credit_facade_credentials);
    208       break;
    209     case TALER_MERCHANT_PATCH_PRIVATE_ACCOUNT_OPTION_EXTRA_WIRE_SUBJECT_METADATA:
    210       GNUNET_free (pah->extra_wire_subject_metadata);
    211       pah->extra_wire_subject_metadata
    212         = GNUNET_strdup (options[i].details.extra_wire_subject_metadata);
    213       break;
    214     default:
    215       GNUNET_break (0);
    216       return GNUNET_SYSERR;
    217     }
    218   }
    219   return GNUNET_OK;
    220 }
    221 
    222 
    223 enum TALER_ErrorCode
    224 TALER_MERCHANT_patch_private_account_start (
    225   struct TALER_MERCHANT_PatchPrivateAccountHandle *pah,
    226   TALER_MERCHANT_PatchPrivateAccountCallback cb,
    227   TALER_MERCHANT_PATCH_PRIVATE_ACCOUNT_RESULT_CLOSURE *cb_cls)
    228 {
    229   json_t *req_obj;
    230   CURL *eh;
    231 
    232   pah->cb = cb;
    233   pah->cb_cls = cb_cls;
    234   {
    235     char w_str[sizeof (pah->h_wire) * 2];
    236     char *path;
    237     char *end;
    238 
    239     end = GNUNET_STRINGS_data_to_string (&pah->h_wire,
    240                                          sizeof (pah->h_wire),
    241                                          w_str,
    242                                          sizeof (w_str));
    243     *end = '\0';
    244     GNUNET_asprintf (&path,
    245                      "private/accounts/%s",
    246                      w_str);
    247     pah->url = TALER_url_join (pah->base_url,
    248                                path,
    249                                NULL);
    250     GNUNET_free (path);
    251   }
    252   if (NULL == pah->url)
    253     return TALER_EC_GENERIC_CONFIGURATION_INVALID;
    254   req_obj = GNUNET_JSON_PACK (
    255     GNUNET_JSON_pack_allow_null (
    256       GNUNET_JSON_pack_string ("credit_facade_url",
    257                                pah->credit_facade_url)),
    258     GNUNET_JSON_pack_allow_null (
    259       GNUNET_JSON_pack_object_incref ("credit_facade_credentials",
    260                                       pah->credit_facade_credentials)),
    261     GNUNET_JSON_pack_allow_null (
    262       GNUNET_JSON_pack_string ("extra_wire_subject_metadata",
    263                                pah->extra_wire_subject_metadata)
    264       ));
    265   eh = TALER_MERCHANT_curl_easy_get_ (pah->url);
    266   if ( (NULL == eh) ||
    267        (GNUNET_OK !=
    268         TALER_curl_easy_post (&pah->post_ctx,
    269                               eh,
    270                               req_obj)) )
    271   {
    272     GNUNET_break (0);
    273     json_decref (req_obj);
    274     if (NULL != eh)
    275       curl_easy_cleanup (eh);
    276     return TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE;
    277   }
    278   json_decref (req_obj);
    279   GNUNET_assert (CURLE_OK ==
    280                  curl_easy_setopt (eh,
    281                                    CURLOPT_CUSTOMREQUEST,
    282                                    MHD_HTTP_METHOD_PATCH));
    283   pah->job = GNUNET_CURL_job_add2 (pah->ctx,
    284                                    eh,
    285                                    pah->post_ctx.headers,
    286                                    &handle_patch_account_finished,
    287                                    pah);
    288   if (NULL == pah->job)
    289     return TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE;
    290   return TALER_EC_NONE;
    291 }
    292 
    293 
    294 void
    295 TALER_MERCHANT_patch_private_account_cancel (
    296   struct TALER_MERCHANT_PatchPrivateAccountHandle *pah)
    297 {
    298   if (NULL != pah->job)
    299   {
    300     GNUNET_CURL_job_cancel (pah->job);
    301     pah->job = NULL;
    302   }
    303   TALER_curl_easy_post_finished (&pah->post_ctx);
    304   GNUNET_free (pah->url);
    305   GNUNET_free (pah->credit_facade_url);
    306   json_decref (pah->credit_facade_credentials);
    307   GNUNET_free (pah->extra_wire_subject_metadata);
    308   GNUNET_free (pah->base_url);
    309   GNUNET_free (pah);
    310 }
    311 
    312 
    313 /* end of merchant_api_patch-private-accounts-H_WIRE.c */