LCOV - code coverage report
Current view: top level - testing - testing_api_cmd_pay_order.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 254 343 74.1 %
Date: 2025-06-23 16:22:09 Functions: 9 9 100.0 %

          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 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             : #include <gnunet/gnunet_common.h>
      27             : #include <gnunet/gnunet_json_lib.h>
      28             : #include <gnunet/gnunet_time_lib.h>
      29             : #include <jansson.h>
      30             : #include <stddef.h>
      31             : #include <stdint.h>
      32             : #include <taler/taler_exchange_service.h>
      33             : #include <taler/taler_testing_lib.h>
      34             : #include <taler/taler_signatures.h>
      35             : #include "taler_merchant_service.h"
      36             : #include "taler_merchant_testing_lib.h"
      37             : 
      38             : 
      39             : /**
      40             :  * State for a /pay CMD.
      41             :  */
      42             : struct PayState
      43             : {
      44             :   /**
      45             :    * Contract terms hash code.
      46             :    */
      47             :   struct TALER_PrivateContractHashP h_contract_terms;
      48             : 
      49             :   /**
      50             :    * The interpreter state.
      51             :    */
      52             :   struct TALER_TESTING_Interpreter *is;
      53             : 
      54             :   /**
      55             :    * Expected HTTP response status code.
      56             :    */
      57             :   unsigned int http_status;
      58             : 
      59             :   /**
      60             :    * Reference to a command that can provide a order id,
      61             :    * typically a /proposal test command.
      62             :    */
      63             :   const char *proposal_reference;
      64             : 
      65             :   /**
      66             :    * Reference to a command that can provide a coin, so
      67             :    * we can pay here.
      68             :    */
      69             :   const char *coin_reference;
      70             : 
      71             :   /**
      72             :    * Reference to a command that can provide one or
      73             :    * multiple tokens used as inputs for the payment.
      74             :    * In the form "LABEL0[/INDEX];LABEL1[/INDEX];..."
      75             :    */
      76             :   const char *token_reference;
      77             : 
      78             :   /**
      79             :    * The merchant base URL.
      80             :    */
      81             :   const char *merchant_url;
      82             : 
      83             :   /**
      84             :    * Total amount to be paid.
      85             :    */
      86             :   struct TALER_Amount total_amount;
      87             : 
      88             :   /**
      89             :    * Amount to be paid, plus the deposit fee.
      90             :    */
      91             :   const char *amount_with_fee;
      92             : 
      93             :   /**
      94             :    * Amount to be paid, including NO fees.
      95             :    */
      96             :   const char *amount_without_fee;
      97             : 
      98             :   /**
      99             :    * Handle to the pay operation.
     100             :    */
     101             :   struct TALER_MERCHANT_OrderPayHandle *oph;
     102             : 
     103             :   /**
     104             :    * Signature from the merchant, set on success.
     105             :    */
     106             :   struct TALER_MerchantSignatureP merchant_sig;
     107             : 
     108             :   /**
     109             :    * Array of issued tokens, set on success.
     110             :    */
     111             :   struct TALER_MERCHANT_PrivateTokenDetails *issued_tokens;
     112             : 
     113             :   /**
     114             :    * Number of tokens in @e issued_tokens.
     115             :    */
     116             :   unsigned int num_issued_tokens;
     117             : 
     118             :   /**
     119             :    * The session for which the payment is made.
     120             :    */
     121             :   const char *session_id;
     122             : 
     123             :   /**
     124             :    * base64-encoded key
     125             :    */
     126             :   const char *pos_key;
     127             : 
     128             :   /**
     129             :    * Option that add amount of the order
     130             :    */
     131             :   enum TALER_MerchantConfirmationAlgorithm pos_alg;
     132             : 
     133             :   /**
     134             :    * Index of the choice to be used in the payment. -1 for orders without choices.
     135             :    */
     136             :   int choice_index;
     137             : 
     138             : };
     139             : 
     140             : 
     141             : /**
     142             :  * Find the token issue public key for a given token family @a slug and
     143             :  * @a valid_after timestamp.
     144             :  *
     145             :  * @param token_families json object of token families where the key is the slug
     146             :  * @param slug the slug of the token family
     147             :  * @param key_index index of the key within the token family
     148             :  * @param[out] pub the token issue public key of the token family
     149             :  * @return #GNUNET_OK on success and #GNUNET_SYSERR if not found
     150             :  */
     151             : static enum GNUNET_GenericReturnValue
     152           6 : find_token_public_key (const json_t *token_families,
     153             :                        const char *slug,
     154             :                        unsigned int key_index,
     155             :                        struct TALER_TokenIssuePublicKey *pub)
     156             : 
     157             : {
     158           6 :   const json_t *tf = json_object_get (token_families, slug);
     159             :   const json_t *keys;
     160             :   struct GNUNET_JSON_Specification spec[] = {
     161           6 :     GNUNET_JSON_spec_array_const ("keys",
     162             :                                   &keys),
     163           6 :     GNUNET_JSON_spec_end ()
     164             :   };
     165             :   const json_t *key;
     166             :   const char *error_name;
     167             :   unsigned int error_line;
     168             :   struct GNUNET_JSON_Specification ispec[] = {
     169           6 :     TALER_JSON_spec_token_pub (NULL,
     170             :                                pub),
     171           6 :     GNUNET_JSON_spec_end ()
     172             :   };
     173             : 
     174           6 :   if (NULL == tf)
     175             :   {
     176           0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     177             :                 "Token family `%s' not found\n",
     178             :                 slug);
     179           0 :     return GNUNET_SYSERR;
     180             :   }
     181           6 :   if (GNUNET_OK !=
     182           6 :       GNUNET_JSON_parse (tf,
     183             :                          spec,
     184             :                          NULL,
     185             :                          NULL))
     186             :   {
     187           0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     188             :                 "Failed to parse token family `%s'\n",
     189             :                 slug);
     190           0 :     return GNUNET_SYSERR;
     191             :   }
     192             : 
     193           6 :   key = json_array_get (keys,
     194             :                         key_index);
     195           6 :   if (NULL == key)
     196             :   {
     197           0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     198             :                 "Key with index %u for token family '%s' not found\n",
     199             :                 key_index,
     200             :                 slug);
     201           0 :     return GNUNET_SYSERR;
     202             :   }
     203           6 :   if (GNUNET_OK !=
     204           6 :       GNUNET_JSON_parse (key,
     205             :                          ispec,
     206             :                          &error_name,
     207             :                          &error_line))
     208             :   {
     209           0 :     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
     210             :                 "Failed to parse %s at %u: %s\n",
     211             :                 ispec[error_line].field,
     212             :                 error_line,
     213             :                 error_name);
     214           0 :     return GNUNET_SYSERR;
     215             :   }
     216           6 :   return GNUNET_OK;
     217             : }
     218             : 
     219             : 
     220             : /**
     221             :  * Parse the @a coins specification and grow the @a pc
     222             :  * array with the coins found, updating @a npc.
     223             :  *
     224             :  * @param[in,out] pc pointer to array of coins found
     225             :  * @param[in,out] npc length of array at @a pc
     226             :  * @param[in] coins string specifying coins to add to @a pc,
     227             :  *            clobbered in the process
     228             :  * @param is interpreter state
     229             :  * @param amount_with_fee total amount to be paid for a contract.
     230             :  * @param amount_without_fee to be removed, there is no
     231             :  *        per-contract fee, only per-coin exists.
     232             :  * @return #GNUNET_OK on success
     233             :  */
     234             : static enum GNUNET_GenericReturnValue
     235          34 : build_coins (struct TALER_MERCHANT_PayCoin **pc,
     236             :              unsigned int *npc,
     237             :              char *coins,
     238             :              struct TALER_TESTING_Interpreter *is,
     239             :              const char *amount_with_fee,
     240             :              const char *amount_without_fee)
     241             : {
     242             :   char *token;
     243             :   struct TALER_EXCHANGE_Keys *keys;
     244             : 
     245          34 :   keys = TALER_TESTING_get_keys (is);
     246          34 :   if (NULL == keys)
     247             :   {
     248           0 :     GNUNET_break (0);
     249           0 :     return GNUNET_SYSERR;
     250             :   }
     251             : 
     252          34 :   for (token = strtok (coins, ";");
     253          74 :        NULL != token;
     254          40 :        token = strtok (NULL, ";"))
     255             :   {
     256             :     const struct TALER_TESTING_Command *coin_cmd;
     257             :     char *ctok;
     258             :     unsigned int ci;
     259             :     struct TALER_MERCHANT_PayCoin *icoin;
     260             :     const struct TALER_EXCHANGE_DenomPublicKey *dpk;
     261             :     const char *exchange_url;
     262             : 
     263             :     /* Token syntax is "LABEL[/NUMBER]" */
     264          40 :     ctok = strchr (token, '/');
     265             :     /* FIXME: Check why ci variable is parsed but not used? */
     266          40 :     ci = 0;
     267          40 :     if (NULL != ctok)
     268             :     {
     269           0 :       *ctok = '\0';
     270           0 :       ctok++;
     271           0 :       if (1 != sscanf (ctok,
     272             :                        "%u",
     273             :                        &ci))
     274             :       {
     275           0 :         GNUNET_break (0);
     276           0 :         return GNUNET_SYSERR;
     277             :       }
     278             :     }
     279             : 
     280          40 :     coin_cmd = TALER_TESTING_interpreter_lookup_command
     281             :                  (is, token);
     282             : 
     283          40 :     if (NULL == coin_cmd)
     284             :     {
     285           0 :       GNUNET_break (0);
     286           0 :       return GNUNET_SYSERR;
     287             :     }
     288             : 
     289          40 :     GNUNET_array_grow (*pc,
     290             :                        *npc,
     291             :                        (*npc) + 1);
     292             : 
     293          40 :     icoin = &((*pc)[(*npc) - 1]);
     294             : 
     295             :     {
     296             :       const struct TALER_CoinSpendPrivateKeyP *coin_priv;
     297             :       const struct TALER_DenominationSignature *denom_sig;
     298             :       const struct TALER_Amount *denom_value;
     299             :       const struct TALER_EXCHANGE_DenomPublicKey *denom_pub;
     300             :       const struct TALER_AgeCommitmentHashP *h_age_commitment;
     301             : 
     302          40 :       GNUNET_assert (GNUNET_OK ==
     303             :                      TALER_TESTING_get_trait_coin_priv (coin_cmd,
     304             :                                                         0,
     305             :                                                         &coin_priv));
     306          40 :       GNUNET_assert (GNUNET_OK ==
     307             :                      TALER_TESTING_get_trait_denom_pub (coin_cmd,
     308             :                                                         0,
     309             :                                                         &denom_pub));
     310          40 :       GNUNET_assert (GNUNET_OK ==
     311             :                      TALER_TESTING_get_trait_denom_sig (coin_cmd,
     312             :                                                         0,
     313             :                                                         &denom_sig));
     314          40 :       GNUNET_assert (GNUNET_OK ==
     315             :                      TALER_TESTING_get_trait_amount (coin_cmd,
     316             :                                                      &denom_value));
     317          40 :       GNUNET_assert (GNUNET_OK ==
     318             :                      TALER_TESTING_get_trait_h_age_commitment (coin_cmd,
     319             :                                                                0,
     320             :                                                                &h_age_commitment
     321             :                                                                ));
     322          40 :       icoin->coin_priv = *coin_priv;
     323          40 :       icoin->denom_pub = denom_pub->key;
     324          40 :       icoin->denom_sig = *denom_sig;
     325          40 :       icoin->denom_value = *denom_value;
     326          40 :       icoin->amount_with_fee = *denom_value;
     327          40 :       icoin->h_age_commitment = h_age_commitment;
     328             :     }
     329          40 :     GNUNET_assert (NULL != (dpk =
     330             :                               TALER_TESTING_find_pk (keys,
     331             :                                                      &icoin->denom_value,
     332             :                                                      false)));
     333             : 
     334          40 :     GNUNET_assert (0 <=
     335             :                    TALER_amount_subtract (&icoin->amount_without_fee,
     336             :                                           &icoin->denom_value,
     337             :                                           &dpk->fees.deposit));
     338          40 :     GNUNET_assert (GNUNET_OK ==
     339             :                    TALER_TESTING_get_trait_exchange_url (coin_cmd,
     340             :                                                          &exchange_url));
     341          40 :     icoin->exchange_url = exchange_url;
     342             :   }
     343             : 
     344          34 :   return GNUNET_OK;
     345             : }
     346             : 
     347             : 
     348             : /**
     349             :  * Parse the @a pay_references specification and grow the @a tokens
     350             :  * array with the tokens found, updating @a tokens_num.
     351             :  *
     352             :  * @param[in,out] tokens array of tokens found
     353             :  * @param[in,out] tokens_num length of @a tokens array
     354             :  * @param[in] pay_references string of ; separated references to pay commands
     355             :               that issued the tokens.
     356             :  * @param is interpreter state
     357             :  * @return #GNUNET_OK on success
     358             :  */
     359             : static enum GNUNET_GenericReturnValue
     360           4 : build_tokens (struct TALER_MERCHANT_UseToken **tokens,
     361             :               unsigned int *tokens_num,
     362             :               char *pay_references,
     363             :               struct TALER_TESTING_Interpreter *is)
     364             : {
     365             :   char *ref;
     366             : 
     367           4 :   for (ref = strtok (pay_references, ";");
     368           8 :        NULL != ref;
     369           4 :        ref = strtok (NULL, ";"))
     370             :   {
     371             :     const struct TALER_TESTING_Command *pay_cmd;
     372             :     char *slash;
     373             :     unsigned int index;
     374             :     struct TALER_MERCHANT_UseToken *token;
     375             : 
     376             :     /* Reference syntax is "LABEL[/NUMBER]" */
     377           4 :     slash = strchr (ref, '/');
     378           4 :     index = 0;
     379           4 :     if (NULL != slash)
     380             :     {
     381           0 :       *slash = '\0';
     382           0 :       slash++;
     383           0 :       if (1 != sscanf (slash,
     384             :                        "%u",
     385             :                        &index))
     386             :       {
     387           0 :         GNUNET_break (0);
     388           0 :         return GNUNET_SYSERR;
     389             :       }
     390             :     }
     391             : 
     392           4 :     pay_cmd = TALER_TESTING_interpreter_lookup_command (is, ref);
     393             : 
     394           4 :     if (NULL == pay_cmd)
     395             :     {
     396           0 :       GNUNET_break (0);
     397           0 :       return GNUNET_SYSERR;
     398             :     }
     399             : 
     400           4 :     GNUNET_array_grow (*tokens,
     401             :                        *tokens_num,
     402             :                        (*tokens_num) + 1);
     403             : 
     404           4 :     token = &((*tokens)[(*tokens_num) - 1]);
     405             : 
     406             :     {
     407             :       const struct TALER_TokenUsePrivateKeyP *token_priv;
     408             :       const struct TALER_TokenIssueSignature *issue_sig;
     409             :       const struct TALER_TokenIssuePublicKey *issue_pub;
     410             : 
     411           4 :       GNUNET_assert (GNUNET_OK ==
     412             :                      TALER_TESTING_get_trait_token_priv (pay_cmd,
     413             :                                                          index,
     414             :                                                          &token_priv));
     415             : 
     416           4 :       GNUNET_assert (GNUNET_OK ==
     417             :                      TALER_TESTING_get_trait_token_issue_sig (pay_cmd,
     418             :                                                               index,
     419             :                                                               &issue_sig));
     420             : 
     421           4 :       GNUNET_assert (GNUNET_OK ==
     422             :                      TALER_TESTING_get_trait_token_issue_pub (pay_cmd,
     423             :                                                               index,
     424             :                                                               &issue_pub));
     425             : 
     426           4 :       token->token_priv = *token_priv;
     427           4 :       token->ub_sig = *issue_sig;
     428           4 :       token->issue_pub = *issue_pub;
     429             :     }
     430             :   }
     431             : 
     432           4 :   return GNUNET_OK;
     433             : }
     434             : 
     435             : 
     436             : /**
     437             :  * Function called with the result of a /pay operation.
     438             :  * Checks whether the merchant signature is valid and the
     439             :  * HTTP response code matches our expectation.
     440             :  *
     441             :  * @param cls closure with the interpreter state
     442             :  * @param pr HTTP response
     443             :  */
     444             : static void
     445          34 : pay_cb (void *cls,
     446             :         const struct TALER_MERCHANT_PayResponse *pr)
     447             : {
     448          34 :   struct PayState *ps = cls;
     449             : 
     450          34 :   ps->oph = NULL;
     451          34 :   if (ps->http_status != pr->hr.http_status)
     452             :   {
     453           0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     454             :                 "Unexpected response code %u (%d) to command (%s) %s\n",
     455             :                 pr->hr.http_status,
     456             :                 (int) pr->hr.ec,
     457             :                 pr->hr.hint,
     458             :                 TALER_TESTING_interpreter_get_current_label (ps->is));
     459           0 :     TALER_TESTING_FAIL (ps->is);
     460             :   }
     461          34 :   if (MHD_HTTP_OK == pr->hr.http_status)
     462             :   {
     463          22 :     ps->merchant_sig = pr->details.ok.merchant_sig;
     464          22 :     if (ps->num_issued_tokens != pr->details.ok.num_tokens)
     465             :     {
     466           0 :       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     467             :                   "Unexpected number of tokens issued. "
     468             :                   "Sent %d envelopes but got %d tokens issued.\n",
     469             :                   ps->num_issued_tokens,
     470             :                   pr->details.ok.num_tokens);
     471           0 :       GNUNET_break (0);
     472           0 :       TALER_TESTING_interpreter_fail (ps->is);
     473           0 :       return;
     474             :     }
     475          26 :     for (unsigned int i = 0; i < ps->num_issued_tokens; i++)
     476             :     {
     477           4 :       struct TALER_MERCHANT_PrivateTokenDetails *details =
     478           4 :         &ps->issued_tokens[i];
     479             : 
     480             :       /* The issued tokens should be in the
     481             :          same order as the provided envelopes. */
     482           4 :       ps->issued_tokens[i].blinded_sig = pr->details.ok.tokens[i].blinded_sig;
     483             : 
     484           4 :       if (GNUNET_OK !=
     485           4 :           TALER_token_issue_sig_unblind (&details->issue_sig,
     486           4 :                                          &details->blinded_sig,
     487           4 :                                          &details->blinding_secret,
     488           4 :                                          &details->h_token_pub,
     489           4 :                                          &details->blinding_inputs,
     490           4 :                                          &details->issue_pub))
     491             :       {
     492           0 :         GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     493             :                     "Failed to unblind token signature\n");
     494           0 :         GNUNET_break (0);
     495           0 :         TALER_TESTING_interpreter_fail (ps->is);
     496           0 :         return;
     497             :       }
     498             :     }
     499          22 :     if (NULL != ps->pos_key)
     500             :     {
     501             :       char *pc;
     502           2 :       bool found = false;
     503             : 
     504           2 :       if (NULL == pr->details.ok.pos_confirmation)
     505             :       {
     506           0 :         GNUNET_break (0);
     507           0 :         TALER_TESTING_interpreter_fail (ps->is);
     508           0 :         return;
     509             :       }
     510           2 :       pc = TALER_build_pos_confirmation (ps->pos_key,
     511             :                                          ps->pos_alg,
     512           2 :                                          &ps->total_amount,
     513             :                                          GNUNET_TIME_timestamp_get ());
     514             :       /* Check if *any* of our TOTP codes overlaps
     515             :          with any of the returned TOTP codes. */
     516           2 :       for (const char *tok = strtok (pc, "\n");
     517           2 :            NULL != tok;
     518           0 :            tok = strtok (NULL, "\n"))
     519             :       {
     520           2 :         if (NULL != strstr (pr->details.ok.pos_confirmation,
     521             :                             tok))
     522             :         {
     523           2 :           found = true;
     524           2 :           break;
     525             :         }
     526             :       }
     527           2 :       GNUNET_free (pc);
     528           2 :       if (! found)
     529             :       {
     530           0 :         GNUNET_break (0);
     531           0 :         TALER_TESTING_interpreter_fail (ps->is);
     532           0 :         return;
     533             :       }
     534             :     }
     535             :   }
     536          34 :   TALER_TESTING_interpreter_next (ps->is);
     537             : }
     538             : 
     539             : 
     540             : /**
     541             :  * Run a "pay" CMD.
     542             :  *
     543             :  * @param cls closure.
     544             :  * @param cmd current CMD being run.
     545             :  * @param is interpreter state.
     546             :  */
     547             : static void
     548          34 : pay_run (void *cls,
     549             :          const struct TALER_TESTING_Command *cmd,
     550             :          struct TALER_TESTING_Interpreter *is)
     551             : {
     552          34 :   struct PayState *ps = cls;
     553             :   const struct TALER_TESTING_Command *proposal_cmd;
     554             :   const json_t *contract_terms;
     555             :   const char *order_id;
     556             :   struct GNUNET_TIME_Timestamp refund_deadline;
     557             :   struct GNUNET_TIME_Timestamp pay_deadline;
     558             :   struct GNUNET_TIME_Timestamp timestamp;
     559             :   struct TALER_MerchantPublicKeyP merchant_pub;
     560             :   struct TALER_MerchantWireHashP h_wire;
     561             :   const struct TALER_PrivateContractHashP *h_proposal;
     562             :   struct TALER_Amount max_fee;
     563          34 :   const char *error_name = NULL;
     564          34 :   unsigned int error_line = 0;
     565             :   struct TALER_MERCHANT_PayCoin *pay_coins;
     566             :   unsigned int npay_coins;
     567          34 :   struct TALER_MERCHANT_UseToken *use_tokens = NULL;
     568          34 :   unsigned int len_use_tokens = 0;
     569          34 :   struct TALER_MERCHANT_OutputToken *output_tokens = NULL;
     570          34 :   unsigned int len_output_tokens = 0;
     571             :   const struct TALER_MerchantSignatureP *merchant_sig;
     572             :   const enum TALER_MerchantConfirmationAlgorithm *alg_ptr;
     573             : 
     574          34 :   ps->is = is;
     575          34 :   proposal_cmd = TALER_TESTING_interpreter_lookup_command (
     576             :     is,
     577             :     ps->proposal_reference);
     578             : 
     579          34 :   if (NULL == proposal_cmd)
     580           0 :     TALER_TESTING_FAIL (is);
     581             : 
     582          34 :   if (GNUNET_OK !=
     583          34 :       TALER_TESTING_get_trait_contract_terms (proposal_cmd,
     584             :                                               &contract_terms))
     585           0 :     TALER_TESTING_FAIL (is);
     586          34 :   if (NULL == contract_terms)
     587           0 :     TALER_TESTING_FAIL (is);
     588          34 :   if (GNUNET_OK !=
     589          34 :       TALER_TESTING_get_trait_otp_key (proposal_cmd,
     590             :                                        &ps->pos_key))
     591          30 :     ps->pos_key = NULL;
     592          34 :   if ( (GNUNET_OK ==
     593          34 :         TALER_TESTING_get_trait_otp_alg (proposal_cmd,
     594           4 :                                          &alg_ptr)) &&
     595           4 :        (NULL != alg_ptr) )
     596           2 :     ps->pos_alg = *alg_ptr;
     597             :   {
     598             :     /* Get information that needs to be put verbatim in the
     599             :      * deposit permission */
     600          34 :     uint64_t version = 0;
     601             :     struct GNUNET_JSON_Specification spec[] = {
     602          34 :       GNUNET_JSON_spec_mark_optional (
     603             :         GNUNET_JSON_spec_uint64 ("version",
     604             :                                  &version),
     605             :         NULL),
     606          34 :       GNUNET_JSON_spec_string ("order_id",
     607             :                                &order_id),
     608          34 :       GNUNET_JSON_spec_timestamp ("refund_deadline",
     609             :                                   &refund_deadline),
     610          34 :       GNUNET_JSON_spec_timestamp ("pay_deadline",
     611             :                                   &pay_deadline),
     612          34 :       GNUNET_JSON_spec_timestamp ("timestamp",
     613             :                                   &timestamp),
     614          34 :       GNUNET_JSON_spec_fixed_auto ("merchant_pub",
     615             :                                    &merchant_pub),
     616          34 :       GNUNET_JSON_spec_fixed_auto ("h_wire",
     617             :                                    &h_wire),
     618             :       /* FIXME oec: parse minimum age, use data later? */
     619          34 :       GNUNET_JSON_spec_end ()
     620             :     };
     621             : 
     622          34 :     if (GNUNET_OK !=
     623          34 :         GNUNET_JSON_parse (contract_terms,
     624             :                            spec,
     625             :                            &error_name,
     626             :                            &error_line))
     627             :     {
     628             :       char *js;
     629             : 
     630           0 :       js = json_dumps (contract_terms,
     631             :                        JSON_INDENT (1));
     632           0 :       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     633             :                   "Parser failed on %s:%u for input `%s'\n",
     634             :                   error_name,
     635             :                   error_line,
     636             :                   js);
     637           0 :       free (js);
     638           0 :       TALER_TESTING_FAIL (is);
     639             :     }
     640          34 :     switch (version)
     641             :     {
     642          28 :     case 0:
     643             :       {
     644             :         struct GNUNET_JSON_Specification v0spec[] = {
     645          28 :           TALER_JSON_spec_amount_any ("amount",
     646             :                                       &ps->total_amount),
     647          28 :           TALER_JSON_spec_amount_any ("max_fee",
     648             :                                       &max_fee),
     649          28 :           GNUNET_JSON_spec_end ()
     650             :         };
     651             : 
     652          28 :         if (GNUNET_OK !=
     653          28 :             GNUNET_JSON_parse (contract_terms,
     654             :                                v0spec,
     655             :                                &error_name,
     656             :                                &error_line))
     657             :         {
     658             :           char *js;
     659             : 
     660           0 :           js = json_dumps (contract_terms,
     661             :                            JSON_INDENT (1));
     662           0 :           GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     663             :                       "Parser failed on %s:%u for input `%s'\n",
     664             :                       error_name,
     665             :                       error_line,
     666             :                       js);
     667           0 :           free (js);
     668           0 :           TALER_TESTING_FAIL (is);
     669             :         }
     670             :       }
     671          28 :       if (0 < ps->choice_index)
     672           0 :         TALER_TESTING_FAIL (is);
     673          28 :       break;
     674           6 :     case 1:
     675             :       {
     676             :         const json_t *choices;
     677             :         const json_t *token_families;
     678             :         struct GNUNET_JSON_Specification v1spec[] = {
     679           6 :           GNUNET_JSON_spec_object_const ("token_families",
     680             :                                          &token_families),
     681           6 :           GNUNET_JSON_spec_array_const ("choices",
     682             :                                         &choices),
     683           6 :           GNUNET_JSON_spec_end ()
     684             :         };
     685             :         const json_t *outputs;
     686             :         json_t *output;
     687             :         unsigned int output_index;
     688             :         const json_t *choice;
     689             : 
     690           6 :         if (GNUNET_OK !=
     691           6 :             GNUNET_JSON_parse (contract_terms,
     692             :                                v1spec,
     693             :                                &error_name,
     694             :                                &error_line))
     695             :         {
     696             :           char *js;
     697             : 
     698           0 :           js = json_dumps (contract_terms,
     699             :                            JSON_INDENT (1));
     700           0 :           GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     701             :                       "Parser failed on %s:%u for input `%s'\n",
     702             :                       error_name,
     703             :                       error_line,
     704             :                       js);
     705           0 :           free (js);
     706           0 :           TALER_TESTING_FAIL (is);
     707             :         }
     708             : 
     709           6 :         choice = json_array_get (choices,
     710           6 :                                  ps->choice_index);
     711           6 :         if (NULL == choice)
     712             :         {
     713           0 :           GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     714             :                       "No choice found at index %d\n",
     715             :                       ps->choice_index);
     716           0 :           TALER_TESTING_FAIL (is);
     717             :         }
     718             : 
     719             :         {
     720           6 :           const char *ierror_name = NULL;
     721           6 :           unsigned int ierror_line = 0;
     722             : 
     723             :           struct GNUNET_JSON_Specification ispec[] = {
     724           6 :             TALER_JSON_spec_amount_any ("amount",
     725             :                                         &ps->total_amount),
     726           6 :             TALER_JSON_spec_amount_any ("max_fee",
     727             :                                         &max_fee),
     728           6 :             GNUNET_JSON_spec_array_const ("outputs",
     729             :                                           &outputs),
     730           6 :             GNUNET_JSON_spec_end ()
     731             :           };
     732             : 
     733           6 :           if (GNUNET_OK !=
     734           6 :               GNUNET_JSON_parse (choice,
     735             :                                  ispec,
     736             :                                  &ierror_name,
     737             :                                  &ierror_line))
     738             :           {
     739           0 :             GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     740             :                         "Parser failed on %s:%u for input `%s'\n",
     741             :                         ierror_name,
     742             :                         ierror_line,
     743             :                         json_dumps (choice,
     744             :                                     JSON_INDENT (2)));
     745           0 :             TALER_TESTING_FAIL (is);
     746             :           }
     747             :         }
     748             : 
     749          12 :         json_array_foreach (outputs, output_index, output)
     750             :         {
     751             :           const char *slug;
     752             :           const char *kind;
     753             :           uint32_t key_index;
     754           6 :           uint32_t count = 1;
     755           6 :           const char *ierror_name = NULL;
     756           6 :           unsigned int ierror_line = 0;
     757             : 
     758             :           struct GNUNET_JSON_Specification ispec[] = {
     759           6 :             GNUNET_JSON_spec_string ("type",
     760             :                                      &kind),
     761           6 :             GNUNET_JSON_spec_string ("token_family_slug",
     762             :                                      &slug),
     763           6 :             GNUNET_JSON_spec_uint32 ("key_index",
     764             :                                      &key_index),
     765           6 :             GNUNET_JSON_spec_mark_optional (
     766             :               GNUNET_JSON_spec_uint32 ("count",
     767             :                                        &count),
     768             :               NULL),
     769           6 :             GNUNET_JSON_spec_end ()
     770             :           };
     771             : 
     772           6 :           if (GNUNET_OK !=
     773           6 :               GNUNET_JSON_parse (output,
     774             :                                  ispec,
     775             :                                  &ierror_name,
     776             :                                  &ierror_line))
     777             :           {
     778           0 :             GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     779             :                         "Parser failed on %s:%u for input `%s'\n",
     780             :                         ierror_name,
     781             :                         ierror_line,
     782             :                         json_dumps (output,
     783             :                                     JSON_INDENT (2)));
     784           0 :             TALER_TESTING_FAIL (is);
     785             :           }
     786             : 
     787           6 :           if (0 != strcmp ("token", kind))
     788             :           {
     789           0 :             continue;
     790             :           }
     791             : 
     792           6 :           GNUNET_array_grow (ps->issued_tokens,
     793             :                              ps->num_issued_tokens,
     794             :                              ps->num_issued_tokens + count);
     795             : 
     796          12 :           for (unsigned int k = 0; k < count; k++)
     797             :           {
     798           6 :             struct TALER_MERCHANT_PrivateTokenDetails *details =
     799           6 :               &ps->issued_tokens[ps->num_issued_tokens - count + k];
     800             : 
     801           6 :             if (GNUNET_OK !=
     802           6 :                 find_token_public_key (token_families,
     803             :                                        slug,
     804             :                                        key_index,
     805             :                                        &details->issue_pub))
     806             :             {
     807           0 :               TALER_TESTING_FAIL (is);
     808             :             }
     809             : 
     810             :             /* Only RSA is supported for now. */
     811           6 :             GNUNET_assert (GNUNET_CRYPTO_BSA_RSA ==
     812             :                            details->issue_pub.public_key->cipher);
     813             : 
     814           6 :             TALER_token_blind_input_copy (&details->blinding_inputs,
     815             :                                           TALER_token_blind_input_rsa_singleton ()
     816             :                                           );
     817             :             /* FIXME: Where to get details->blinding_inputs from? */
     818           6 :             TALER_token_use_setup_random (&details->master);
     819           6 :             TALER_token_use_setup_priv (&details->master,
     820           6 :                                         &details->blinding_inputs,
     821             :                                         &details->token_priv);
     822           6 :             TALER_token_use_blinding_secret_create (&details->master,
     823           6 :                                                     &details->blinding_inputs,
     824             :                                                     &details->blinding_secret);
     825           6 :             GNUNET_CRYPTO_eddsa_key_get_public (&details->token_priv.private_key
     826             :                                                 ,
     827             :                                                 &details->token_pub.public_key);
     828           6 :             GNUNET_CRYPTO_hash (&details->token_pub.public_key,
     829             :                                 sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey),
     830             :                                 &details->h_token_pub.hash);
     831          12 :             details->envelope.blinded_pub = GNUNET_CRYPTO_message_blind_to_sign
     832             :                                             (
     833           6 :               details->issue_pub.public_key,
     834           6 :               &details->blinding_secret,
     835             :               NULL, /* FIXME: Add session nonce to support CS tokens */
     836           6 :               &details->h_token_pub.hash,
     837             :               sizeof (details->h_token_pub.hash),
     838           6 :               details->blinding_inputs.blinding_inputs);
     839             : 
     840           6 :             if (NULL == details->envelope.blinded_pub)
     841             :             {
     842           0 :               GNUNET_break (0);
     843           0 :               TALER_TESTING_FAIL (is);
     844             :             }
     845             :           }
     846             :         }
     847             :       }
     848             : 
     849           6 :       break;
     850           0 :     default:
     851           0 :       TALER_TESTING_FAIL (is);
     852             :     }
     853             : 
     854             : 
     855             :   }
     856             : 
     857             :   {
     858             :     char *cr;
     859             : 
     860          34 :     cr = GNUNET_strdup (ps->coin_reference);
     861          34 :     pay_coins = NULL;
     862          34 :     npay_coins = 0;
     863          34 :     if (GNUNET_OK !=
     864          34 :         build_coins (&pay_coins,
     865             :                      &npay_coins,
     866             :                      cr,
     867             :                      is,
     868             :                      ps->amount_with_fee,
     869             :                      ps->amount_without_fee))
     870             :     {
     871           0 :       GNUNET_array_grow (pay_coins,
     872             :                          npay_coins,
     873             :                          0);
     874           0 :       GNUNET_free (cr);
     875           0 :       TALER_TESTING_FAIL (is);
     876             :     }
     877          34 :     GNUNET_free (cr);
     878             :   }
     879          34 :   if (NULL != ps->token_reference)
     880             :   {
     881             :     char *tr;
     882             : 
     883           4 :     tr = GNUNET_strdup (ps->token_reference);
     884           4 :     if (GNUNET_OK !=
     885           4 :         build_tokens (&use_tokens,
     886             :                       &len_use_tokens,
     887             :                       tr,
     888             :                       is))
     889             :     {
     890           0 :       GNUNET_array_grow (use_tokens,
     891             :                          len_use_tokens,
     892             :                          0);
     893           0 :       GNUNET_free (tr);
     894           0 :       TALER_TESTING_FAIL (is);
     895             :     }
     896           4 :     GNUNET_free (tr);
     897             :   }
     898             : 
     899          34 :   GNUNET_array_grow (output_tokens,
     900             :                      len_output_tokens,
     901             :                      ps->num_issued_tokens);
     902          40 :   for (unsigned int i = 0; i<len_output_tokens; i++)
     903             :   {
     904           6 :     output_tokens[i].envelope.blinded_pub = ps->issued_tokens[i].envelope.
     905             :                                             blinded_pub;
     906             :   }
     907             : 
     908          34 :   if (GNUNET_OK !=
     909          34 :       TALER_TESTING_get_trait_merchant_sig (proposal_cmd,
     910             :                                             &merchant_sig))
     911           0 :     TALER_TESTING_FAIL (is);
     912             : 
     913          34 :   if (GNUNET_OK !=
     914          34 :       TALER_TESTING_get_trait_h_contract_terms (proposal_cmd,
     915             :                                                 &h_proposal))
     916           0 :     TALER_TESTING_FAIL (is);
     917          34 :   ps->h_contract_terms = *h_proposal;
     918          34 :   ps->oph = TALER_MERCHANT_order_pay (
     919             :     TALER_TESTING_interpreter_get_context (is),
     920             :     ps->merchant_url,
     921             :     ps->session_id,
     922             :     h_proposal,
     923             :     ps->choice_index,
     924          34 :     &ps->total_amount,
     925             :     &max_fee,
     926             :     &merchant_pub,
     927             :     merchant_sig,
     928             :     timestamp,
     929             :     refund_deadline,
     930             :     pay_deadline,
     931             :     &h_wire,
     932             :     order_id,
     933             :     npay_coins,
     934             :     pay_coins,
     935             :     len_use_tokens,
     936             :     use_tokens,
     937             :     len_output_tokens,
     938             :     output_tokens,
     939             :     &pay_cb,
     940             :     ps);
     941          34 :   GNUNET_array_grow (pay_coins,
     942             :                      npay_coins,
     943             :                      0);
     944          34 :   if (NULL == ps->oph)
     945           0 :     TALER_TESTING_FAIL (is);
     946             : }
     947             : 
     948             : 
     949             : /**
     950             :  * Free a "pay" CMD, and cancel it if need be.
     951             :  *
     952             :  * @param cls closure.
     953             :  * @param cmd command currently being freed.
     954             :  */
     955             : static void
     956          34 : pay_cleanup (void *cls,
     957             :              const struct TALER_TESTING_Command *cmd)
     958             : {
     959          34 :   struct PayState *ps = cls;
     960             : 
     961          34 :   if (NULL != ps->oph)
     962             :   {
     963           0 :     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
     964             :                 "Command `%s' did not complete.\n",
     965             :                 TALER_TESTING_interpreter_get_current_label (
     966             :                   ps->is));
     967           0 :     TALER_MERCHANT_order_pay_cancel (ps->oph);
     968             :   }
     969             : 
     970          34 :   GNUNET_free (ps);
     971          34 : }
     972             : 
     973             : 
     974             : /**
     975             :  * Offer internal data useful to other commands.
     976             :  *
     977             :  * @param cls closure
     978             :  * @param[out] ret result
     979             :  * @param trait name of the trait
     980             :  * @param index index number of the object to extract.
     981             :  * @return #GNUNET_OK on success
     982             :  */
     983             : static enum GNUNET_GenericReturnValue
     984          24 : pay_traits (void *cls,
     985             :             const void **ret,
     986             :             const char *trait,
     987             :             unsigned int index)
     988             : {
     989             : 
     990          24 :   struct PayState *ps = cls;
     991             :   const char *order_id;
     992             :   const struct TALER_TESTING_Command *proposal_cmd;
     993             :   const struct TALER_MerchantPublicKeyP *merchant_pub;
     994             : 
     995          24 :   if (NULL != ps->token_reference &&
     996           0 :       index >= ps->num_issued_tokens)
     997             :   {
     998           0 :     GNUNET_break (0);
     999           0 :     return GNUNET_NO;
    1000             :   }
    1001             : 
    1002          24 :   if (NULL ==
    1003             :       (proposal_cmd =
    1004          24 :          TALER_TESTING_interpreter_lookup_command (ps->is,
    1005             :                                                    ps->proposal_reference)))
    1006             :   {
    1007           0 :     GNUNET_break (0);
    1008           0 :     return GNUNET_SYSERR;
    1009             :   }
    1010             : 
    1011          24 :   if (GNUNET_OK !=
    1012          24 :       TALER_TESTING_get_trait_order_id (proposal_cmd,
    1013             :                                         &order_id))
    1014             :   {
    1015           0 :     GNUNET_break (0);
    1016           0 :     return GNUNET_SYSERR;
    1017             :   }
    1018             : 
    1019          24 :   if (GNUNET_OK !=
    1020          24 :       TALER_TESTING_get_trait_merchant_pub (proposal_cmd,
    1021             :                                             &merchant_pub))
    1022             :   {
    1023           0 :     GNUNET_break (0);
    1024           0 :     return GNUNET_SYSERR;
    1025             :   }
    1026             :   {
    1027             :     struct TALER_Amount amount_with_fee;
    1028             : 
    1029          24 :     GNUNET_assert (GNUNET_OK ==
    1030             :                    TALER_string_to_amount (ps->amount_with_fee,
    1031             :                                            &amount_with_fee));
    1032             :     {
    1033             :       struct TALER_TESTING_Trait traits[] = {
    1034          24 :         TALER_TESTING_make_trait_proposal_reference (ps->proposal_reference),
    1035          24 :         TALER_TESTING_make_trait_coin_reference (0,
    1036             :                                                  ps->coin_reference),
    1037          24 :         TALER_TESTING_make_trait_order_id (order_id),
    1038          24 :         TALER_TESTING_make_trait_merchant_pub (merchant_pub),
    1039          24 :         TALER_TESTING_make_trait_merchant_sig (&ps->merchant_sig),
    1040          24 :         TALER_TESTING_make_trait_amount (&amount_with_fee),
    1041          24 :         TALER_TESTING_make_trait_otp_key (ps->pos_key),
    1042          24 :         TALER_TESTING_make_trait_otp_alg (&ps->pos_alg),
    1043          24 :         TALER_TESTING_make_trait_token_priv (index,
    1044          24 :                                              &ps->issued_tokens[index].
    1045             :                                              token_priv),
    1046          24 :         TALER_TESTING_make_trait_token_issue_pub (index,
    1047          24 :                                                   &ps->issued_tokens[index].
    1048             :                                                   issue_pub),
    1049          24 :         TALER_TESTING_make_trait_token_issue_sig (index,
    1050          24 :                                                   &ps->issued_tokens[index].
    1051             :                                                   issue_sig),
    1052          24 :         TALER_TESTING_trait_end ()
    1053             :       };
    1054             : 
    1055          24 :       return TALER_TESTING_get_trait (traits,
    1056             :                                       ret,
    1057             :                                       trait,
    1058             :                                       index);
    1059             :     }
    1060             :   }
    1061             : }
    1062             : 
    1063             : 
    1064             : struct TALER_TESTING_Command
    1065          34 : TALER_TESTING_cmd_merchant_pay_order_choices (const char *label,
    1066             :                                               const char *merchant_url,
    1067             :                                               unsigned int http_status,
    1068             :                                               const char *proposal_reference,
    1069             :                                               const char *coin_reference,
    1070             :                                               const char *amount_with_fee,
    1071             :                                               const char *amount_without_fee,
    1072             :                                               const char *session_id,
    1073             :                                               int choice_index,
    1074             :                                               const char *token_reference)
    1075             : {
    1076             :   struct PayState *ps;
    1077             : 
    1078          34 :   ps = GNUNET_new (struct PayState);
    1079          34 :   ps->http_status = http_status;
    1080          34 :   ps->proposal_reference = proposal_reference;
    1081          34 :   ps->coin_reference = coin_reference;
    1082          34 :   ps->merchant_url = merchant_url;
    1083          34 :   ps->amount_with_fee = amount_with_fee;
    1084          34 :   ps->amount_without_fee = amount_without_fee;
    1085          34 :   ps->session_id = session_id;
    1086          34 :   ps->token_reference = token_reference;
    1087          34 :   ps->choice_index = choice_index;
    1088             :   {
    1089          34 :     struct TALER_TESTING_Command cmd = {
    1090             :       .cls = ps,
    1091             :       .label = label,
    1092             :       .run = &pay_run,
    1093             :       .cleanup = &pay_cleanup,
    1094             :       .traits = &pay_traits
    1095             :     };
    1096             : 
    1097          34 :     return cmd;
    1098             :   }
    1099             : }
    1100             : 
    1101             : 
    1102             : struct TALER_TESTING_Command
    1103          28 : TALER_TESTING_cmd_merchant_pay_order (const char *label,
    1104             :                                       const char *merchant_url,
    1105             :                                       unsigned int http_status,
    1106             :                                       const char *proposal_reference,
    1107             :                                       const char *coin_reference,
    1108             :                                       const char *amount_with_fee,
    1109             :                                       const char *amount_without_fee,
    1110             :                                       const char *session_id)
    1111             : {
    1112          28 :   return TALER_TESTING_cmd_merchant_pay_order_choices (label,
    1113             :                                                        merchant_url,
    1114             :                                                        http_status,
    1115             :                                                        proposal_reference,
    1116             :                                                        coin_reference,
    1117             :                                                        amount_with_fee,
    1118             :                                                        amount_without_fee,
    1119             :                                                        session_id,
    1120             :                                                        -1,
    1121             :                                                        NULL);
    1122             : }
    1123             : 
    1124             : 
    1125             : /* end of testing_api_cmd_pay_order.c */

Generated by: LCOV version 1.16