LCOV - code coverage report
Current view: top level - testing - testing_api_cmd_pay_order.c (source / functions) Coverage Total Hit
Test: coverage.info Lines: 77.5 % 476 369
Test Date: 2026-09-11 17:45:24 Functions: 100.0 % 11 11

            Line data    Source code
       1              : /*
       2              :   This file is part of TALER
       3              :   Copyright (C) 2014-2024 Taler Systems SA
       4              : 
       5              :   TALER is free software; you can redistribute it and/or modify
       6              :   it under the terms of the GNU General Public License as
       7              :   published by the Free Software Foundation; either version 3, or
       8              :   (at your option) any later version.
       9              : 
      10              :   TALER is distributed in the hope that it will be useful, but
      11              :   WITHOUT ANY WARRANTY; without even the implied warranty of
      12              :   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      13              :   GNU General Public License for more details.
      14              : 
      15              :   You should have received a copy of the GNU General Public
      16              :   License along with TALER; see the file COPYING.  If not, see
      17              :   <http://www.gnu.org/licenses/>
      18              : */
      19              : /**
      20              :  * @file src/testing/testing_api_cmd_pay_order.c
      21              :  * @brief command to test the /orders/ID/pay feature.
      22              :  * @author Marcello Stanisci
      23              :  * @author Christian Grothoff
      24              :  */
      25              : #include "platform.h"
      26              : struct PayState;
      27              : #define TALER_MERCHANT_POST_ORDERS_PAY_RESULT_CLOSURE struct PayState
      28              : #include <gnunet/gnunet_common.h>
      29              : #include <gnunet/gnunet_json_lib.h>
      30              : #include <gnunet/gnunet_time_lib.h>
      31              : #include <jansson.h>
      32              : #include <stddef.h>
      33              : #include <stdint.h>
      34              : #include <taler/taler_exchange_service.h>
      35              : #include <taler/taler_testing_lib.h>
      36              : #include <taler/taler_signatures.h>
      37              : #include "taler/taler_merchant_service.h"
      38              : #include "taler/taler_merchant_testing_lib.h"
      39              : #include <taler/merchant/post-orders-ORDER_ID-pay.h>
      40              : #include <donau/donau_service.h>
      41              : #include <donau/donau_testing_lib.h>
      42              : #include <donau/donau_json_lib.h>
      43              : 
      44              : 
      45              : /**
      46              :  * Struct for handling the CS approach in signing of the bkps
      47              :  */
      48              : struct CSR_Data
      49              : {
      50              :   /**
      51              :    * Handle to the "batch issue receipt status" operation.
      52              :    */
      53              :   struct DONAU_CsRBatchIssueHandle *csr_handle;
      54              : 
      55              :   /**
      56              :    * CS-Nonce
      57              :    */
      58              :   union GNUNET_CRYPTO_BlindSessionNonce nonce;
      59              : 
      60              :   /**
      61              :    * batch issue receipt status state
      62              :    */
      63              :   struct StatusState *ss;
      64              : 
      65              :   /**
      66              :    * array position in batch issue receipt request (first position is zero)
      67              :    */
      68              :   size_t position;
      69              : };
      70              : 
      71              : /**
      72              :  * Handling all data needed for the /pay DONAU CMD.
      73              :  */
      74              : struct MerchantDonauPayData
      75              : {
      76              :   /**
      77              :    * Donau URL.
      78              :    */
      79              :   char *donau_url;
      80              : 
      81              :   /**
      82              :    * Donau keys
      83              :    */
      84              :   struct DONAU_Keys *keys;
      85              : 
      86              :   /**
      87              :    * Charity reference
      88              :    */
      89              :   const char *charity_reference;
      90              : 
      91              :   /**
      92              :    * Charity id
      93              :    */
      94              :   uint64_t charity_id;
      95              : 
      96              :   /**
      97              :    * Amount of the donation
      98              :    */
      99              :   struct TALER_Amount donation_amount;
     100              : 
     101              :   /**
     102              :    * Number of BUDIs to create or fetch. Example only.
     103              :    */
     104              :   size_t num_bkps;
     105              : 
     106              :   /**
     107              :    * Year of the donation
     108              :    */
     109              :   uint64_t year;
     110              : 
     111              :   /**
     112              :    * Selected donation unit pub keys for this pay order request
     113              :    */
     114              :   struct DONAU_DonationUnitPublicKey *selected_pks;
     115              : 
     116              :   /**
     117              :    * BUDI key pairs used in the payment (blinded_udi + pubkey).
     118              :    */
     119              :   struct DONAU_BlindedUniqueDonorIdentifierKeyPair *bkps;
     120              : 
     121              :   /**
     122              :    * Blinding secrets, if needed for each BUDI (CS vs. RSA).
     123              :    */
     124              :   union GNUNET_CRYPTO_BlindingSecretP *blinding_secrets;
     125              : 
     126              :   /**
     127              :    * Blinding values. Cs-nonces, cipher.
     128              :    */
     129              :   const struct DONAU_BatchIssueValues **alg_values;
     130              : 
     131              :   /**
     132              :    * Hash of the salted donor tax id, if relevant.
     133              :    */
     134              :   struct DONAU_HashDonorTaxId h_donor_tax_id;
     135              : 
     136              :   /**
     137              :    * Array of donation receipts;
     138              :    */
     139              :   struct DONAU_DonationReceipt *receipts;
     140              : 
     141              :   /**
     142              :    * Array of hashed udis.
     143              :    */
     144              :   struct DONAU_UniqueDonorIdentifierHashP *h_udis;
     145              : 
     146              :   /**
     147              :    * If using the CS approach, we might track how many
     148              :    * asynchronous calls are still pending, etc.
     149              :    */
     150              :   unsigned int cs_pending;
     151              : };
     152              : 
     153              : 
     154              : /**
     155              :  * Prepares the donau data for the /pay CMD.
     156              :  *
     157              :  * @param is interpreter state
     158              :  * @param ss donau data to prepare
     159              :  * @return #GNUNET_OK on success,
     160              :  *         #GNUNET_NO to skip
     161              :  *         #GNUNET_SYSERR on failure
     162              :  */
     163              : static enum GNUNET_GenericReturnValue
     164            2 : prepare_donau_data (struct TALER_TESTING_Interpreter *is,
     165              :                     struct MerchantDonauPayData *ss)
     166              : {
     167              :   /* Get charity id and the charity private key from trait */
     168              :   {
     169              :     const struct TALER_TESTING_Command *charity_post_cmd;
     170              :     const uint64_t *charity_id;
     171              : 
     172            2 :     charity_post_cmd = TALER_TESTING_interpreter_lookup_command (
     173              :       is,
     174              :       ss->charity_reference);
     175              : 
     176            2 :     if (GNUNET_OK !=
     177            2 :         TALER_TESTING_get_trait_charity_id (charity_post_cmd,
     178              :                                             &charity_id))
     179              :     {
     180            0 :       GNUNET_break (0);
     181            0 :       return GNUNET_SYSERR;
     182              :     }
     183            2 :     ss->charity_id = (uint64_t) *(charity_id);
     184              :   }
     185              : 
     186              :   /* Get donau keys from trait */
     187              :   {
     188              :     const struct TALER_TESTING_Command *keys_cmd;
     189              :     struct DONAU_Keys *keys;
     190              : 
     191            2 :     keys_cmd = TALER_TESTING_interpreter_get_command (is,
     192              :                                                       "donau");
     193              : 
     194            2 :     if (GNUNET_OK !=
     195            2 :         TALER_TESTING_get_trait_donau_keys (keys_cmd,
     196              :                                             &keys))
     197              :     {
     198            0 :       GNUNET_break (0);
     199            0 :       return GNUNET_SYSERR;
     200              :     }
     201            2 :     ss->keys = keys;
     202              :   }
     203              : 
     204              :   /* Get selected_pks + num_bkps*/
     205              :   {
     206              :     enum GNUNET_GenericReturnValue sret;
     207              : 
     208            2 :     sret = DONAU_select_donation_unit_keys_for_amount (
     209            2 :       ss->keys,
     210            2 :       &ss->donation_amount,
     211              :       ss->year,
     212              :       &ss->selected_pks,
     213              :       &ss->num_bkps);
     214              : 
     215            2 :     if (GNUNET_SYSERR == sret)
     216              :     {
     217            0 :       GNUNET_break (0);
     218            0 :       TALER_TESTING_interpreter_fail (is);
     219            0 :       return GNUNET_SYSERR;
     220              :     }
     221            2 :     if ( (GNUNET_NO == sret) ||
     222            2 :          (0 == ss->num_bkps) )
     223              :     {
     224            0 :       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
     225              :                   "Could not compose exact amount from donation units\n");
     226            0 :       TALER_TESTING_interpreter_fail (is);
     227            0 :       return GNUNET_SYSERR;
     228              :     }
     229              :   }
     230              : 
     231              :   /* Get BUDIsKP */
     232              :   {
     233              :     ss->bkps
     234            2 :       = GNUNET_new_array (ss->num_bkps,
     235              :                           struct DONAU_BlindedUniqueDonorIdentifierKeyPair);
     236              :     ss->blinding_secrets
     237            2 :       = GNUNET_new_array (ss->num_bkps,
     238              :                           union GNUNET_CRYPTO_BlindingSecretP);
     239              :     ss->receipts
     240            2 :       = GNUNET_new_array (ss->num_bkps,
     241              :                           struct DONAU_DonationReceipt);
     242              :     ss->alg_values
     243            2 :       = GNUNET_new_array (ss->num_bkps,
     244              :                           const struct DONAU_BatchIssueValues *);
     245              :     ss->h_udis
     246            2 :       = GNUNET_new_array (ss->num_bkps,
     247              :                           struct DONAU_UniqueDonorIdentifierHashP);
     248              : 
     249            3 :     for (size_t cnt = 0; cnt < ss->num_bkps; cnt++)
     250              :     {
     251              :       struct DONAU_UniqueDonorIdentifierNonce *udi_nonce;
     252              :       struct DONAU_BudiMasterSecretP ps;
     253              :       const struct DONAU_BatchIssueValues *alg_values;
     254              :       struct DONAU_BlindedUniqueDonorIdentifier *blinded_udi;
     255              :       struct DONAU_UniqueDonorIdentifierHashP *udi_hash;
     256              : 
     257            2 :       DONAU_donation_unit_pub_hash (&ss->selected_pks[cnt],
     258            2 :                                     &ss->bkps[cnt].h_donation_unit_pub);
     259              : 
     260            2 :       ss->receipts[cnt].h_donation_unit_pub
     261            2 :         = ss->bkps[cnt].h_donation_unit_pub;
     262              :       udi_nonce
     263            2 :         = &ss->receipts[cnt].nonce;
     264              :       blinded_udi
     265            2 :         = &ss->bkps[cnt].blinded_udi;
     266            2 :       udi_hash = &ss->h_udis[cnt];
     267              : 
     268            2 :       GNUNET_CRYPTO_random_block (&ps,
     269              :                                   sizeof (ps));
     270            2 :       GNUNET_CRYPTO_random_block (udi_nonce,
     271              :                                   sizeof (*udi_nonce));
     272            2 :       switch (ss->selected_pks[cnt].bsign_pub_key->cipher)
     273              :       {
     274            1 :       case GNUNET_CRYPTO_BSA_RSA:
     275            1 :         alg_values = DONAU_donation_unit_ewv_rsa_singleton ();
     276            1 :         DONAU_budi_secret_create (&ps,
     277              :                                   alg_values,
     278            1 :                                   &ss->blinding_secrets[cnt]);
     279            1 :         GNUNET_assert (GNUNET_OK ==
     280              :                        DONAU_donation_unit_blind (
     281              :                          &ss->selected_pks[cnt],
     282              :                          &ss->blinding_secrets[cnt],
     283              :                          NULL,                    /* no cs-nonce needed for rsa */
     284              :                          udi_nonce,
     285              :                          &ss->h_donor_tax_id,
     286              :                          alg_values,
     287              :                          udi_hash,
     288              :                          blinded_udi));
     289            1 :         ss->alg_values[cnt] = alg_values;
     290            1 :         break;
     291            1 :       case GNUNET_CRYPTO_BSA_CS:
     292            1 :         GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
     293              :                     "CS donation-unit key not yet supported – skip");
     294            1 :         return GNUNET_NO;
     295              :         /* FIXME: BUG-#### Cs support missing/broken for donau
     296              :         struct CSR_Data *csr_data = GNUNET_new (struct CSR_Data);
     297              :         TALER_cs_withdraw_nonce_derive ( // FIXME: write new method
     298              :           (struct TALER_PlanchetMasterSecretP *) &ps,
     299              :           &csr_data->nonce.cs_nonce);
     300              :         csr_data->ss = is;
     301              :         csr_data->position = cnt;
     302              : 
     303              :         csr_data->csr_handle = DONAU_csr_issue (
     304              :           TALER_TESTING_interpreter_get_context (is),
     305              :           TALER_TESTING_get_donau_url (is),
     306              :           &ss->selected_pks[cnt],
     307              :           &csr_data->nonce.cs_nonce,
     308              :           &cs_stage_two_callback,
     309              :           csr_data);
     310              :         if (NULL == csr_data->csr_handle)
     311              :         {
     312              :           GNUNET_break (0);
     313              :         }
     314              :         ss->cs_pending++; */
     315              :         break;
     316            0 :       default:
     317            0 :         GNUNET_break (0);
     318              :       }
     319              :     }
     320              :   }
     321            1 :   return GNUNET_OK;
     322              : }
     323              : 
     324              : 
     325              : /**
     326              :  * All the details about a token that are generated during issuance and
     327              :  * that may be needed for future operations on the coin.
     328              :  */
     329              : struct TALER_MERCHANT_PrivateTokenDetails
     330              : {
     331              : 
     332              :   /**
     333              :    * Master secret used to derive the private key from.
     334              :    */
     335              :   struct TALER_TokenUseMasterSecretP master;
     336              : 
     337              :   /**
     338              :    * Private key of the token.
     339              :    */
     340              :   struct TALER_TokenUsePrivateKeyP token_priv;
     341              : 
     342              :   /**
     343              :    * Public key of the token.
     344              :    */
     345              :   struct TALER_TokenUsePublicKeyP token_pub;
     346              : 
     347              :   /**
     348              :    * Public key of the token.
     349              :    */
     350              :   struct TALER_TokenUsePublicKeyHashP h_token_pub;
     351              : 
     352              :   /**
     353              :    * Blinded public key of the token.
     354              :    */
     355              :   struct TALER_TokenEnvelope envelope;
     356              : 
     357              :   /**
     358              :    * Value used to blind the key for the signature.
     359              :    */
     360              :   union GNUNET_CRYPTO_BlindingSecretP blinding_secret;
     361              : 
     362              :   /**
     363              :    * Inputs needed from the merchant for blind signing.
     364              :    */
     365              :   struct TALER_TokenUseMerchantValues blinding_inputs;
     366              : 
     367              :   /**
     368              :    * Token issue public key.
     369              :    */
     370              :   struct TALER_TokenIssuePublicKey issue_pub;
     371              : 
     372              :   /**
     373              :    * Unblinded token issue signature made by the merchant.
     374              :    */
     375              :   struct TALER_TokenIssueSignature issue_sig;
     376              : 
     377              :   /**
     378              :    * Blinded token issue signature made by the merchant.
     379              :    */
     380              :   struct TALER_BlindedTokenIssueSignature blinded_sig;
     381              : 
     382              : };
     383              : 
     384              : 
     385              : /**
     386              :  * State for a /pay CMD.
     387              :  */
     388              : struct PayState
     389              : {
     390              :   /**
     391              :    * Contract terms hash code.
     392              :    */
     393              :   struct TALER_PrivateContractHashP h_contract_terms;
     394              : 
     395              :   /**
     396              :    * The interpreter state.
     397              :    */
     398              :   struct TALER_TESTING_Interpreter *is;
     399              : 
     400              :   /**
     401              :    * Expected HTTP response status code.
     402              :    */
     403              :   unsigned int http_status;
     404              : 
     405              :   /**
     406              :    * Reference to a command that can provide a order id,
     407              :    * typically a /proposal test command.
     408              :    */
     409              :   const char *proposal_reference;
     410              : 
     411              :   /**
     412              :    * Reference to a command that can provide a coin, so
     413              :    * we can pay here.
     414              :    */
     415              :   const char *coin_reference;
     416              : 
     417              :   /**
     418              :    * Reference to a command that can provide one or
     419              :    * multiple tokens used as inputs for the payment.
     420              :    * In the form "LABEL0[/INDEX];LABEL1[/INDEX];..."
     421              :    */
     422              :   const char *token_reference;
     423              : 
     424              :   /**
     425              :    * The merchant base URL.
     426              :    */
     427              :   const char *merchant_url;
     428              : 
     429              :   /**
     430              :    * Total amount to be paid.
     431              :    */
     432              :   struct TALER_Amount total_amount;
     433              : 
     434              :   /**
     435              :    * Amount to be paid, plus the deposit fee.
     436              :    */
     437              :   const char *amount_with_fee;
     438              : 
     439              :   /**
     440              :    * Parsed version of @e amount_with_fee, kept in persistent
     441              :    * command state so it can be safely exposed via the amount trait.
     442              :    */
     443              :   struct TALER_Amount amount_with_fee_parsed;
     444              : 
     445              :   /**
     446              :    * Amount to be paid, including NO fees.
     447              :    */
     448              :   const char *amount_without_fee;
     449              : 
     450              :   /**
     451              :    * Handle to the pay operation.
     452              :    */
     453              :   struct TALER_MERCHANT_PostOrdersPayHandle *oph;
     454              : 
     455              :   /**
     456              :    * Signature from the merchant, set on success.
     457              :    */
     458              :   struct TALER_MerchantSignatureP merchant_sig;
     459              : 
     460              :   /**
     461              :    * Array of issued tokens, set on success.
     462              :    */
     463              :   struct TALER_MERCHANT_PrivateTokenDetails *issued_tokens;
     464              : 
     465              :   /**
     466              :    * Number of tokens in @e issued_tokens.
     467              :    */
     468              :   unsigned int num_issued_tokens;
     469              : 
     470              :   /**
     471              :    * Number of donau_tokens in @e issued_tokens.
     472              :    */
     473              :   unsigned int num_donau_tokens;
     474              : 
     475              :   /**
     476              :    * The session for which the payment is made.
     477              :    */
     478              :   const char *session_id;
     479              : 
     480              :   /**
     481              :    * base64-encoded key
     482              :    */
     483              :   const char *pos_key;
     484              : 
     485              :   /**
     486              :    * Option that add amount of the order
     487              :    */
     488              :   enum TALER_MerchantConfirmationAlgorithm pos_alg;
     489              : 
     490              :   /**
     491              :    * Index of the choice to be used in the payment. -1 for orders without choices.
     492              :    */
     493              :   int choice_index;
     494              : 
     495              :   /**
     496              :    * Donau data, if required.
     497              :    */
     498              :   struct MerchantDonauPayData donau_data;
     499              : };
     500              : 
     501              : 
     502              : /**
     503              :  * Find the token issue public key for a given token family @a slug and
     504              :  * @a valid_after timestamp.
     505              :  *
     506              :  * @param token_families json object of token families where the key is the slug
     507              :  * @param slug the slug of the token family
     508              :  * @param key_index index of the key within the token family
     509              :  * @param[out] pub the token issue public key of the token family
     510              :  * @return #GNUNET_OK on success and #GNUNET_SYSERR if not found
     511              :  */
     512              : static enum GNUNET_GenericReturnValue
     513            6 : find_token_public_key (const json_t *token_families,
     514              :                        const char *slug,
     515              :                        unsigned int key_index,
     516              :                        struct TALER_TokenIssuePublicKey *pub)
     517              : 
     518              : {
     519            6 :   const json_t *tf = json_object_get (token_families, slug);
     520              :   const json_t *keys;
     521              :   struct GNUNET_JSON_Specification spec[] = {
     522            6 :     GNUNET_JSON_spec_array_const ("keys",
     523              :                                   &keys),
     524            6 :     GNUNET_JSON_spec_end ()
     525              :   };
     526              :   const json_t *key;
     527              :   const char *error_name;
     528              :   unsigned int error_line;
     529              :   struct GNUNET_JSON_Specification ispec[] = {
     530            6 :     TALER_JSON_spec_token_pub (NULL,
     531              :                                pub),
     532            6 :     GNUNET_JSON_spec_end ()
     533              :   };
     534              : 
     535            6 :   if (NULL == tf)
     536              :   {
     537            0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     538              :                 "Token family `%s' not found\n",
     539              :                 slug);
     540            0 :     return GNUNET_SYSERR;
     541              :   }
     542            6 :   if (GNUNET_OK !=
     543            6 :       GNUNET_JSON_parse (tf,
     544              :                          spec,
     545              :                          NULL,
     546              :                          NULL))
     547              :   {
     548            0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     549              :                 "Failed to parse token family `%s'\n",
     550              :                 slug);
     551            0 :     return GNUNET_SYSERR;
     552              :   }
     553              : 
     554            6 :   key = json_array_get (keys,
     555              :                         key_index);
     556            6 :   if (NULL == key)
     557              :   {
     558            0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     559              :                 "Key with index %u for token family '%s' not found\n",
     560              :                 key_index,
     561              :                 slug);
     562            0 :     return GNUNET_SYSERR;
     563              :   }
     564            6 :   if (GNUNET_OK !=
     565            6 :       GNUNET_JSON_parse (key,
     566              :                          ispec,
     567              :                          &error_name,
     568              :                          &error_line))
     569              :   {
     570            0 :     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
     571              :                 "Failed to parse %s at %u: %s\n",
     572              :                 ispec[error_line].field,
     573              :                 error_line,
     574              :                 error_name);
     575            0 :     return GNUNET_SYSERR;
     576              :   }
     577            6 :   return GNUNET_OK;
     578              : }
     579              : 
     580              : 
     581              : /**
     582              :  * Parse the @a coins specification and grow the @a pc
     583              :  * array with the coins found, updating @a npc.
     584              :  *
     585              :  * @param[in,out] pc pointer to array of coins found
     586              :  * @param[in,out] npc length of array at @a pc
     587              :  * @param[in] coins string specifying coins to add to @a pc,
     588              :  *            clobbered in the process
     589              :  * @param is interpreter state
     590              :  * @param amount_with_fee total amount to be paid for a contract.
     591              :  * @param amount_without_fee to be removed, there is no
     592              :  *        per-contract fee, only per-coin exists.
     593              :  * @return #GNUNET_OK on success
     594              :  */
     595              : static enum GNUNET_GenericReturnValue
     596           46 : build_coins (struct TALER_MERCHANT_PostOrdersPayCoin **pc,
     597              :              unsigned int *npc,
     598              :              char *coins,
     599              :              struct TALER_TESTING_Interpreter *is,
     600              :              const char *amount_with_fee,
     601              :              const char *amount_without_fee)
     602              : {
     603              :   char *token;
     604              :   struct TALER_EXCHANGE_Keys *keys;
     605              : 
     606           46 :   keys = TALER_TESTING_get_keys (is);
     607           46 :   if (NULL == keys)
     608              :   {
     609            0 :     GNUNET_break (0);
     610            0 :     return GNUNET_SYSERR;
     611              :   }
     612              : 
     613           46 :   for (token = strtok (coins, ";");
     614           94 :        NULL != token;
     615           48 :        token = strtok (NULL, ";"))
     616              :   {
     617              :     const struct TALER_TESTING_Command *coin_cmd;
     618              :     char *ctok;
     619              :     unsigned int ci;
     620              :     struct TALER_MERCHANT_PostOrdersPayCoin *icoin;
     621              :     const struct TALER_EXCHANGE_DenomPublicKey *dpk;
     622              :     const char *exchange_url;
     623              : 
     624              :     /* Token syntax is "LABEL[/NUMBER]" */
     625           48 :     ctok = strchr (token, '/');
     626              :     /* FIXME: Check why ci variable is parsed but not used? */
     627           48 :     ci = 0;
     628           48 :     if (NULL != ctok)
     629              :     {
     630            0 :       *ctok = '\0';
     631            0 :       ctok++;
     632            0 :       if (1 != sscanf (ctok,
     633              :                        "%u",
     634              :                        &ci))
     635              :       {
     636            0 :         GNUNET_break (0);
     637            0 :         return GNUNET_SYSERR;
     638              :       }
     639              :     }
     640              : 
     641           48 :     coin_cmd = TALER_TESTING_interpreter_lookup_command
     642              :                  (is, token);
     643              : 
     644           48 :     if (NULL == coin_cmd)
     645              :     {
     646            0 :       GNUNET_break (0);
     647            0 :       return GNUNET_SYSERR;
     648              :     }
     649              : 
     650           48 :     GNUNET_array_grow (*pc,
     651              :                        *npc,
     652              :                        (*npc) + 1);
     653              : 
     654           48 :     icoin = &((*pc)[(*npc) - 1]);
     655              : 
     656              :     {
     657              :       const struct TALER_CoinSpendPrivateKeyP *coin_priv;
     658              :       const struct TALER_DenominationSignature *denom_sig;
     659              :       const struct TALER_Amount *denom_value;
     660              :       const struct TALER_EXCHANGE_DenomPublicKey *denom_pub;
     661              :       const struct TALER_AgeCommitmentHashP *h_age_commitment;
     662              : 
     663           48 :       GNUNET_assert (GNUNET_OK ==
     664              :                      TALER_TESTING_get_trait_coin_priv (coin_cmd,
     665              :                                                         0,
     666              :                                                         &coin_priv));
     667           48 :       GNUNET_assert (GNUNET_OK ==
     668              :                      TALER_TESTING_get_trait_denom_pub (coin_cmd,
     669              :                                                         0,
     670              :                                                         &denom_pub));
     671           48 :       GNUNET_assert (GNUNET_OK ==
     672              :                      TALER_TESTING_get_trait_denom_sig (coin_cmd,
     673              :                                                         0,
     674              :                                                         &denom_sig));
     675           48 :       GNUNET_assert (GNUNET_OK ==
     676              :                      TALER_TESTING_get_trait_amount (coin_cmd,
     677              :                                                      &denom_value));
     678           48 :       GNUNET_assert (GNUNET_OK ==
     679              :                      TALER_TESTING_get_trait_h_age_commitment (coin_cmd,
     680              :                                                                0,
     681              :                                                                &h_age_commitment
     682              :                                                                ));
     683           48 :       icoin->coin_priv = *coin_priv;
     684           48 :       icoin->denom_pub = denom_pub->key;
     685           48 :       icoin->denom_sig = *denom_sig;
     686           48 :       icoin->denom_value = *denom_value;
     687           48 :       icoin->amount_with_fee = *denom_value;
     688           48 :       if (NULL != h_age_commitment)
     689            0 :         icoin->h_age_commitment = *h_age_commitment;
     690              :     }
     691           48 :     GNUNET_assert (NULL != (dpk =
     692              :                               TALER_TESTING_find_pk (keys,
     693              :                                                      &icoin->denom_value,
     694              :                                                      false)));
     695              : 
     696           48 :     GNUNET_assert (0 <=
     697              :                    TALER_amount_subtract (&icoin->amount_without_fee,
     698              :                                           &icoin->denom_value,
     699              :                                           &dpk->fees.deposit));
     700           48 :     GNUNET_assert (GNUNET_OK ==
     701              :                    TALER_TESTING_get_trait_exchange_url (coin_cmd,
     702              :                                                          &exchange_url));
     703           48 :     icoin->exchange_url = (char *) exchange_url;
     704              :   }
     705              : 
     706           46 :   return GNUNET_OK;
     707              : }
     708              : 
     709              : 
     710              : /**
     711              :  * Parse the @a pay_references specification and grow the @a tokens
     712              :  * array with the tokens found, updating @a tokens_num.
     713              :  *
     714              :  * @param[in,out] tokens array of tokens found
     715              :  * @param[in,out] tokens_num length of @a tokens array
     716              :  * @param[in] pay_references string of ; separated references to pay commands
     717              :               that issued the tokens.
     718              :  * @param is interpreter state
     719              :  * @return #GNUNET_OK on success
     720              :  */
     721              : static enum GNUNET_GenericReturnValue
     722            4 : build_tokens (struct TALER_MERCHANT_PostOrdersPayUseToken **tokens,
     723              :               unsigned int *tokens_num,
     724              :               char *pay_references,
     725              :               struct TALER_TESTING_Interpreter *is)
     726              : {
     727              :   char *ref;
     728              : 
     729            4 :   for (ref = strtok (pay_references, ";");
     730            8 :        NULL != ref;
     731            4 :        ref = strtok (NULL, ";"))
     732              :   {
     733              :     const struct TALER_TESTING_Command *pay_cmd;
     734              :     char *slash;
     735              :     unsigned int index;
     736              :     struct TALER_MERCHANT_PostOrdersPayUseToken *token;
     737              : 
     738              :     /* Reference syntax is "LABEL[/NUMBER]" */
     739            4 :     slash = strchr (ref, '/');
     740            4 :     index = 0;
     741            4 :     if (NULL != slash)
     742              :     {
     743            0 :       *slash = '\0';
     744            0 :       slash++;
     745            0 :       if (1 != sscanf (slash,
     746              :                        "%u",
     747              :                        &index))
     748              :       {
     749            0 :         GNUNET_break (0);
     750            0 :         return GNUNET_SYSERR;
     751              :       }
     752              :     }
     753              : 
     754            4 :     pay_cmd = TALER_TESTING_interpreter_lookup_command (is, ref);
     755              : 
     756            4 :     if (NULL == pay_cmd)
     757              :     {
     758            0 :       GNUNET_break (0);
     759            0 :       return GNUNET_SYSERR;
     760              :     }
     761              : 
     762            4 :     GNUNET_array_grow (*tokens,
     763              :                        *tokens_num,
     764              :                        (*tokens_num) + 1);
     765              : 
     766            4 :     token = &((*tokens)[(*tokens_num) - 1]);
     767              : 
     768              :     {
     769              :       const struct TALER_TokenUsePrivateKeyP *token_priv;
     770              :       const struct TALER_TokenIssueSignature *issue_sig;
     771              :       const struct TALER_TokenIssuePublicKey *issue_pub;
     772              : 
     773            4 :       GNUNET_assert (GNUNET_OK ==
     774              :                      TALER_TESTING_get_trait_token_priv (pay_cmd,
     775              :                                                          index,
     776              :                                                          &token_priv));
     777              : 
     778            4 :       GNUNET_assert (GNUNET_OK ==
     779              :                      TALER_TESTING_get_trait_token_issue_sig (pay_cmd,
     780              :                                                               index,
     781              :                                                               &issue_sig));
     782              : 
     783            4 :       GNUNET_assert (GNUNET_OK ==
     784              :                      TALER_TESTING_get_trait_token_issue_pub (pay_cmd,
     785              :                                                               index,
     786              :                                                               &issue_pub));
     787              : 
     788            4 :       token->token_priv = *token_priv;
     789            4 :       token->ub_sig = *issue_sig;
     790            4 :       token->issue_pub = *issue_pub;
     791              :     }
     792              :   }
     793              : 
     794            4 :   return GNUNET_OK;
     795              : }
     796              : 
     797              : 
     798              : /**
     799              :  * Function called with the result of a /pay operation.
     800              :  * Checks whether the merchant signature is valid and the
     801              :  * HTTP response code matches our expectation.
     802              :  *
     803              :  * @param cls closure with the interpreter state
     804              :  * @param pr HTTP response
     805              :  */
     806              : static void
     807           46 : pay_cb (struct PayState *ps,
     808              :         const struct TALER_MERCHANT_PostOrdersPayResponse *pr)
     809              : {
     810              : 
     811           46 :   ps->oph = NULL;
     812           46 :   if (ps->http_status != pr->hr.http_status)
     813              :   {
     814            0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     815              :                 "Unexpected response code %u (%d) to command (%s) %s\n",
     816              :                 pr->hr.http_status,
     817              :                 (int) pr->hr.ec,
     818              :                 pr->hr.hint,
     819              :                 TALER_TESTING_interpreter_get_current_label (ps->is));
     820            0 :     TALER_TESTING_FAIL (ps->is);
     821              :   }
     822           46 :   if (MHD_HTTP_OK == pr->hr.http_status)
     823              :   {
     824           32 :     ps->merchant_sig = pr->details.ok.merchant_sig;
     825           32 :     if (ps->num_issued_tokens + ps->num_donau_tokens !=
     826           32 :         pr->details.ok.num_tokens)
     827              :     {
     828            0 :       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     829              :                   "Unexpected number of tokens issued. "
     830              :                   "Sent %d envelopes but got %d tokens issued.\n",
     831              :                   ps->num_issued_tokens,
     832              :                   pr->details.ok.num_tokens);
     833            0 :       GNUNET_break (0);
     834            0 :       TALER_TESTING_interpreter_fail (ps->is);
     835            0 :       return;
     836              :     }
     837           36 :     for (unsigned int i = 0; i < ps->num_issued_tokens; i++)
     838              :     {
     839            4 :       struct TALER_MERCHANT_PrivateTokenDetails *details =
     840            4 :         &ps->issued_tokens[i];
     841              : 
     842              :       /* The issued tokens should be in the
     843              :          same order as the provided envelopes. */
     844            4 :       ps->issued_tokens[i].blinded_sig = pr->details.ok.tokens[i].blinded_sig;
     845              : 
     846            4 :       if (GNUNET_OK !=
     847            4 :           TALER_token_issue_sig_unblind (&details->issue_sig,
     848            4 :                                          &details->blinded_sig,
     849            4 :                                          &details->blinding_secret,
     850            4 :                                          &details->h_token_pub,
     851            4 :                                          &details->blinding_inputs,
     852            4 :                                          &details->issue_pub))
     853              :       {
     854            0 :         GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     855              :                     "Failed to unblind token signature\n");
     856            0 :         GNUNET_break (0);
     857            0 :         TALER_TESTING_interpreter_fail (ps->is);
     858            0 :         return;
     859              :       }
     860              :     }
     861           32 :     if (NULL != ps->pos_key)
     862              :     {
     863              :       char *pc;
     864            2 :       bool found = false;
     865              : 
     866            2 :       if (NULL == pr->details.ok.pos_confirmation)
     867              :       {
     868            0 :         GNUNET_break (0);
     869            0 :         TALER_TESTING_interpreter_fail (ps->is);
     870            0 :         return;
     871              :       }
     872            2 :       pc = TALER_build_pos_confirmation (ps->pos_key,
     873              :                                          ps->pos_alg,
     874            2 :                                          &ps->total_amount,
     875              :                                          GNUNET_TIME_timestamp_get ());
     876              :       /* Check if *any* of our TOTP codes overlaps
     877              :          with any of the returned TOTP codes. */
     878            2 :       for (const char *tok = strtok (pc, "\n");
     879            2 :            NULL != tok;
     880            0 :            tok = strtok (NULL, "\n"))
     881              :       {
     882            2 :         if (NULL != strstr (pr->details.ok.pos_confirmation,
     883              :                             tok))
     884              :         {
     885            2 :           found = true;
     886            2 :           break;
     887              :         }
     888              :       }
     889            2 :       GNUNET_free (pc);
     890            2 :       if (! found)
     891              :       {
     892            0 :         GNUNET_break (0);
     893            0 :         TALER_TESTING_interpreter_fail (ps->is);
     894            0 :         return;
     895              :       }
     896              :     }
     897              :   }
     898           46 :   TALER_TESTING_interpreter_next (ps->is);
     899              : }
     900              : 
     901              : 
     902              : /**
     903              :  * Run a "pay" CMD.
     904              :  *
     905              :  * @param cls closure.
     906              :  * @param cmd current CMD being run.
     907              :  * @param is interpreter state.
     908              :  */
     909              : static void
     910           47 : pay_run (void *cls,
     911              :          const struct TALER_TESTING_Command *cmd,
     912              :          struct TALER_TESTING_Interpreter *is)
     913              : {
     914           47 :   struct PayState *ps = cls;
     915              :   const struct TALER_TESTING_Command *proposal_cmd;
     916              :   const json_t *contract_terms;
     917              :   const char *order_id;
     918              :   struct GNUNET_TIME_Timestamp refund_deadline;
     919              :   struct GNUNET_TIME_Timestamp pay_deadline;
     920              :   struct GNUNET_TIME_Timestamp timestamp;
     921              :   struct TALER_MerchantPublicKeyP merchant_pub;
     922              :   struct TALER_MerchantWireHashP h_wire;
     923              :   const struct TALER_PrivateContractHashP *h_proposal;
     924              :   struct TALER_Amount max_fee;
     925           47 :   const char *error_name = NULL;
     926           47 :   unsigned int error_line = 0;
     927              :   struct TALER_MERCHANT_PostOrdersPayCoin *pay_coins;
     928              :   unsigned int npay_coins;
     929           47 :   struct TALER_MERCHANT_PostOrdersPayUseToken *use_tokens = NULL;
     930           47 :   unsigned int len_use_tokens = 0;
     931           47 :   struct TALER_MERCHANT_PostOrdersPayOutputToken *output_tokens = NULL;
     932           47 :   unsigned int len_output_tokens = 0;
     933              :   const struct TALER_MerchantSignatureP *merchant_sig;
     934              :   const enum TALER_MerchantConfirmationAlgorithm *alg_ptr;
     935              : 
     936           47 :   ps->is = is;
     937           47 :   proposal_cmd = TALER_TESTING_interpreter_lookup_command (
     938              :     is,
     939              :     ps->proposal_reference);
     940              : 
     941           47 :   if (NULL == proposal_cmd)
     942            1 :     TALER_TESTING_FAIL (is);
     943              : 
     944           47 :   if (GNUNET_OK !=
     945           47 :       TALER_TESTING_get_trait_contract_terms (proposal_cmd,
     946              :                                               &contract_terms))
     947            0 :     TALER_TESTING_FAIL (is);
     948           47 :   if (NULL == contract_terms)
     949            0 :     TALER_TESTING_FAIL (is);
     950           47 :   if (GNUNET_OK !=
     951           47 :       TALER_TESTING_get_trait_otp_key (proposal_cmd,
     952              :                                        &ps->pos_key))
     953           41 :     ps->pos_key = NULL;
     954           47 :   if ( (GNUNET_OK ==
     955           47 :         TALER_TESTING_get_trait_otp_alg (proposal_cmd,
     956            6 :                                          &alg_ptr)) &&
     957            6 :        (NULL != alg_ptr) )
     958            2 :     ps->pos_alg = *alg_ptr;
     959              :   {
     960              :     /* Get information that needs to be put verbatim in the
     961              :      * deposit permission */
     962           47 :     uint64_t version = 0;
     963              :     struct GNUNET_JSON_Specification spec[] = {
     964           47 :       GNUNET_JSON_spec_mark_optional (
     965              :         GNUNET_JSON_spec_uint64 ("version",
     966              :                                  &version),
     967              :         NULL),
     968           47 :       TALER_JSON_spec_slug ("order_id",
     969              :                             &order_id),
     970           47 :       GNUNET_JSON_spec_timestamp ("refund_deadline",
     971              :                                   &refund_deadline),
     972           47 :       GNUNET_JSON_spec_timestamp ("pay_deadline",
     973              :                                   &pay_deadline),
     974           47 :       GNUNET_JSON_spec_timestamp ("timestamp",
     975              :                                   &timestamp),
     976           47 :       GNUNET_JSON_spec_fixed_auto ("merchant_pub",
     977              :                                    &merchant_pub),
     978           47 :       GNUNET_JSON_spec_fixed_auto ("h_wire",
     979              :                                    &h_wire),
     980              :       /* FIXME oec: parse minimum age, use data later? */
     981           47 :       GNUNET_JSON_spec_end ()
     982              :     };
     983              : 
     984           47 :     if (GNUNET_OK !=
     985           47 :         GNUNET_JSON_parse (contract_terms,
     986              :                            spec,
     987              :                            &error_name,
     988              :                            &error_line))
     989              :     {
     990              :       char *js;
     991              : 
     992            0 :       js = json_dumps (contract_terms,
     993              :                        JSON_INDENT (1));
     994            0 :       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     995              :                   "Parser failed on %s:%u for input `%s'\n",
     996              :                   error_name,
     997              :                   error_line,
     998              :                   js);
     999            0 :       free (js);
    1000            1 :       TALER_TESTING_FAIL (is);
    1001              :     }
    1002           47 :     switch (version)
    1003              :     {
    1004           33 :     case 0:
    1005              :       {
    1006              :         struct GNUNET_JSON_Specification v0spec[] = {
    1007           33 :           TALER_JSON_spec_amount_any ("amount",
    1008              :                                       &ps->total_amount),
    1009           33 :           TALER_JSON_spec_amount_any ("max_fee",
    1010              :                                       &max_fee),
    1011           33 :           GNUNET_JSON_spec_end ()
    1012              :         };
    1013              : 
    1014           33 :         if (GNUNET_OK !=
    1015           33 :             GNUNET_JSON_parse (contract_terms,
    1016              :                                v0spec,
    1017              :                                &error_name,
    1018              :                                &error_line))
    1019              :         {
    1020              :           char *js;
    1021              : 
    1022            0 :           js = json_dumps (contract_terms,
    1023              :                            JSON_INDENT (1));
    1024            0 :           GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    1025              :                       "Parser failed on %s:%u for input `%s'\n",
    1026              :                       error_name,
    1027              :                       error_line,
    1028              :                       js);
    1029            0 :           free (js);
    1030            0 :           TALER_TESTING_FAIL (is);
    1031              :         }
    1032              :       }
    1033           33 :       if (0 < ps->choice_index)
    1034            0 :         TALER_TESTING_FAIL (is);
    1035           33 :       break;
    1036           14 :     case 1:
    1037              :       {
    1038              :         const json_t *choices;
    1039              :         const json_t *token_families;
    1040              :         struct GNUNET_JSON_Specification v1spec[] = {
    1041           14 :           GNUNET_JSON_spec_object_const ("token_families",
    1042              :                                          &token_families),
    1043           14 :           GNUNET_JSON_spec_array_const ("choices",
    1044              :                                         &choices),
    1045           14 :           GNUNET_JSON_spec_end ()
    1046              :         };
    1047              :         const json_t *outputs;
    1048              :         json_t *output;
    1049              :         unsigned int output_index;
    1050              :         const json_t *choice;
    1051              : 
    1052           14 :         if (GNUNET_OK !=
    1053           14 :             GNUNET_JSON_parse (contract_terms,
    1054              :                                v1spec,
    1055              :                                &error_name,
    1056              :                                &error_line))
    1057              :         {
    1058              :           char *js;
    1059              : 
    1060            0 :           js = json_dumps (contract_terms,
    1061              :                            JSON_INDENT (1));
    1062            0 :           GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    1063              :                       "Parser failed on %s:%u for input `%s'\n",
    1064              :                       error_name,
    1065              :                       error_line,
    1066              :                       js);
    1067            0 :           free (js);
    1068            1 :           TALER_TESTING_FAIL (is);
    1069              :         }
    1070              : 
    1071           14 :         choice = json_array_get (choices,
    1072           14 :                                  ps->choice_index);
    1073           14 :         if (NULL == choice)
    1074              :         {
    1075            0 :           GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    1076              :                       "No choice found at index %d\n",
    1077              :                       ps->choice_index);
    1078            0 :           TALER_TESTING_FAIL (is);
    1079              :         }
    1080              : 
    1081              :         {
    1082           14 :           const char *ierror_name = NULL;
    1083           14 :           unsigned int ierror_line = 0;
    1084              : 
    1085              :           struct GNUNET_JSON_Specification ispec[] = {
    1086           14 :             TALER_JSON_spec_amount_any ("amount",
    1087              :                                         &ps->total_amount),
    1088           14 :             TALER_JSON_spec_amount_any ("max_fee",
    1089              :                                         &max_fee),
    1090           14 :             GNUNET_JSON_spec_array_const ("outputs",
    1091              :                                           &outputs),
    1092           14 :             GNUNET_JSON_spec_end ()
    1093              :           };
    1094              : 
    1095           14 :           if (GNUNET_OK !=
    1096           14 :               GNUNET_JSON_parse (choice,
    1097              :                                  ispec,
    1098              :                                  &ierror_name,
    1099              :                                  &ierror_line))
    1100              :           {
    1101            0 :             GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    1102              :                         "Parser failed on %s:%u for input `%s'\n",
    1103              :                         ierror_name,
    1104              :                         ierror_line,
    1105              :                         json_dumps (choice,
    1106              :                                     JSON_INDENT (2)));
    1107            0 :             TALER_TESTING_FAIL (is);
    1108              :           }
    1109              :         }
    1110              : 
    1111           21 :         json_array_foreach (outputs, output_index, output)
    1112              :         {
    1113              :           const char *slug;
    1114              :           const char *kind;
    1115              :           uint32_t key_index;
    1116            8 :           uint32_t count = 1;
    1117            8 :           const char *ierror_name = NULL;
    1118            8 :           unsigned int ierror_line = 0;
    1119              : 
    1120              :           struct GNUNET_JSON_Specification typespec[] = {
    1121            8 :             GNUNET_JSON_spec_string ("type",
    1122              :                                      &kind),
    1123            8 :             GNUNET_JSON_spec_end ()
    1124              :           };
    1125              : 
    1126            8 :           if (GNUNET_OK !=
    1127            8 :               GNUNET_JSON_parse (output,
    1128              :                                  typespec,
    1129              :                                  &ierror_name,
    1130              :                                  &ierror_line))
    1131              :           {
    1132            0 :             GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    1133              :                         "Parser failed on %s:%u for input `%s'\n",
    1134              :                         ierror_name,
    1135              :                         ierror_line,
    1136              :                         json_dumps (output,
    1137              :                                     JSON_INDENT (2)));
    1138            1 :             TALER_TESTING_FAIL (is);
    1139              :           }
    1140              : 
    1141            8 :           if (0 == strcmp ("tax-receipt",
    1142              :                            kind))
    1143              :           {
    1144              :             const json_t *donau_urls;
    1145              : 
    1146              :             // For test, we care only about the presence of it
    1147              :             struct GNUNET_JSON_Specification donauspec[] = {
    1148            2 :               GNUNET_JSON_spec_array_const ("donau_urls",
    1149              :                                             &donau_urls),
    1150            2 :               GNUNET_JSON_spec_end ()
    1151              :             };
    1152              : 
    1153            2 :             if (GNUNET_OK !=
    1154            2 :                 GNUNET_JSON_parse (output,
    1155              :                                    donauspec,
    1156              :                                    &ierror_name,
    1157              :                                    &ierror_line))
    1158              :             {
    1159            0 :               GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    1160              :                           "Parser failed on %s:%u for input `%s'\n",
    1161              :                           ierror_name,
    1162              :                           ierror_line,
    1163              :                           json_dumps (output,
    1164              :                                       JSON_INDENT (2)));
    1165            1 :               TALER_TESTING_FAIL (is);
    1166              :             }
    1167              : 
    1168              :             {
    1169              :               const char *donau_url_str;
    1170              : 
    1171            4 :               if ( (NULL == donau_urls) ||
    1172            2 :                    (0 == json_array_size (donau_urls)) )
    1173              :               {
    1174            0 :                 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    1175              :                             "No donau_urls found in output\n");
    1176            0 :                 TALER_TESTING_FAIL (is);
    1177              :               }
    1178              : 
    1179            2 :               donau_url_str = json_string_value (json_array_get (donau_urls,
    1180              :                                                                  0));
    1181            2 :               if (NULL == donau_url_str)
    1182              :               {
    1183            0 :                 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    1184              :                             "First entry in donau_urls is not a string\n");
    1185            0 :                 TALER_TESTING_FAIL (is);
    1186              :               }
    1187              : 
    1188            2 :               ps->donau_data.donau_url = GNUNET_strdup (donau_url_str);
    1189              : 
    1190            2 :               if (NULL != ps->donau_data.charity_reference)
    1191              :               {
    1192            2 :                 switch (prepare_donau_data (is,
    1193              :                                             &ps->donau_data))
    1194              :                 {
    1195            1 :                 case GNUNET_OK:
    1196            1 :                   break;
    1197            1 :                 case GNUNET_NO:
    1198            1 :                   TALER_TESTING_interpreter_next (ps->is);
    1199            1 :                   return;
    1200            0 :                 case GNUNET_SYSERR:
    1201            0 :                   TALER_TESTING_FAIL (is);
    1202              :                   return;
    1203              :                 }
    1204            1 :                 ps->num_donau_tokens = ps->donau_data.num_bkps;
    1205              :               }
    1206              :             }
    1207              :           }
    1208              : 
    1209            7 :           if (0 == strcmp ("token",
    1210              :                            kind))
    1211              :           {
    1212              :             struct GNUNET_JSON_Specification ispec[] = {
    1213            6 :               TALER_JSON_spec_slug ("token_family_slug",
    1214              :                                     &slug),
    1215            6 :               GNUNET_JSON_spec_uint32 ("key_index",
    1216              :                                        &key_index),
    1217            6 :               GNUNET_JSON_spec_mark_optional (
    1218              :                 GNUNET_JSON_spec_uint32 ("count",
    1219              :                                          &count),
    1220              :                 NULL),
    1221            6 :               GNUNET_JSON_spec_end ()
    1222              :             };
    1223              : 
    1224            6 :             if (GNUNET_OK !=
    1225            6 :                 GNUNET_JSON_parse (output,
    1226              :                                    ispec,
    1227              :                                    &ierror_name,
    1228              :                                    &ierror_line))
    1229              :             {
    1230            0 :               GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    1231              :                           "Parser failed on %s:%u for input `%s'\n",
    1232              :                           ierror_name,
    1233              :                           ierror_line,
    1234              :                           json_dumps (output,
    1235              :                                       JSON_INDENT (2)));
    1236            0 :               TALER_TESTING_FAIL (is);
    1237              :             }
    1238              : 
    1239            6 :             if (0 != strcmp ("token",
    1240              :                              kind))
    1241              :             {
    1242            0 :               continue;
    1243              :             }
    1244              : 
    1245            6 :             GNUNET_array_grow (
    1246              :               ps->issued_tokens,
    1247              :               ps->num_issued_tokens,
    1248              :               ps->num_issued_tokens + count + ps->num_donau_tokens);
    1249              : 
    1250           12 :             for (unsigned int k = 0; k < count; k++)
    1251              :             {
    1252            6 :               struct TALER_MERCHANT_PrivateTokenDetails *details =
    1253            6 :                 &ps->issued_tokens[ps->num_issued_tokens - count + k
    1254            6 :                                    + ps->num_donau_tokens];
    1255              : 
    1256            6 :               if (GNUNET_OK !=
    1257            6 :                   find_token_public_key (token_families,
    1258              :                                          slug,
    1259              :                                          key_index,
    1260              :                                          &details->issue_pub))
    1261              :               {
    1262            0 :                 TALER_TESTING_FAIL (is);
    1263              :               }
    1264              : 
    1265              :               /* Only RSA is supported for now. */
    1266            6 :               GNUNET_assert (GNUNET_CRYPTO_BSA_RSA ==
    1267              :                              details->issue_pub.public_key->cipher);
    1268              : 
    1269            6 :               TALER_token_blind_input_copy (&details->blinding_inputs,
    1270              :                                             TALER_token_blind_input_rsa_singleton ()
    1271              :                                             );
    1272              :               /* FIXME: Where to get details->blinding_inputs from? */
    1273            6 :               TALER_token_use_setup_random (&details->master);
    1274            6 :               TALER_token_use_setup_priv (&details->master,
    1275            6 :                                           &details->blinding_inputs,
    1276              :                                           &details->token_priv);
    1277            6 :               TALER_token_use_blinding_secret_create (&details->master,
    1278            6 :                                                       &details->blinding_inputs,
    1279              :                                                       &details->blinding_secret)
    1280              :               ;
    1281            6 :               GNUNET_CRYPTO_eddsa_key_get_public (
    1282            6 :                 &details->token_priv.private_key,
    1283              :                 &details->token_pub.public_key);
    1284            6 :               GNUNET_CRYPTO_hash (&details->token_pub.public_key,
    1285              :                                   sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey),
    1286              :                                   &details->h_token_pub.hash);
    1287            6 :               details->envelope.blinded_pub =
    1288            6 :                 GNUNET_CRYPTO_message_blind_to_sign
    1289              :                 (
    1290            6 :                   details->issue_pub.public_key,
    1291            6 :                   &details->blinding_secret,
    1292              :                   NULL,   /* FIXME: Add session nonce to support CS tokens */
    1293            6 :                   &details->h_token_pub.hash,
    1294              :                   sizeof (details->h_token_pub.hash),
    1295            6 :                   details->blinding_inputs.blinding_inputs);
    1296              : 
    1297            6 :               if (NULL == details->envelope.blinded_pub)
    1298              :               {
    1299            0 :                 GNUNET_break (0);
    1300            0 :                 TALER_TESTING_FAIL (is);
    1301              :               }
    1302              :             }
    1303              :           }
    1304              :         }
    1305              :       }
    1306              : 
    1307           13 :       break;
    1308            0 :     default:
    1309            0 :       TALER_TESTING_FAIL (is);
    1310              :     }
    1311              :   }
    1312              : 
    1313              :   {
    1314              :     char *cr;
    1315              : 
    1316           46 :     cr = GNUNET_strdup (ps->coin_reference);
    1317           46 :     pay_coins = NULL;
    1318           46 :     npay_coins = 0;
    1319           46 :     if (GNUNET_OK !=
    1320           46 :         build_coins (&pay_coins,
    1321              :                      &npay_coins,
    1322              :                      cr,
    1323              :                      is,
    1324              :                      ps->amount_with_fee,
    1325              :                      ps->amount_without_fee))
    1326              :     {
    1327            0 :       GNUNET_array_grow (pay_coins,
    1328              :                          npay_coins,
    1329              :                          0);
    1330            0 :       GNUNET_free (cr);
    1331            0 :       TALER_TESTING_FAIL (is);
    1332              :     }
    1333           46 :     GNUNET_free (cr);
    1334              :   }
    1335           46 :   if (NULL != ps->token_reference)
    1336              :   {
    1337              :     char *tr;
    1338              : 
    1339            4 :     tr = GNUNET_strdup (ps->token_reference);
    1340            4 :     if (GNUNET_OK !=
    1341            4 :         build_tokens (&use_tokens,
    1342              :                       &len_use_tokens,
    1343              :                       tr,
    1344              :                       is))
    1345              :     {
    1346            0 :       GNUNET_array_grow (use_tokens,
    1347              :                          len_use_tokens,
    1348              :                          0);
    1349            0 :       GNUNET_free (tr);
    1350            0 :       TALER_TESTING_FAIL (is);
    1351              :     }
    1352            4 :     GNUNET_free (tr);
    1353              :   }
    1354              : 
    1355           46 :   GNUNET_array_grow (output_tokens,
    1356              :                      len_output_tokens,
    1357              :                      ps->num_issued_tokens);
    1358           52 :   for (unsigned int i = 0; i<len_output_tokens; i++)
    1359              :   {
    1360            6 :     output_tokens[i].envelope.blinded_pub
    1361            6 :       = ps->issued_tokens[i].envelope.blinded_pub;
    1362              :   }
    1363              : 
    1364           46 :   if (GNUNET_OK !=
    1365           46 :       TALER_TESTING_get_trait_merchant_sig (proposal_cmd,
    1366              :                                             &merchant_sig))
    1367            0 :     TALER_TESTING_FAIL (is);
    1368              : 
    1369           46 :   if (GNUNET_OK !=
    1370           46 :       TALER_TESTING_get_trait_h_contract_terms (proposal_cmd,
    1371              :                                                 &h_proposal))
    1372            0 :     TALER_TESTING_FAIL (is);
    1373           46 :   ps->h_contract_terms = *h_proposal;
    1374              : 
    1375              :   /* New logic of setting pay params */
    1376              :   {
    1377              :     struct GNUNET_CURL_Context *ctx =
    1378           46 :       TALER_TESTING_interpreter_get_context (is);
    1379              : 
    1380           92 :     ps->oph = TALER_MERCHANT_post_orders_pay_create (ctx,
    1381              :                                                      ps->merchant_url,
    1382              :                                                      order_id,
    1383              :                                                      h_proposal,
    1384           46 :                                                      &ps->total_amount,
    1385              :                                                      &max_fee,
    1386              :                                                      &merchant_pub,
    1387              :                                                      merchant_sig,
    1388              :                                                      timestamp,
    1389              :                                                      refund_deadline,
    1390              :                                                      pay_deadline,
    1391              :                                                      &h_wire,
    1392              :                                                      npay_coins,
    1393              :                                                      pay_coins);
    1394              : 
    1395           46 :     if (NULL == ps->oph)
    1396            0 :       TALER_TESTING_FAIL (is);
    1397           46 :     if (0 <= ps->choice_index)
    1398           13 :       GNUNET_assert (
    1399              :         GNUNET_OK ==
    1400              :         TALER_MERCHANT_post_orders_pay_set_options (
    1401              :           ps->oph,
    1402              :           TALER_MERCHANT_post_orders_pay_option_choice_index (
    1403              :             ps->choice_index)));
    1404           46 :     if (NULL != ps->session_id)
    1405           11 :       GNUNET_assert (
    1406              :         GNUNET_OK ==
    1407              :         TALER_MERCHANT_post_orders_pay_set_options (
    1408              :           ps->oph,
    1409              :           TALER_MERCHANT_post_orders_pay_option_session_id (
    1410              :             ps->session_id)));
    1411              : 
    1412           46 :     if (len_use_tokens > 0)
    1413            4 :       GNUNET_assert (
    1414              :         GNUNET_OK ==
    1415              :         TALER_MERCHANT_post_orders_pay_set_options (
    1416              :           ps->oph,
    1417              :           TALER_MERCHANT_post_orders_pay_option_use_tokens (
    1418              :             len_use_tokens,
    1419              :             use_tokens)));
    1420           46 :     if (len_output_tokens > 0)
    1421            6 :       GNUNET_assert (
    1422              :         GNUNET_OK ==
    1423              :         TALER_MERCHANT_post_orders_pay_set_options (
    1424              :           ps->oph,
    1425              :           TALER_MERCHANT_post_orders_pay_option_output_tokens (
    1426              :             len_output_tokens,
    1427              :             output_tokens)));
    1428              : 
    1429           46 :     if (ps->donau_data.charity_reference)
    1430              :     {
    1431            1 :       GNUNET_assert (
    1432              :         GNUNET_OK ==
    1433              :         TALER_MERCHANT_post_orders_pay_set_options (
    1434              :           ps->oph,
    1435              :           TALER_MERCHANT_post_orders_pay_option_output_donau (
    1436              :             ps->donau_data.donau_url,
    1437              :             ps->donau_data.year,
    1438              :             ps->donau_data.num_bkps,
    1439              :             ps->donau_data.bkps)));
    1440              :     }
    1441           46 :     if (TALER_EC_NONE !=
    1442           46 :         TALER_MERCHANT_post_orders_pay_start (ps->oph,
    1443              :                                               &pay_cb,
    1444              :                                               ps))
    1445            0 :       TALER_TESTING_FAIL (is);
    1446              :   }
    1447              : 
    1448           46 :   GNUNET_array_grow (pay_coins,
    1449              :                      npay_coins,
    1450              :                      0);
    1451              : 
    1452           46 :   GNUNET_array_grow (use_tokens,
    1453              :                      len_use_tokens,
    1454              :                      0);
    1455              : 
    1456           46 :   GNUNET_array_grow (output_tokens,
    1457              :                      len_output_tokens,
    1458              :                      0);
    1459              : }
    1460              : 
    1461              : 
    1462              : /**
    1463              :  * Free a "pay" CMD, and cancel it if need be.
    1464              :  *
    1465              :  * @param cls closure.
    1466              :  * @param cmd command currently being freed.
    1467              :  */
    1468              : static void
    1469           47 : pay_cleanup (void *cls,
    1470              :              const struct TALER_TESTING_Command *cmd)
    1471              : {
    1472           47 :   struct PayState *ps = cls;
    1473              : 
    1474           47 :   if (NULL != ps->oph)
    1475              :   {
    1476            0 :     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
    1477              :                 "Command `%s' did not complete.\n",
    1478              :                 TALER_TESTING_interpreter_get_current_label (
    1479              :                   ps->is));
    1480            0 :     TALER_MERCHANT_post_orders_pay_cancel (ps->oph);
    1481              :   }
    1482              : 
    1483           47 :   GNUNET_array_grow (ps->issued_tokens,
    1484              :                      ps->num_issued_tokens,
    1485              :                      0);
    1486           47 :   GNUNET_free (ps->donau_data.bkps);
    1487           47 :   GNUNET_free (ps->donau_data.blinding_secrets);
    1488           47 :   GNUNET_free (ps->donau_data.receipts);
    1489           47 :   GNUNET_free (ps->donau_data.alg_values);
    1490           47 :   GNUNET_free (ps->donau_data.h_udis);
    1491           47 :   GNUNET_free (ps->donau_data.donau_url);
    1492           47 :   GNUNET_free (ps);
    1493           47 : }
    1494              : 
    1495              : 
    1496              : /**
    1497              :  * Offer internal data useful to other commands.
    1498              :  *
    1499              :  * @param cls closure
    1500              :  * @param[out] ret result
    1501              :  * @param trait name of the trait
    1502              :  * @param index index number of the object to extract.
    1503              :  * @return #GNUNET_OK on success
    1504              :  */
    1505              : static enum GNUNET_GenericReturnValue
    1506           24 : pay_traits (void *cls,
    1507              :             const void **ret,
    1508              :             const char *trait,
    1509              :             unsigned int index)
    1510              : {
    1511           24 :   struct PayState *ps = cls;
    1512              :   const char *order_id;
    1513              :   const struct TALER_TESTING_Command *proposal_cmd;
    1514              :   const struct TALER_MerchantPublicKeyP *merchant_pub;
    1515              : 
    1516           24 :   if (NULL ==
    1517              :       (proposal_cmd =
    1518           24 :          TALER_TESTING_interpreter_lookup_command (ps->is,
    1519              :                                                    ps->proposal_reference)))
    1520              :   {
    1521            0 :     GNUNET_break (0);
    1522            0 :     return GNUNET_SYSERR;
    1523              :   }
    1524              : 
    1525           24 :   if (GNUNET_OK !=
    1526           24 :       TALER_TESTING_get_trait_order_id (proposal_cmd,
    1527              :                                         &order_id))
    1528              :   {
    1529            0 :     GNUNET_break (0);
    1530            0 :     return GNUNET_SYSERR;
    1531              :   }
    1532              : 
    1533           24 :   if (GNUNET_OK !=
    1534           24 :       TALER_TESTING_get_trait_merchant_pub (proposal_cmd,
    1535              :                                             &merchant_pub))
    1536              :   {
    1537            0 :     GNUNET_break (0);
    1538            0 :     return GNUNET_SYSERR;
    1539              :   }
    1540              :   {
    1541           24 :     GNUNET_assert (GNUNET_OK ==
    1542              :                    TALER_string_to_amount (ps->amount_with_fee,
    1543              :                                            &ps->amount_with_fee_parsed));
    1544              :     {
    1545              :       struct TALER_TESTING_Trait traits[] = {
    1546              :         /* these must be first, see 'off' below */
    1547           24 :         TALER_TESTING_make_trait_token_priv (
    1548              :           index,
    1549           24 :           &ps->issued_tokens[index].token_priv),
    1550           24 :         TALER_TESTING_make_trait_token_issue_pub (
    1551              :           index,
    1552           24 :           &ps->issued_tokens[index].issue_pub),
    1553           24 :         TALER_TESTING_make_trait_token_issue_sig (
    1554              :           index,
    1555           24 :           &ps->issued_tokens[index].issue_sig),
    1556           24 :         TALER_TESTING_make_trait_proposal_reference (ps->proposal_reference),
    1557           24 :         TALER_TESTING_make_trait_coin_reference (0,
    1558              :                                                  ps->coin_reference),
    1559           24 :         TALER_TESTING_make_trait_order_id (order_id),
    1560           24 :         TALER_TESTING_make_trait_merchant_pub (merchant_pub),
    1561           24 :         TALER_TESTING_make_trait_merchant_sig (&ps->merchant_sig),
    1562           24 :         TALER_TESTING_make_trait_amount (&ps->amount_with_fee_parsed),
    1563           24 :         TALER_TESTING_make_trait_otp_key (ps->pos_key),
    1564           24 :         TALER_TESTING_make_trait_otp_alg (&ps->pos_alg),
    1565           24 :         TALER_TESTING_trait_end ()
    1566              :       };
    1567           24 :       unsigned int off = (index >= ps->num_issued_tokens) ? 3 : 0;
    1568              : 
    1569           24 :       return TALER_TESTING_get_trait (&traits[off],
    1570              :                                       ret,
    1571              :                                       trait,
    1572              :                                       index);
    1573              :     }
    1574              :   }
    1575              : }
    1576              : 
    1577              : 
    1578              : struct TALER_TESTING_Command
    1579           45 : TALER_TESTING_cmd_merchant_pay_order_choices (
    1580              :   const char *label,
    1581              :   const char *merchant_url,
    1582              :   unsigned int http_status,
    1583              :   const char *proposal_reference,
    1584              :   const char *coin_reference,
    1585              :   const char *amount_with_fee,
    1586              :   const char *amount_without_fee,
    1587              :   const char *session_id,
    1588              :   int choice_index,
    1589              :   const char *token_reference)
    1590              : {
    1591              :   struct PayState *ps;
    1592              : 
    1593           45 :   ps = GNUNET_new (struct PayState);
    1594           45 :   ps->http_status = http_status;
    1595           45 :   ps->proposal_reference = proposal_reference;
    1596           45 :   ps->coin_reference = coin_reference;
    1597           45 :   ps->merchant_url = merchant_url;
    1598           45 :   ps->amount_with_fee = amount_with_fee;
    1599           45 :   ps->amount_without_fee = amount_without_fee;
    1600           45 :   ps->session_id = session_id;
    1601           45 :   ps->token_reference = token_reference;
    1602           45 :   ps->choice_index = choice_index;
    1603              :   {
    1604           45 :     struct TALER_TESTING_Command cmd = {
    1605              :       .cls = ps,
    1606              :       .label = label,
    1607              :       .run = &pay_run,
    1608              :       .cleanup = &pay_cleanup,
    1609              :       .traits = &pay_traits
    1610              :     };
    1611              : 
    1612           45 :     return cmd;
    1613              :   }
    1614              : }
    1615              : 
    1616              : 
    1617              : struct TALER_TESTING_Command
    1618            2 : TALER_TESTING_cmd_merchant_pay_order_donau (
    1619              :   const char *label,
    1620              :   const char *merchant_url,
    1621              :   unsigned int http_status,
    1622              :   const char *proposal_reference,
    1623              :   const char *coin_reference,
    1624              :   const char *amount_with_fee,
    1625              :   const char *amount_without_fee,
    1626              :   const char *amount_donation,
    1627              :   const char *session_id,
    1628              :   int choice_index,
    1629              :   const char *charity_reference,
    1630              :   uint64_t year,
    1631              :   const char *donor_tax_id,
    1632              :   const char *salt)
    1633              : {
    1634              :   struct PayState *ps;
    1635              : 
    1636            2 :   ps = GNUNET_new (struct PayState);
    1637            2 :   ps->http_status = http_status;
    1638            2 :   ps->proposal_reference = proposal_reference;
    1639            2 :   ps->coin_reference = coin_reference;
    1640            2 :   ps->merchant_url = merchant_url;
    1641            2 :   ps->amount_with_fee = amount_with_fee;
    1642            2 :   ps->amount_without_fee = amount_without_fee;
    1643            2 :   ps->session_id = session_id;
    1644            2 :   ps->token_reference = NULL;
    1645            2 :   ps->choice_index = choice_index;
    1646            2 :   ps->donau_data.year = year;
    1647            2 :   ps->donau_data.num_bkps = 5;
    1648            2 :   ps->donau_data.charity_reference = charity_reference;
    1649            2 :   if (GNUNET_OK !=
    1650            2 :       TALER_string_to_amount (amount_donation,
    1651              :                               &ps->donau_data.donation_amount))
    1652              :   {
    1653            0 :     GNUNET_assert (0);
    1654              :   }
    1655              : 
    1656              :   /* Compute h_donor_tax_id directly into ps->donau_data: */
    1657            2 :   if (! DONAU_compute_salted_tax_id_hash (donor_tax_id,
    1658              :                                           salt,
    1659            2 :                                           ps->donau_data.h_donor_tax_id.hash))
    1660              :   {
    1661            0 :     GNUNET_assert (0);
    1662              :   }
    1663              : 
    1664              :   {
    1665            2 :     struct TALER_TESTING_Command cmd = {
    1666              :       .cls = ps,
    1667              :       .label = label,
    1668              :       .run = &pay_run,
    1669              :       .cleanup = &pay_cleanup,
    1670              :       .traits = &pay_traits
    1671              :     };
    1672              : 
    1673            2 :     return cmd;
    1674              :   }
    1675              : }
    1676              : 
    1677              : 
    1678              : struct TALER_TESTING_Command
    1679           33 : TALER_TESTING_cmd_merchant_pay_order (
    1680              :   const char *label,
    1681              :   const char *merchant_url,
    1682              :   unsigned int http_status,
    1683              :   const char *proposal_reference,
    1684              :   const char *coin_reference,
    1685              :   const char *amount_with_fee,
    1686              :   const char *amount_without_fee,
    1687              :   const char *session_id)
    1688              : {
    1689           33 :   return TALER_TESTING_cmd_merchant_pay_order_choices (
    1690              :     label,
    1691              :     merchant_url,
    1692              :     http_status,
    1693              :     proposal_reference,
    1694              :     coin_reference,
    1695              :     amount_with_fee,
    1696              :     amount_without_fee,
    1697              :     session_id,
    1698              :     -1,
    1699              :     NULL);
    1700              : }
    1701              : 
    1702              : 
    1703              : /* end of testing_api_cmd_pay_order.c */
        

Generated by: LCOV version 2.0-1