merchant

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

merchant_api_post-orders-ORDER_ID-claim.c (7873B)


      1 /*
      2   This file is part of TALER
      3   Copyright (C) 2014-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-orders-ORDER_ID-claim.c
     21  * @brief Implementation of the POST /orders/$ID/claim 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-orders-ORDER_ID-claim.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 #include <taler/taler_signatures.h>
     36 
     37 
     38 /**
     39  * Handle for a POST /orders/$ORDER_ID/claim operation.
     40  */
     41 struct TALER_MERCHANT_PostOrdersClaimHandle
     42 {
     43   /**
     44    * Base URL of the merchant backend.
     45    */
     46   char *base_url;
     47 
     48   /**
     49    * The full URL for this request.
     50    */
     51   char *url;
     52 
     53   /**
     54    * Handle for the request.
     55    */
     56   struct GNUNET_CURL_Job *job;
     57 
     58   /**
     59    * Function to call with the result.
     60    */
     61   TALER_MERCHANT_PostOrdersClaimCallback cb;
     62 
     63   /**
     64    * Closure for @a cb.
     65    */
     66   TALER_MERCHANT_POST_ORDERS_CLAIM_RESULT_CLOSURE *cb_cls;
     67 
     68   /**
     69    * Reference to the execution context.
     70    */
     71   struct GNUNET_CURL_Context *ctx;
     72 
     73   /**
     74    * Minor context that holds body and headers.
     75    */
     76   struct TALER_CURL_PostContext post_ctx;
     77 
     78   /**
     79    * Order identifier.
     80    */
     81   char *order_id;
     82 
     83   /**
     84    * Wallet nonce for claiming.
     85    */
     86   struct GNUNET_CRYPTO_EddsaPublicKey nonce;
     87 
     88   /**
     89    * Optional claim token.
     90    */
     91   const struct TALER_ClaimTokenP *token;
     92 };
     93 
     94 
     95 /**
     96  * Function called when we're done processing the
     97  * HTTP POST /orders/$ID/claim request.
     98  *
     99  * @param cls the `struct TALER_MERCHANT_PostOrdersClaimHandle`
    100  * @param response_code HTTP response code, 0 on error
    101  * @param response response body, NULL if not in JSON
    102  */
    103 static void
    104 handle_post_order_claim_finished (void *cls,
    105                                   long response_code,
    106                                   const void *response)
    107 {
    108   struct TALER_MERCHANT_PostOrdersClaimHandle *poch = cls;
    109   const json_t *json = response;
    110   struct TALER_MERCHANT_PostOrdersClaimResponse ocr = {
    111     .hr.http_status = (unsigned int) response_code,
    112     .hr.reply = json
    113   };
    114   struct GNUNET_JSON_Specification spec[] = {
    115     GNUNET_JSON_spec_object_const (
    116       "contract_terms",
    117       &ocr.details.ok.contract_terms),
    118     GNUNET_JSON_spec_fixed_auto (
    119       "sig",
    120       &ocr.details.ok.merchant_sig),
    121     GNUNET_JSON_spec_end ()
    122   };
    123 
    124   poch->job = NULL;
    125   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    126               "POST /orders/$ID/claim completed with response code %u\n",
    127               (unsigned int) response_code);
    128   switch (response_code)
    129   {
    130   case MHD_HTTP_OK:
    131     if (GNUNET_OK !=
    132         GNUNET_JSON_parse (json,
    133                            spec,
    134                            NULL, NULL))
    135     {
    136       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
    137                   "Claiming order failed: could not parse JSON response\n");
    138       GNUNET_break_op (0);
    139       ocr.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
    140       ocr.hr.http_status = 0;
    141       break;
    142     }
    143 
    144     if (GNUNET_OK !=
    145         TALER_JSON_contract_hash (ocr.details.ok.contract_terms,
    146                                   &ocr.details.ok.h_contract_terms))
    147     {
    148       GNUNET_break (0);
    149       ocr.hr.ec
    150         = TALER_EC_MERCHANT_POST_ORDERS_ID_CLAIM_CLIENT_INTERNAL_FAILURE;
    151       ocr.hr.http_status = 0;
    152       break;
    153     }
    154     break;
    155   case MHD_HTTP_CONFLICT:
    156     ocr.hr.ec = TALER_JSON_get_error_code (json);
    157     ocr.hr.hint = TALER_JSON_get_error_hint (json);
    158     break;
    159   default:
    160     ocr.hr.ec = TALER_JSON_get_error_code (json);
    161     ocr.hr.hint = TALER_JSON_get_error_hint (json);
    162     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
    163                 "Claim order failed with HTTP status code %u/%d\n",
    164                 (unsigned int) response_code,
    165                 (int) ocr.hr.ec);
    166     break;
    167   }
    168   poch->cb (poch->cb_cls,
    169             &ocr);
    170   TALER_MERCHANT_post_orders_claim_cancel (poch);
    171 }
    172 
    173 
    174 struct TALER_MERCHANT_PostOrdersClaimHandle *
    175 TALER_MERCHANT_post_orders_claim_create (
    176   struct GNUNET_CURL_Context *ctx,
    177   const char *url,
    178   const char *order_id,
    179   const struct GNUNET_CRYPTO_EddsaPublicKey *nonce)
    180 {
    181   struct TALER_MERCHANT_PostOrdersClaimHandle *poch;
    182 
    183   poch = GNUNET_new (struct TALER_MERCHANT_PostOrdersClaimHandle);
    184   poch->ctx = ctx;
    185   poch->base_url = GNUNET_strdup (url);
    186   poch->order_id = GNUNET_strdup (order_id);
    187   poch->nonce = *nonce;
    188   return poch;
    189 }
    190 
    191 
    192 enum GNUNET_GenericReturnValue
    193 TALER_MERCHANT_post_orders_claim_set_options_ (
    194   struct TALER_MERCHANT_PostOrdersClaimHandle *poch,
    195   unsigned int num_options,
    196   const struct TALER_MERCHANT_PostOrdersClaimOptionValue *options)
    197 {
    198   for (unsigned int i = 0; i < num_options; i++)
    199   {
    200     switch (options[i].option)
    201     {
    202     case TALER_MERCHANT_POST_ORDERS_CLAIM_OPTION_END:
    203       return GNUNET_OK;
    204     case TALER_MERCHANT_POST_ORDERS_CLAIM_OPTION_TOKEN:
    205       poch->token = options[i].details.token;
    206       break;
    207     default:
    208       GNUNET_break (0);
    209       return GNUNET_SYSERR;
    210     }
    211   }
    212   return GNUNET_OK;
    213 }
    214 
    215 
    216 enum TALER_ErrorCode
    217 TALER_MERCHANT_post_orders_claim_start (
    218   struct TALER_MERCHANT_PostOrdersClaimHandle *poch,
    219   TALER_MERCHANT_PostOrdersClaimCallback cb,
    220   TALER_MERCHANT_POST_ORDERS_CLAIM_RESULT_CLOSURE *cb_cls)
    221 {
    222   json_t *req_obj;
    223   CURL *eh;
    224 
    225   poch->cb = cb;
    226   poch->cb_cls = cb_cls;
    227   {
    228     char *path;
    229 
    230     GNUNET_asprintf (&path,
    231                      "orders/%s/claim",
    232                      poch->order_id);
    233     poch->url = TALER_url_join (poch->base_url,
    234                                 path,
    235                                 NULL);
    236     GNUNET_free (path);
    237   }
    238   if (NULL == poch->url)
    239     return TALER_EC_GENERIC_CONFIGURATION_INVALID;
    240   req_obj = GNUNET_JSON_PACK (
    241     GNUNET_JSON_pack_data_auto ("nonce",
    242                                 &poch->nonce),
    243     GNUNET_JSON_pack_allow_null (
    244       GNUNET_JSON_pack_data_auto ("token",
    245                                   poch->token)));
    246   eh = TALER_MERCHANT_curl_easy_get_ (poch->url);
    247   if ( (NULL == eh) ||
    248        (GNUNET_OK !=
    249         TALER_curl_easy_post (&poch->post_ctx,
    250                               eh,
    251                               req_obj)) )
    252   {
    253     GNUNET_break (0);
    254     json_decref (req_obj);
    255     if (NULL != eh)
    256       curl_easy_cleanup (eh);
    257     return TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE;
    258   }
    259   json_decref (req_obj);
    260   poch->job = GNUNET_CURL_job_add2 (poch->ctx,
    261                                     eh,
    262                                     poch->post_ctx.headers,
    263                                     &handle_post_order_claim_finished,
    264                                     poch);
    265   if (NULL == poch->job)
    266     return TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE;
    267   return TALER_EC_NONE;
    268 }
    269 
    270 
    271 void
    272 TALER_MERCHANT_post_orders_claim_cancel (
    273   struct TALER_MERCHANT_PostOrdersClaimHandle *poch)
    274 {
    275   if (NULL != poch->job)
    276   {
    277     GNUNET_CURL_job_cancel (poch->job);
    278     poch->job = NULL;
    279   }
    280   TALER_curl_easy_post_finished (&poch->post_ctx);
    281   GNUNET_free (poch->order_id);
    282   GNUNET_free (poch->url);
    283   GNUNET_free (poch->base_url);
    284   GNUNET_free (poch);
    285 }
    286 
    287 
    288 /* end of merchant_api_post-orders-ORDER_ID-claim.c */