merchant

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

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


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