merchant

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

merchant_api_post-orders-ORDER_ID-pay.c (36872B)


      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 src/lib/merchant_api_post-orders-ORDER_ID-pay.c
     21  * @brief Implementation of the POST /orders/$ORDER_ID/pay request
     22  * @author Christian Grothoff
     23  * @author Marcello Stanisci
     24  */
     25 #include "platform.h"
     26 #include <curl/curl.h>
     27 #include <jansson.h>
     28 #include <microhttpd.h> /* just for HTTP status codes */
     29 #include <gnunet/gnunet_util_lib.h>
     30 #include <gnunet/gnunet_curl_lib.h>
     31 #include <taler/merchant/post-orders-ORDER_ID-pay.h>
     32 #include "merchant_api_curl_defaults.h"
     33 #include "merchant_api_common.h"
     34 #include <taler/taler_json_lib.h>
     35 #include <taler/taler_curl_lib.h>
     36 #include <taler/taler_signatures.h>
     37 #include <donau/donau_service.h>
     38 #include <donau/donau_json_lib.h>
     39 
     40 /**
     41  * Maximum number of exchange base URLs we accept in an (untrusted)
     42  * response before considering it malformed.  Bounds the stack VLA used
     43  * to parse the array.
     44  */
     45 #define MAX_EXCHANGE_BASE_URLS 1024
     46 
     47 /**
     48  * Handle for a POST /orders/$ORDER_ID/pay operation.
     49  */
     50 struct TALER_MERCHANT_PostOrdersPayHandle
     51 {
     52   /**
     53    * Base URL of the merchant backend.
     54    */
     55   char *base_url;
     56 
     57   /**
     58    * The full URL for this request.
     59    */
     60   char *url;
     61 
     62   /**
     63    * Handle for the request.
     64    */
     65   struct GNUNET_CURL_Job *job;
     66 
     67   /**
     68    * Function to call with the result.
     69    */
     70   TALER_MERCHANT_PostOrdersPayCallback cb;
     71 
     72   /**
     73    * Closure for @a cb.
     74    */
     75   TALER_MERCHANT_POST_ORDERS_PAY_RESULT_CLOSURE *cb_cls;
     76 
     77   /**
     78    * Reference to the execution context.
     79    */
     80   struct GNUNET_CURL_Context *ctx;
     81 
     82   /**
     83    * Minor context that holds body and headers.
     84    */
     85   struct TALER_CURL_PostContext post_ctx;
     86 
     87   /**
     88    * Order identifier.
     89    */
     90   char *order_id;
     91 
     92   /**
     93    * The coins we are paying with (frontend mode, already signed).
     94    */
     95   struct TALER_MERCHANT_PostOrdersPayPaidCoin *paid_coins;
     96 
     97   /**
     98    * Number of @e paid_coins.
     99    */
    100   unsigned int num_paid_coins;
    101 
    102   /**
    103    * Hash of the contract terms (wallet mode).
    104    */
    105   struct TALER_PrivateContractHashP h_contract_terms;
    106 
    107   /**
    108    * Public key of the merchant (wallet mode).
    109    */
    110   struct TALER_MerchantPublicKeyP merchant_pub;
    111 
    112   /**
    113    * Merchant signature (wallet mode).
    114    */
    115   struct TALER_MerchantSignatureP merchant_sig;
    116 
    117   /**
    118    * Total payment amount (wallet mode).
    119    */
    120   struct TALER_Amount amount;
    121 
    122   /**
    123    * Maximum fee (wallet mode).
    124    */
    125   struct TALER_Amount max_fee;
    126 
    127   /**
    128    * Contract timestamp (wallet mode).
    129    */
    130   struct GNUNET_TIME_Timestamp timestamp;
    131 
    132   /**
    133    * Refund deadline (wallet mode).
    134    */
    135   struct GNUNET_TIME_Timestamp refund_deadline;
    136 
    137   /**
    138    * Payment deadline (wallet mode).
    139    */
    140   struct GNUNET_TIME_Timestamp pay_deadline;
    141 
    142   /**
    143    * Hash of merchant wire details (wallet mode).
    144    */
    145   struct TALER_MerchantWireHashP h_wire;
    146 
    147   /**
    148    * Choice index (wallet mode).
    149    */
    150   int choice_index;
    151 
    152   /**
    153    * Coins with private keys (wallet mode).
    154    */
    155   struct TALER_MERCHANT_PostOrdersPayCoin *coins;
    156 
    157   /**
    158    * Number of @e coins (wallet mode).
    159    */
    160   unsigned int num_coins;
    161 
    162   /**
    163    * Optional session identifier.
    164    */
    165   char *session_id;
    166 
    167   /**
    168    * Optional wallet data (JSON).
    169    */
    170   json_t *wallet_data;
    171 
    172   /**
    173    * Used tokens (public form, frontend mode).
    174    */
    175   struct TALER_MERCHANT_PostOrdersPayUsedToken *used_tokens;
    176 
    177   /**
    178    * Number of @e used_tokens.
    179    */
    180   unsigned int num_used_tokens;
    181 
    182   /**
    183    * Use tokens (private form, wallet mode).
    184    */
    185   struct TALER_MERCHANT_PostOrdersPayUseToken *use_tokens;
    186 
    187   /**
    188    * Number of @e use_tokens.
    189    */
    190   unsigned int num_use_tokens;
    191 
    192   /**
    193    * Output tokens (wallet mode).
    194    */
    195   struct TALER_MERCHANT_PostOrdersPayOutputToken *output_tokens;
    196 
    197   /**
    198    * Number of @e output_tokens.
    199    */
    200   unsigned int num_output_tokens;
    201 
    202   /**
    203    * Output tokens as JSON array (frontend mode).
    204    */
    205   json_t *output_tokens_json;
    206 
    207   /**
    208    * Base URL of the selected donau for donation receipts.
    209    */
    210   char *donau_url;
    211 
    212   /**
    213    * Tax year used for the donau.
    214    */
    215   unsigned int donau_year;
    216 
    217   /**
    218    * Array of blinded donation receipts.
    219    */
    220   struct DONAU_BlindedUniqueDonorIdentifierKeyPair *donau_bkps;
    221 
    222   /**
    223    * Length of the @e donau_bkps array.
    224    */
    225   size_t num_donau_bkps;
    226 
    227   /**
    228    * Set to true if this is the wallet mode (private keys available).
    229    */
    230   bool am_wallet;
    231 };
    232 
    233 
    234 /**
    235  * Parse blindly signed output tokens from JSON response.
    236  *
    237  * @param token_sigs the JSON array with the token signatures, can be NULL
    238  * @param[out] tokens where to store the parsed tokens
    239  * @param[out] num_tokens where to store the length of the @a tokens array
    240  * @return #GNUNET_YES on success
    241  */
    242 static enum GNUNET_GenericReturnValue
    243 parse_tokens (const json_t *token_sigs,
    244               struct TALER_MERCHANT_PostOrdersPayOutputToken **tokens,
    245               unsigned int *num_tokens)
    246 {
    247   GNUNET_array_grow (*tokens,
    248                      *num_tokens,
    249                      json_array_size (token_sigs));
    250 
    251   for (unsigned int i = 0; i < (*num_tokens); i++)
    252   {
    253     struct TALER_MERCHANT_PostOrdersPayOutputToken *token = &(*tokens)[i];
    254     struct GNUNET_JSON_Specification spec[] = {
    255       TALER_JSON_spec_blinded_token_issue_sig ("blind_sig",
    256                                                &token->blinded_sig),
    257       GNUNET_JSON_spec_end ()
    258     };
    259     const json_t *jtoken
    260       = json_array_get (token_sigs,
    261                         i);
    262 
    263     if (NULL == jtoken)
    264     {
    265       GNUNET_break (0);
    266       return GNUNET_SYSERR;
    267     }
    268     if (GNUNET_OK !=
    269         GNUNET_JSON_parse (jtoken,
    270                            spec,
    271                            NULL, NULL))
    272     {
    273       GNUNET_break (0);
    274       return GNUNET_SYSERR;
    275     }
    276   }
    277 
    278   return GNUNET_YES;
    279 }
    280 
    281 
    282 /**
    283  * Function called when we're done processing the
    284  * HTTP POST /orders/$ORDER_ID/pay request.
    285  *
    286  * @param cls the `struct TALER_MERCHANT_PostOrdersPayHandle`
    287  * @param response_code HTTP response code, 0 on error
    288  * @param response response body, NULL if not in JSON
    289  */
    290 static void
    291 handle_pay_finished (void *cls,
    292                      long response_code,
    293                      const void *response)
    294 {
    295   struct TALER_MERCHANT_PostOrdersPayHandle *poph = cls;
    296   const json_t *json = response;
    297   struct TALER_MERCHANT_PostOrdersPayResponse pr = {
    298     .hr.http_status = (unsigned int) response_code,
    299     .hr.reply = json
    300   };
    301 
    302   poph->job = NULL;
    303   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    304               "POST /orders/$ID/pay completed with response code %u\n",
    305               (unsigned int) response_code);
    306   switch (response_code)
    307   {
    308   case 0:
    309     pr.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
    310     break;
    311   case MHD_HTTP_OK:
    312     if (poph->am_wallet)
    313     {
    314       const json_t *token_sigs = NULL;
    315       struct GNUNET_JSON_Specification spec[] = {
    316         GNUNET_JSON_spec_fixed_auto ("sig",
    317                                      &pr.details.ok.merchant_sig),
    318         GNUNET_JSON_spec_mark_optional (
    319           GNUNET_JSON_spec_string ("pos_confirmation",
    320                                    &pr.details.ok.pos_confirmation),
    321           NULL),
    322         GNUNET_JSON_spec_mark_optional (
    323           GNUNET_JSON_spec_array_const ("token_sigs",
    324                                         &token_sigs),
    325           NULL),
    326         GNUNET_JSON_spec_end ()
    327       };
    328 
    329       if (GNUNET_OK !=
    330           GNUNET_JSON_parse (json,
    331                              spec,
    332                              NULL, NULL))
    333       {
    334         GNUNET_break_op (0);
    335         pr.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
    336         pr.hr.http_status = 0;
    337         pr.hr.hint = "sig field missing in response";
    338         break;
    339       }
    340 
    341       if (GNUNET_OK !=
    342           parse_tokens (token_sigs,
    343                         &pr.details.ok.tokens,
    344                         &pr.details.ok.num_tokens))
    345       {
    346         GNUNET_break_op (0);
    347         pr.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
    348         pr.hr.http_status = 0;
    349         pr.hr.hint = "failed to parse token_sigs field in response";
    350         break;
    351       }
    352 
    353       if (GNUNET_OK !=
    354           TALER_merchant_pay_verify (&poph->h_contract_terms,
    355                                      &poph->merchant_pub,
    356                                      &pr.details.ok.merchant_sig))
    357       {
    358         GNUNET_break_op (0);
    359         pr.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
    360         pr.hr.http_status = 0;
    361         pr.hr.hint = "signature invalid";
    362       }
    363     }
    364     break;
    365   case MHD_HTTP_BAD_REQUEST:
    366     pr.hr.ec = TALER_JSON_get_error_code (json);
    367     pr.hr.hint = TALER_JSON_get_error_hint (json);
    368     break;
    369   case MHD_HTTP_PAYMENT_REQUIRED:
    370     pr.hr.ec = TALER_JSON_get_error_code (json);
    371     pr.hr.hint = TALER_JSON_get_error_hint (json);
    372     break;
    373   case MHD_HTTP_FORBIDDEN:
    374     pr.hr.ec = TALER_JSON_get_error_code (json);
    375     pr.hr.hint = TALER_JSON_get_error_hint (json);
    376     break;
    377   case MHD_HTTP_NOT_FOUND:
    378     pr.hr.ec = TALER_JSON_get_error_code (json);
    379     pr.hr.hint = TALER_JSON_get_error_hint (json);
    380     break;
    381   case MHD_HTTP_REQUEST_TIMEOUT:
    382     pr.hr.ec = TALER_JSON_get_error_code (json);
    383     pr.hr.hint = TALER_JSON_get_error_hint (json);
    384     break;
    385   case MHD_HTTP_CONFLICT:
    386     TALER_MERCHANT_parse_error_details_ (json,
    387                                          MHD_HTTP_CONFLICT,
    388                                          &pr.hr);
    389     {
    390       const char *eu = json_string_value (
    391         json_object_get (json, "exchange_url"));
    392 
    393       pr.details.conflict.exchange_url = eu;
    394       pr.details.conflict.exchange_ec = pr.hr.exchange_code;
    395       pr.details.conflict.exchange_http_status
    396         = pr.hr.exchange_http_status;
    397     }
    398     break;
    399   case MHD_HTTP_GONE:
    400     TALER_MERCHANT_parse_error_details_ (json,
    401                                          response_code,
    402                                          &pr.hr);
    403     break;
    404   case MHD_HTTP_PRECONDITION_FAILED:
    405     TALER_MERCHANT_parse_error_details_ (json,
    406                                          response_code,
    407                                          &pr.hr);
    408     break;
    409   case MHD_HTTP_UNAVAILABLE_FOR_LEGAL_REASONS:
    410     {
    411       json_t *ebus = json_object_get (json,
    412                                       "exchange_base_urls");
    413       if (NULL == ebus)
    414       {
    415         GNUNET_break_op (0);
    416         pr.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
    417         pr.hr.http_status = 0;
    418         pr.hr.hint
    419           = "failed to parse exchange_base_urls field in response";
    420         break;
    421       }
    422       {
    423         size_t alen = json_array_size (ebus);
    424 
    425         if (alen > MAX_EXCHANGE_BASE_URLS)
    426         {
    427           /* Bound the stack VLA below by an untrusted response. */
    428           GNUNET_break_op (0);
    429           pr.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
    430           pr.hr.http_status = 0;
    431           pr.hr.hint = "too many exchange_base_urls in response";
    432           break;
    433         }
    434         {
    435           const char *ebua[GNUNET_NZL (alen)];
    436           size_t idx;
    437           json_t *jebu;
    438           bool ok = true;
    439 
    440           json_array_foreach (ebus, idx, jebu)
    441           {
    442             ebua[idx] = json_string_value (jebu);
    443             if (NULL == ebua[idx])
    444             {
    445               GNUNET_break_op (0);
    446               pr.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
    447               pr.hr.http_status = 0;
    448               pr.hr.hint
    449                 = "non-string value in exchange_base_urls in response";
    450               ok = false;
    451               break;
    452             }
    453           }
    454           if (! ok)
    455             break;
    456           pr.details.unavailable_for_legal_reasons.num_exchanges
    457             = (unsigned int) alen;
    458           pr.details.unavailable_for_legal_reasons.exchanges
    459             = ebua;
    460           poph->cb (poph->cb_cls,
    461                     &pr);
    462           TALER_MERCHANT_post_orders_pay_cancel (poph);
    463           return;
    464         }
    465       }
    466     }
    467     break;
    468   case MHD_HTTP_INTERNAL_SERVER_ERROR:
    469     TALER_MERCHANT_parse_error_details_ (json,
    470                                          response_code,
    471                                          &pr.hr);
    472     break;
    473   case MHD_HTTP_NOT_IMPLEMENTED:
    474     TALER_MERCHANT_parse_error_details_ (json,
    475                                          response_code,
    476                                          &pr.hr);
    477     break;
    478   case MHD_HTTP_BAD_GATEWAY:
    479     TALER_MERCHANT_parse_error_details_ (json,
    480                                          response_code,
    481                                          &pr.hr);
    482     {
    483       const char *eu = json_string_value (
    484         json_object_get (json, "exchange_url"));
    485 
    486       pr.details.bad_gateway.exchange_url = eu;
    487       pr.details.bad_gateway.exchange_ec = pr.hr.exchange_code;
    488       pr.details.bad_gateway.exchange_http_status
    489         = pr.hr.exchange_http_status;
    490     }
    491     break;
    492   case MHD_HTTP_GATEWAY_TIMEOUT:
    493     TALER_MERCHANT_parse_error_details_ (json,
    494                                          response_code,
    495                                          &pr.hr);
    496     break;
    497   default:
    498     TALER_MERCHANT_parse_error_details_ (json,
    499                                          response_code,
    500                                          &pr.hr);
    501     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    502                 "Unexpected response code %u/%d\n",
    503                 (unsigned int) response_code,
    504                 (int) pr.hr.ec);
    505     GNUNET_break_op (0);
    506     break;
    507   }
    508   poph->cb (poph->cb_cls,
    509             &pr);
    510   if (poph->am_wallet &&
    511       (MHD_HTTP_OK == response_code) )
    512   {
    513     for (unsigned int i = 0; i < pr.details.ok.num_tokens; i++)
    514     {
    515       struct GNUNET_CRYPTO_BlindedSignature *bs
    516         = pr.details.ok.tokens[i].blinded_sig.signature;
    517 
    518       if (NULL != bs)
    519         GNUNET_CRYPTO_blinded_sig_decref (bs);
    520     }
    521     GNUNET_array_grow (pr.details.ok.tokens,
    522                        pr.details.ok.num_tokens,
    523                        0);
    524   }
    525   TALER_MERCHANT_post_orders_pay_cancel (poph);
    526 }
    527 
    528 
    529 struct TALER_MERCHANT_PostOrdersPayHandle *
    530 TALER_MERCHANT_post_orders_pay_frontend_create (
    531   struct GNUNET_CURL_Context *ctx,
    532   const char *url,
    533   const char *order_id,
    534   unsigned int num_coins,
    535   const struct TALER_MERCHANT_PostOrdersPayPaidCoin coins[static num_coins])
    536 {
    537   struct TALER_MERCHANT_PostOrdersPayHandle *poph;
    538 
    539   poph = GNUNET_new (struct TALER_MERCHANT_PostOrdersPayHandle);
    540   poph->ctx = ctx;
    541   poph->base_url = GNUNET_strdup (url);
    542   poph->order_id = GNUNET_strdup (order_id);
    543   poph->am_wallet = false;
    544   poph->num_paid_coins = num_coins;
    545   poph->paid_coins = GNUNET_new_array (
    546     num_coins,
    547     struct TALER_MERCHANT_PostOrdersPayPaidCoin);
    548   for (unsigned int i = 0; i < num_coins; i++)
    549   {
    550     struct TALER_MERCHANT_PostOrdersPayPaidCoin *dst = &poph->paid_coins[i];
    551     const struct TALER_MERCHANT_PostOrdersPayPaidCoin *src = &coins[i];
    552 
    553     *dst = *src;
    554     /* deep copy fields that need it */
    555     TALER_denom_pub_copy (&dst->denom_pub,
    556                           &src->denom_pub);
    557     TALER_denom_sig_copy (&dst->denom_sig,
    558                           &src->denom_sig);
    559     dst->exchange_url = GNUNET_strdup (src->exchange_url);
    560   }
    561   return poph;
    562 }
    563 
    564 
    565 struct TALER_MERCHANT_PostOrdersPayHandle *
    566 TALER_MERCHANT_post_orders_pay_create (
    567   struct GNUNET_CURL_Context *ctx,
    568   const char *url,
    569   const char *order_id,
    570   const struct TALER_PrivateContractHashP *h_contract_terms,
    571   const struct TALER_Amount *amount,
    572   const struct TALER_Amount *max_fee,
    573   const struct TALER_MerchantPublicKeyP *merchant_pub,
    574   const struct TALER_MerchantSignatureP *merchant_sig,
    575   struct GNUNET_TIME_Timestamp timestamp,
    576   struct GNUNET_TIME_Timestamp refund_deadline,
    577   struct GNUNET_TIME_Timestamp pay_deadline,
    578   const struct TALER_MerchantWireHashP *h_wire,
    579   unsigned int num_coins,
    580   const struct TALER_MERCHANT_PostOrdersPayCoin coins[static num_coins])
    581 {
    582   struct TALER_MERCHANT_PostOrdersPayHandle *poph;
    583 
    584   if (GNUNET_YES !=
    585       TALER_amount_cmp_currency (amount,
    586                                  max_fee))
    587   {
    588     GNUNET_break (0);
    589     return NULL;
    590   }
    591 
    592   poph = GNUNET_new (struct TALER_MERCHANT_PostOrdersPayHandle);
    593   poph->ctx = ctx;
    594   poph->base_url = GNUNET_strdup (url);
    595   poph->order_id = GNUNET_strdup (order_id);
    596   poph->am_wallet = true;
    597   poph->h_contract_terms = *h_contract_terms;
    598   poph->choice_index = -1;
    599   poph->amount = *amount;
    600   poph->max_fee = *max_fee;
    601   poph->merchant_pub = *merchant_pub;
    602   poph->merchant_sig = *merchant_sig;
    603   poph->timestamp = timestamp;
    604   poph->refund_deadline = refund_deadline;
    605   poph->pay_deadline = pay_deadline;
    606   poph->h_wire = *h_wire;
    607   poph->num_coins = num_coins;
    608   poph->coins = GNUNET_new_array (num_coins,
    609                                   struct TALER_MERCHANT_PostOrdersPayCoin);
    610   for (unsigned int i = 0; i < num_coins; i++)
    611   {
    612     struct TALER_MERCHANT_PostOrdersPayCoin *dst = &poph->coins[i];
    613     const struct TALER_MERCHANT_PostOrdersPayCoin *src = &coins[i];
    614 
    615     *dst = *src;
    616     TALER_denom_pub_copy (&dst->denom_pub,
    617                           &src->denom_pub);
    618     TALER_denom_sig_copy (&dst->denom_sig,
    619                           &src->denom_sig);
    620     dst->exchange_url = GNUNET_strdup (src->exchange_url);
    621   }
    622   return poph;
    623 }
    624 
    625 
    626 enum GNUNET_GenericReturnValue
    627 TALER_MERCHANT_post_orders_pay_set_options_ (
    628   struct TALER_MERCHANT_PostOrdersPayHandle *poph,
    629   unsigned int num_options,
    630   const struct TALER_MERCHANT_PostOrdersPayOptionValue *options)
    631 {
    632   for (unsigned int i = 0; i < num_options; i++)
    633   {
    634     switch (options[i].option)
    635     {
    636     case TALER_MERCHANT_POST_ORDERS_PAY_OPTION_END:
    637       return GNUNET_OK;
    638     case TALER_MERCHANT_POST_ORDERS_PAY_OPTION_SESSION_ID:
    639       GNUNET_free (poph->session_id);
    640       if (NULL != options[i].details.session_id)
    641         poph->session_id = GNUNET_strdup (options[i].details.session_id);
    642       break;
    643     case TALER_MERCHANT_POST_ORDERS_PAY_OPTION_WALLET_DATA:
    644       json_decref (poph->wallet_data);
    645       poph->wallet_data = NULL;
    646       if (NULL != options[i].details.wallet_data)
    647         poph->wallet_data = json_incref (
    648           (json_t *) options[i].details.wallet_data);
    649       break;
    650     case TALER_MERCHANT_POST_ORDERS_PAY_OPTION_USED_TOKENS:
    651       GNUNET_free (poph->used_tokens);
    652       poph->num_used_tokens = options[i].details.used_tokens.num;
    653       if (0 < poph->num_used_tokens)
    654       {
    655         poph->used_tokens = GNUNET_new_array (
    656           poph->num_used_tokens,
    657           struct TALER_MERCHANT_PostOrdersPayUsedToken);
    658         GNUNET_memcpy (poph->used_tokens,
    659                        options[i].details.used_tokens.tokens,
    660                        poph->num_used_tokens
    661                        * sizeof (struct TALER_MERCHANT_PostOrdersPayUsedToken));
    662       }
    663       break;
    664     case TALER_MERCHANT_POST_ORDERS_PAY_OPTION_USE_TOKENS:
    665       GNUNET_free (poph->use_tokens);
    666       poph->num_use_tokens = options[i].details.use_tokens.num;
    667       if (0 < poph->num_use_tokens)
    668       {
    669         poph->use_tokens = GNUNET_new_array (
    670           poph->num_use_tokens,
    671           struct TALER_MERCHANT_PostOrdersPayUseToken);
    672         GNUNET_memcpy (poph->use_tokens,
    673                        options[i].details.use_tokens.tokens,
    674                        poph->num_use_tokens
    675                        * sizeof (struct TALER_MERCHANT_PostOrdersPayUseToken));
    676       }
    677       break;
    678     case TALER_MERCHANT_POST_ORDERS_PAY_OPTION_OUTPUT_TOKENS:
    679       GNUNET_free (poph->output_tokens);
    680       poph->num_output_tokens = options[i].details.output_tokens.num;
    681       if (0 < poph->num_output_tokens)
    682       {
    683         poph->output_tokens = GNUNET_new_array (
    684           poph->num_output_tokens,
    685           struct TALER_MERCHANT_PostOrdersPayOutputToken);
    686         GNUNET_memcpy (
    687           poph->output_tokens,
    688           options[i].details.output_tokens.tokens,
    689           poph->num_output_tokens
    690           * sizeof (struct TALER_MERCHANT_PostOrdersPayOutputToken));
    691       }
    692       break;
    693     case TALER_MERCHANT_POST_ORDERS_PAY_OPTION_OUTPUT_TOKENS_JSON:
    694       json_decref (poph->output_tokens_json);
    695       poph->output_tokens_json = NULL;
    696       if (NULL != options[i].details.output_tokens_json)
    697         poph->output_tokens_json = json_incref (
    698           options[i].details.output_tokens_json);
    699       break;
    700     case TALER_MERCHANT_POST_ORDERS_PAY_OPTION_OUTPUT_DONAU:
    701       if (NULL != poph->donau_url)
    702       {
    703         GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    704                     "Only one set of donation receipts is allowed to be specified\n");
    705         return GNUNET_NO;
    706       }
    707       poph->donau_url
    708         = GNUNET_strdup (options[i].details.output_donau.donau_base_url);
    709       poph->donau_year
    710         = options[i].details.output_donau.year;
    711       poph->num_donau_bkps = options[i].details.output_donau.num_bkps;
    712       poph->donau_bkps = GNUNET_new_array (
    713         poph->num_donau_bkps,
    714         struct DONAU_BlindedUniqueDonorIdentifierKeyPair);
    715       for (size_t j=0; j<poph->num_donau_bkps; j++)
    716       {
    717         const struct DONAU_BlindedUniqueDonorIdentifierKeyPair *src
    718           = &options[i].details.output_donau.bkps[j];
    719         struct DONAU_BlindedUniqueDonorIdentifierKeyPair *dst
    720           = &poph->donau_bkps[j];
    721 
    722         dst->h_donation_unit_pub = src->h_donation_unit_pub;
    723         dst->blinded_udi.blinded_message
    724           = GNUNET_CRYPTO_blinded_message_incref (
    725               src->blinded_udi.blinded_message);
    726       }
    727       break;
    728     case TALER_MERCHANT_POST_ORDERS_PAY_OPTION_CHOICE_INDEX:
    729       poph->choice_index = options[i].details.choice_index;
    730       break;
    731     default:
    732       GNUNET_break (0);
    733       return GNUNET_SYSERR;
    734     }
    735   }
    736   return GNUNET_OK;
    737 }
    738 
    739 
    740 enum TALER_ErrorCode
    741 TALER_MERCHANT_post_orders_pay_start (
    742   struct TALER_MERCHANT_PostOrdersPayHandle *poph,
    743   TALER_MERCHANT_PostOrdersPayCallback cb,
    744   TALER_MERCHANT_POST_ORDERS_PAY_RESULT_CLOSURE *cb_cls)
    745 {
    746   json_t *pay_obj;
    747   json_t *j_coins;
    748   json_t *j_tokens = NULL;
    749   json_t *j_output_tokens = NULL;
    750   CURL *eh;
    751 
    752   poph->cb = cb;
    753   poph->cb_cls = cb_cls;
    754   {
    755     char *path;
    756 
    757     GNUNET_asprintf (&path,
    758                      "orders/%s/pay",
    759                      poph->order_id);
    760     poph->url = TALER_url_join (poph->base_url,
    761                                 path,
    762                                 NULL);
    763     GNUNET_free (path);
    764   }
    765   if (NULL == poph->url)
    766     return TALER_EC_GENERIC_CONFIGURATION_INVALID;
    767 
    768   if (poph->am_wallet)
    769   {
    770     /* Wallet mode: sign coins and tokens, build wallet_data */
    771     json_t *wallet_data = poph->wallet_data;
    772     json_t *j_donau_data = NULL;
    773     struct GNUNET_HashCode wallet_data_hash;
    774 
    775     if (NULL != poph->donau_url)
    776     {
    777       json_t *budis;
    778 
    779       budis = json_array ();
    780       GNUNET_assert (NULL != budis);
    781       for (size_t i=0; i<poph->num_donau_bkps; i++)
    782       {
    783         const struct DONAU_BlindedUniqueDonorIdentifierKeyPair *bkp
    784           = &poph->donau_bkps[i];
    785         json_t *budikeypair = GNUNET_JSON_PACK (
    786           GNUNET_JSON_pack_data_auto ("h_donation_unit_pub",
    787                                       &bkp->h_donation_unit_pub),
    788           DONAU_JSON_pack_blinded_donation_identifier ("blinded_udi",
    789                                                        &bkp->blinded_udi));
    790 
    791         GNUNET_assert (0 ==
    792                        json_array_append_new (budis,
    793                                               budikeypair));
    794       }
    795 
    796       j_donau_data = GNUNET_JSON_PACK (
    797         GNUNET_JSON_pack_string ("url",
    798                                  poph->donau_url),
    799         GNUNET_JSON_pack_int64 ("year",
    800                                 poph->donau_year),
    801         GNUNET_JSON_pack_array_steal ("budikeypairs",
    802                                       budis));
    803     }
    804 
    805     /* Build output token envelopes JSON if we have output tokens */
    806     if (0 < poph->num_output_tokens)
    807     {
    808       j_output_tokens = json_array ();
    809       GNUNET_assert (NULL != j_output_tokens);
    810       for (unsigned int i = 0; i < poph->num_output_tokens; i++)
    811       {
    812         json_t *j_token_ev;
    813         const struct TALER_MERCHANT_PostOrdersPayOutputToken *ev
    814           = &poph->output_tokens[i];
    815 
    816         j_token_ev = GNUNET_JSON_PACK (
    817           TALER_JSON_pack_token_envelope (NULL,
    818                                           &ev->envelope));
    819         if (0 !=
    820             json_array_append_new (j_output_tokens,
    821                                    j_token_ev))
    822         {
    823           GNUNET_break (0);
    824           json_decref (j_output_tokens);
    825           json_decref (j_donau_data);
    826           return TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE;
    827         }
    828       }
    829     }
    830     else if (NULL != poph->output_tokens_json)
    831     {
    832       j_output_tokens = json_incref (poph->output_tokens_json);
    833     }
    834 
    835     /* Build wallet_data if choice_index is valid */
    836     if (0 <= poph->choice_index)
    837     {
    838       if (NULL == wallet_data)
    839       {
    840         wallet_data = GNUNET_JSON_PACK (
    841           GNUNET_JSON_pack_int64 ("choice_index",
    842                                   poph->choice_index),
    843           GNUNET_JSON_pack_allow_null (
    844             GNUNET_JSON_pack_object_incref ("donau",
    845                                             j_donau_data)),
    846           GNUNET_JSON_pack_allow_null (
    847             GNUNET_JSON_pack_array_incref ("tokens_evs",
    848                                            j_output_tokens)));
    849       }
    850       TALER_json_hash (wallet_data,
    851                        &wallet_data_hash);
    852     }
    853     json_decref (j_donau_data);
    854     j_donau_data = NULL;
    855 
    856     if ( (0 < poph->num_use_tokens || 0 < poph->num_output_tokens
    857           || NULL != poph->output_tokens_json)
    858          && (0 > poph->choice_index) )
    859     {
    860       GNUNET_break (0);
    861       json_decref (j_output_tokens);
    862       if ( (NULL == poph->wallet_data) &&
    863            (NULL != wallet_data) )
    864         json_decref (wallet_data);
    865       return TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE;
    866     }
    867 
    868     /* Sign coins */
    869     j_coins = json_array ();
    870     GNUNET_assert (NULL != j_coins);
    871     for (unsigned int i = 0; i < poph->num_coins; i++)
    872     {
    873       const struct TALER_MERCHANT_PostOrdersPayCoin *coin = &poph->coins[i];
    874       struct TALER_CoinSpendPublicKeyP coin_pub;
    875       struct TALER_CoinSpendSignatureP coin_sig;
    876       struct TALER_Amount fee;
    877       struct TALER_DenominationHashP h_denom_pub;
    878       json_t *j_coin;
    879 
    880       if (0 >
    881           TALER_amount_subtract (&fee,
    882                                  &coin->amount_with_fee,
    883                                  &coin->amount_without_fee))
    884       {
    885         GNUNET_break (0);
    886         json_decref (j_coins);
    887         json_decref (j_output_tokens);
    888         if ( (NULL == poph->wallet_data) &&
    889              (NULL != wallet_data) )
    890           json_decref (wallet_data);
    891         return TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE;
    892       }
    893       TALER_denom_pub_hash (&coin->denom_pub,
    894                             &h_denom_pub);
    895       TALER_wallet_deposit_sign (&coin->amount_with_fee,
    896                                  &fee,
    897                                  &poph->h_wire,
    898                                  &poph->h_contract_terms,
    899                                  (0 <= poph->choice_index)
    900                                  ? &wallet_data_hash
    901                                  : NULL,
    902                                  GNUNET_is_zero (&coin->h_age_commitment)
    903                                  ? NULL
    904                                  : &coin->h_age_commitment,
    905                                  NULL /* h_extensions */,
    906                                  &h_denom_pub,
    907                                  poph->timestamp,
    908                                  &poph->merchant_pub,
    909                                  poph->refund_deadline,
    910                                  &coin->coin_priv,
    911                                  &coin_sig);
    912       GNUNET_CRYPTO_eddsa_key_get_public (&coin->coin_priv.eddsa_priv,
    913                                           &coin_pub.eddsa_pub);
    914       j_coin = GNUNET_JSON_PACK (
    915         TALER_JSON_pack_amount ("contribution",
    916                                 &coin->amount_with_fee),
    917         GNUNET_JSON_pack_data_auto ("coin_pub",
    918                                     &coin_pub),
    919         GNUNET_JSON_pack_string ("exchange_url",
    920                                  coin->exchange_url),
    921         GNUNET_JSON_pack_data_auto ("h_denom",
    922                                     &h_denom_pub),
    923         TALER_JSON_pack_denom_sig ("ub_sig",
    924                                    &coin->denom_sig),
    925         GNUNET_JSON_pack_data_auto ("coin_sig",
    926                                     &coin_sig));
    927       if (0 !=
    928           json_array_append_new (j_coins,
    929                                  j_coin))
    930       {
    931         GNUNET_break (0);
    932         json_decref (j_coins);
    933         json_decref (j_output_tokens);
    934         if ( (NULL == poph->wallet_data) &&
    935              (NULL != wallet_data) )
    936           json_decref (wallet_data);
    937         return TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE;
    938       }
    939     }
    940 
    941     /* Sign use tokens */
    942     if (0 < poph->num_use_tokens)
    943     {
    944       j_tokens = json_array ();
    945       GNUNET_assert (NULL != j_tokens);
    946       for (unsigned int i = 0; i < poph->num_use_tokens; i++)
    947       {
    948         const struct TALER_MERCHANT_PostOrdersPayUseToken *token
    949           = &poph->use_tokens[i];
    950         struct TALER_TokenUseSignatureP token_sig;
    951         struct TALER_TokenUsePublicKeyP token_pub;
    952         json_t *j_token;
    953 
    954         TALER_wallet_token_use_sign (&poph->h_contract_terms,
    955                                      &wallet_data_hash,
    956                                      &token->token_priv,
    957                                      &token_sig);
    958         GNUNET_CRYPTO_eddsa_key_get_public (
    959           &token->token_priv.private_key,
    960           &token_pub.public_key);
    961         j_token = GNUNET_JSON_PACK (
    962           GNUNET_JSON_pack_data_auto ("token_sig",
    963                                       &token_sig),
    964           GNUNET_JSON_pack_data_auto ("token_pub",
    965                                       &token_pub),
    966           GNUNET_JSON_pack_data_auto (
    967             "h_issue",
    968             &token->issue_pub.public_key->pub_key_hash),
    969           TALER_JSON_pack_token_issue_sig ("ub_sig",
    970                                            &token->ub_sig));
    971         if (0 !=
    972             json_array_append_new (j_tokens,
    973                                    j_token))
    974         {
    975           GNUNET_break (0);
    976           json_decref (j_coins);
    977           json_decref (j_tokens);
    978           json_decref (j_output_tokens);
    979           if ( (NULL == poph->wallet_data) &&
    980                (NULL != wallet_data) )
    981             json_decref (wallet_data);
    982           return TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE;
    983         }
    984       }
    985     }
    986 
    987     pay_obj = GNUNET_JSON_PACK (
    988       GNUNET_JSON_pack_array_steal ("coins",
    989                                     j_coins),
    990       GNUNET_JSON_pack_allow_null (
    991         GNUNET_JSON_pack_array_steal ("tokens",
    992                                       j_tokens)),
    993       GNUNET_JSON_pack_allow_null (
    994         GNUNET_JSON_pack_object_incref ("wallet_data",
    995                                         wallet_data)),
    996       GNUNET_JSON_pack_allow_null (
    997         GNUNET_JSON_pack_string ("session_id",
    998                                  poph->session_id)));
    999     if ( (NULL == poph->wallet_data) &&
   1000          (NULL != wallet_data) )
   1001       json_decref (wallet_data);
   1002     json_decref (j_output_tokens);
   1003   }
   1004   else
   1005   {
   1006     /* Frontend mode: coins are already signed */
   1007     j_coins = json_array ();
   1008     GNUNET_assert (NULL != j_coins);
   1009     for (unsigned int i = 0; i < poph->num_paid_coins; i++)
   1010     {
   1011       const struct TALER_MERCHANT_PostOrdersPayPaidCoin *pc
   1012         = &poph->paid_coins[i];
   1013       struct TALER_DenominationHashP denom_hash;
   1014       json_t *j_coin;
   1015 
   1016       TALER_denom_pub_hash (&pc->denom_pub,
   1017                             &denom_hash);
   1018       j_coin = GNUNET_JSON_PACK (
   1019         TALER_JSON_pack_amount ("contribution",
   1020                                 &pc->amount_with_fee),
   1021         GNUNET_JSON_pack_data_auto ("coin_pub",
   1022                                     &pc->coin_pub),
   1023         GNUNET_JSON_pack_string ("exchange_url",
   1024                                  pc->exchange_url),
   1025         GNUNET_JSON_pack_data_auto ("h_denom",
   1026                                     &denom_hash),
   1027         TALER_JSON_pack_denom_sig ("ub_sig",
   1028                                    &pc->denom_sig),
   1029         GNUNET_JSON_pack_data_auto ("coin_sig",
   1030                                     &pc->coin_sig));
   1031       if (0 !=
   1032           json_array_append_new (j_coins,
   1033                                  j_coin))
   1034       {
   1035         GNUNET_break (0);
   1036         json_decref (j_coins);
   1037         return TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE;
   1038       }
   1039     }
   1040 
   1041     /* Build used tokens JSON (frontend mode) */
   1042     if (0 < poph->num_used_tokens)
   1043     {
   1044       j_tokens = json_array ();
   1045       GNUNET_assert (NULL != j_tokens);
   1046       for (unsigned int i = 0; i < poph->num_used_tokens; i++)
   1047       {
   1048         const struct TALER_MERCHANT_PostOrdersPayUsedToken *ut
   1049           = &poph->used_tokens[i];
   1050         json_t *j_token;
   1051 
   1052         j_token = GNUNET_JSON_PACK (
   1053           GNUNET_JSON_pack_data_auto ("token_sig",
   1054                                       &ut->token_sig),
   1055           GNUNET_JSON_pack_data_auto ("token_pub",
   1056                                       &ut->token_pub),
   1057           GNUNET_JSON_pack_data_auto (
   1058             "h_issue",
   1059             &ut->issue_pub.public_key->pub_key_hash),
   1060           TALER_JSON_pack_token_issue_sig ("ub_sig",
   1061                                            &ut->ub_sig));
   1062         if (0 !=
   1063             json_array_append_new (j_tokens,
   1064                                    j_token))
   1065         {
   1066           GNUNET_break (0);
   1067           json_decref (j_coins);
   1068           json_decref (j_tokens);
   1069           return TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE;
   1070         }
   1071       }
   1072     }
   1073 
   1074     pay_obj = GNUNET_JSON_PACK (
   1075       GNUNET_JSON_pack_array_steal ("coins",
   1076                                     j_coins),
   1077       GNUNET_JSON_pack_allow_null (
   1078         GNUNET_JSON_pack_array_steal ("tokens",
   1079                                       j_tokens)),
   1080       GNUNET_JSON_pack_allow_null (
   1081         GNUNET_JSON_pack_object_incref ("wallet_data",
   1082                                         poph->wallet_data)),
   1083       GNUNET_JSON_pack_allow_null (
   1084         GNUNET_JSON_pack_string ("session_id",
   1085                                  poph->session_id)));
   1086   }
   1087 
   1088   eh = TALER_MERCHANT_curl_easy_get_ (poph->url);
   1089   if ( (NULL == eh) ||
   1090        (GNUNET_OK !=
   1091         TALER_curl_easy_post (&poph->post_ctx,
   1092                               eh,
   1093                               pay_obj)) )
   1094   {
   1095     GNUNET_break (0);
   1096     json_decref (pay_obj);
   1097     if (NULL != eh)
   1098       curl_easy_cleanup (eh);
   1099     return TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE;
   1100   }
   1101   json_decref (pay_obj);
   1102   poph->job = GNUNET_CURL_job_add2 (poph->ctx,
   1103                                     eh,
   1104                                     poph->post_ctx.headers,
   1105                                     &handle_pay_finished,
   1106                                     poph);
   1107   if (NULL == poph->job)
   1108     return TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE;
   1109   return TALER_EC_NONE;
   1110 }
   1111 
   1112 
   1113 void
   1114 TALER_MERCHANT_post_orders_pay_cancel (
   1115   struct TALER_MERCHANT_PostOrdersPayHandle *poph)
   1116 {
   1117   if (NULL != poph->job)
   1118   {
   1119     GNUNET_CURL_job_cancel (poph->job);
   1120     poph->job = NULL;
   1121   }
   1122   TALER_curl_easy_post_finished (&poph->post_ctx);
   1123   if (NULL != poph->paid_coins)
   1124   {
   1125     for (unsigned int i = 0; i < poph->num_paid_coins; i++)
   1126     {
   1127       TALER_denom_pub_free (&poph->paid_coins[i].denom_pub);
   1128       TALER_denom_sig_free (&poph->paid_coins[i].denom_sig);
   1129       GNUNET_free (poph->paid_coins[i].exchange_url);
   1130     }
   1131     GNUNET_free (poph->paid_coins);
   1132   }
   1133   if (NULL != poph->coins)
   1134   {
   1135     for (unsigned int i = 0; i < poph->num_coins; i++)
   1136     {
   1137       TALER_denom_pub_free (&poph->coins[i].denom_pub);
   1138       TALER_denom_sig_free (&poph->coins[i].denom_sig);
   1139       GNUNET_free (poph->coins[i].exchange_url);
   1140     }
   1141     GNUNET_free (poph->coins);
   1142   }
   1143   for (size_t j = 0; j<poph->num_donau_bkps; j++)
   1144   {
   1145     struct DONAU_BlindedUniqueDonorIdentifierKeyPair *bpk
   1146       = &poph->donau_bkps[j];
   1147 
   1148     GNUNET_CRYPTO_blinded_message_decref (bpk->blinded_udi.blinded_message);
   1149   }
   1150   GNUNET_free (poph->donau_bkps);
   1151   GNUNET_free (poph->donau_url);
   1152   GNUNET_free (poph->used_tokens);
   1153   GNUNET_free (poph->use_tokens);
   1154   GNUNET_free (poph->output_tokens);
   1155   json_decref (poph->output_tokens_json);
   1156   json_decref (poph->wallet_data);
   1157   GNUNET_free (poph->session_id);
   1158   GNUNET_free (poph->order_id);
   1159   GNUNET_free (poph->url);
   1160   GNUNET_free (poph->base_url);
   1161   GNUNET_free (poph);
   1162 }
   1163 
   1164 
   1165 /* end of merchant_api_post-orders-ORDER_ID-pay-new.c */