merchant

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

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


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