LCOV - code coverage report
Current view: top level - lib - testing_api_cmd_pay.c (source / functions) Hit Total Coverage
Test: rcoverage.info Lines: 267 349 76.5 %
Date: 2018-07-14 06:17:23 Functions: 24 24 100.0 %

          Line data    Source code
       1             : /*
       2             :   This file is part of TALER
       3             :   Copyright (C) 2014-2018 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             : /**
      21             :  * @file lib/testing_api_cmd_pay.c
      22             :  * @brief command to test the /pay feature.
      23             :  * @author Marcello Stanisci
      24             :  */
      25             : 
      26             : #include "platform.h"
      27             : #include <taler/taler_exchange_service.h>
      28             : #include <taler/taler_testing_lib.h>
      29             : #include <taler/taler_signatures.h>
      30             : #include "taler_merchant_service.h"
      31             : #include "taler_merchant_testing_lib.h"
      32             : 
      33             : #define AMOUNT_WITH_FEE 0
      34             : #define AMOUNT_WITHOUT_FEE 1
      35             : #define REFUND_FEE 2
      36             : 
      37             : /**
      38             :  * State for a /pay CMD.
      39             :  */
      40             : struct PayState
      41             : {
      42             :   /**
      43             :    * Contract terms hash code.
      44             :    */
      45             :   struct GNUNET_HashCode h_contract_terms;
      46             : 
      47             :   /**
      48             :    * The interpreter state.
      49             :    */
      50             :   struct TALER_TESTING_Interpreter *is;
      51             : 
      52             :   /**
      53             :    * Expected HTTP response status code.
      54             :    */
      55             :   unsigned int http_status;
      56             : 
      57             :   /**
      58             :    * Reference to a command that can provide a order id,
      59             :    * typically a /proposal test command.
      60             :    */
      61             :   const char *proposal_reference;
      62             : 
      63             :   /**
      64             :    * Reference to a command that can provide a coin, so
      65             :    * we can pay here.
      66             :    */
      67             :   const char *coin_reference;
      68             : 
      69             :   /**
      70             :    * The curl context.
      71             :    */
      72             :   struct GNUNET_CURL_Context *ctx;
      73             : 
      74             :   /**
      75             :    * The merchant base URL.
      76             :    */
      77             :   const char *merchant_url;
      78             : 
      79             :   /**
      80             :    * Amount to be paid, plus the deposit fee.
      81             :    */
      82             :   const char *amount_with_fee;
      83             : 
      84             :   /**
      85             :    * Amount to be paid, including NO fees.
      86             :    */
      87             :   const char *amount_without_fee;
      88             : 
      89             :   /**
      90             :    * Fee for refunding this payment.
      91             :    */
      92             :   const char *refund_fee;
      93             : 
      94             :   /**
      95             :    * Handle to the /pay operation.
      96             :    */
      97             :   struct TALER_MERCHANT_Pay *po;
      98             : 
      99             : };
     100             : 
     101             : 
     102             : /**
     103             :  * State for a /check-payment CMD.
     104             :  */
     105             : struct CheckPaymentState
     106             : {
     107             : 
     108             :   /**
     109             :    * Operation handle.
     110             :    */
     111             :   struct TALER_MERCHANT_CheckPaymentOperation *cpo;
     112             : 
     113             :   /**
     114             :    * The interpreter state.
     115             :    */
     116             :   struct TALER_TESTING_Interpreter *is;
     117             : 
     118             :   /**
     119             :    * Expected HTTP response status code.
     120             :    */
     121             :   unsigned int http_status;
     122             : 
     123             :   /**
     124             :    * Reference to a command that can provide a order id,
     125             :    * typically a /proposal test command.
     126             :    */
     127             :   const char *proposal_reference;
     128             : 
     129             :   /**
     130             :    * GNUNET_YES if we expect the proposal was paid.
     131             :    */
     132             :   unsigned int expect_paid;
     133             : 
     134             :   /**
     135             :    * The curl context.
     136             :    */
     137             :   struct GNUNET_CURL_Context *ctx;
     138             : 
     139             :   /**
     140             :    * The merchant base URL.
     141             :    */
     142             :   const char *merchant_url;
     143             : 
     144             : };
     145             : 
     146             : 
     147             : /**
     148             :  * State for a "pay again" CMD.
     149             :  */
     150             : struct PayAgainState
     151             : {
     152             :   
     153             :   /**
     154             :    * Expected HTTP response code.
     155             :    */
     156             :   unsigned int http_status;
     157             : 
     158             :   /**
     159             :    * Reference to the "pay" command to abort.
     160             :    */
     161             :   const char *pay_reference;
     162             : 
     163             :   /**
     164             :    * Reference to the coins to use.
     165             :    */
     166             :   const char *coin_reference;
     167             : 
     168             :   /**
     169             :    * Main CURL context.
     170             :    */
     171             :   struct GNUNET_CURL_Context *ctx;
     172             : 
     173             :   /**
     174             :    * Merchant URL.
     175             :    */
     176             :   const char *merchant_url;
     177             : 
     178             :   /**
     179             :    * Refund fee.
     180             :    */
     181             :   const char *refund_fee;
     182             : 
     183             :   /**
     184             :    * Handle to a "pay again" operation.
     185             :    */
     186             :   struct TALER_MERCHANT_Pay *pao;
     187             : 
     188             :   /**
     189             :    * Interpreter state.
     190             :    */
     191             :   struct TALER_TESTING_Interpreter *is;
     192             : };
     193             : 
     194             : 
     195             : /**
     196             :  * State for a "pay abort" CMD.
     197             :  */
     198             : struct PayAbortState
     199             : {
     200             : 
     201             :   /**
     202             :    * Expected HTTP response code.
     203             :    */
     204             :   unsigned int http_status;
     205             : 
     206             :   /**
     207             :    * Reference to the "pay" command to abort.
     208             :    */
     209             :   const char *pay_reference;
     210             : 
     211             :   /**
     212             :    * Main CURL context.
     213             :    */
     214             :   struct GNUNET_CURL_Context *ctx;
     215             : 
     216             :   /**
     217             :    * Merchant URL.
     218             :    */
     219             :   const char *merchant_url;
     220             : 
     221             :   /**
     222             :    * Handle to a "pay abort" operation.
     223             :    */
     224             :   struct TALER_MERCHANT_Pay *pao;
     225             : 
     226             :   /**
     227             :    * Interpreter state.
     228             :    */
     229             :   struct TALER_TESTING_Interpreter *is;
     230             : 
     231             : 
     232             :   /**
     233             :    * How many refund permissions this CMD got
     234             :    * the right for.  Roughly, there is one refund
     235             :    * permission for one coin.
     236             :    */
     237             :   unsigned int num_refunds;
     238             : 
     239             :   /**
     240             :    * The actual refund data.
     241             :    */
     242             :   struct TALER_MERCHANT_RefundEntry *res;
     243             : 
     244             :   /**
     245             :    * The contract whose payment is to be aborted.
     246             :    */
     247             :   struct GNUNET_HashCode h_contract;
     248             : 
     249             :   /**
     250             :    * Merchant public key.
     251             :    */
     252             :   struct TALER_MerchantPublicKeyP merchant_pub;
     253             : };
     254             : 
     255             : 
     256             : /**
     257             :  * State for a "pay abort refund" CMD.  This command
     258             :  * takes the refund permissions from a "pay abort" CMD,
     259             :  * and redeems those at the exchange.
     260             :  */
     261             : struct PayAbortRefundState
     262             : {
     263             : 
     264             :   /**
     265             :    * "abort" CMD that will provide with refund permissions.
     266             :    */
     267             :   const char *abort_reference;
     268             : 
     269             :   /**
     270             :    * Expected number of coins that were refunded.
     271             :    * Only used to counter-check, not to perform any
     272             :    * operation.
     273             :    */
     274             :   unsigned int num_coins;
     275             : 
     276             :   /**
     277             :    * The amount to be "withdrawn" from the refund session.
     278             :    */
     279             :   const char *refund_amount;
     280             : 
     281             :   /**
     282             :    * The refund fee (charged to the merchant).
     283             :    */
     284             :   const char *refund_fee;
     285             : 
     286             :   /**
     287             :    * The interpreter state.
     288             :    */
     289             :   struct TALER_TESTING_Interpreter *is;
     290             : 
     291             :   /**
     292             :    * Handle to the refund operation.
     293             :    */
     294             :   struct TALER_EXCHANGE_RefundHandle *rh;
     295             : 
     296             :   /**
     297             :    * Expected HTTP response code.
     298             :    */
     299             :   unsigned int http_status;
     300             : 
     301             :   /**
     302             :    * Connection handle to the exchange.
     303             :    */
     304             :   struct TALER_EXCHANGE_Handle *exchange;
     305             : };
     306             : 
     307             : 
     308             : 
     309             : /**
     310             :  * Free a /check-payment CMD, and possibly cancel a pending
     311             :  * operation thereof.
     312             :  *
     313             :  * @param cls closure
     314             :  * @param cmd the command currently getting freed.
     315             :  */
     316             : static void
     317           2 : check_payment_cleanup (void *cls,
     318             :                        const struct TALER_TESTING_Command *cmd)
     319             : {
     320           2 :   struct CheckPaymentState *cps = cls;
     321             : 
     322           2 :   if (NULL != cps->cpo)
     323             :   {
     324           0 :     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
     325             :                 "Command `%s' was not terminated\n",
     326             :                 TALER_TESTING_interpreter_get_current_label (
     327             :                   cps->is));
     328           0 :     TALER_MERCHANT_check_payment_cancel (cps->cpo);  
     329             :   }
     330           2 :   GNUNET_free (cps);
     331           2 : }
     332             : 
     333             : 
     334             : /**
     335             :  * Callback for a /check-payment request.
     336             :  *
     337             :  * @param cls closure.
     338             :  * @param http_status HTTP status code we got.
     339             :  * @param json full response we got.
     340             :  * @param paid GNUNET_YES (GNUNET_NO) if the contract was paid
     341             :  *        (not paid).
     342             :  * @param refunded GNUNET_YES (GNUNET_NO) if the contract was
     343             :  *        refunded (not refunded).
     344             :  * @param refund_amount the amount that was refunded to this
     345             :  *        contract.
     346             :  * @param payment_redirect_url URL where the payment has to be
     347             :  *        addressed.
     348             :  */
     349             : static void
     350           2 : check_payment_cb (void *cls,
     351             :                   unsigned int http_status,
     352             :                   const json_t *obj,
     353             :                   int paid,
     354             :                   int refunded,
     355             :                   struct TALER_Amount *refund_amount,
     356             :                   const char *payment_redirect_url)
     357             : {
     358           2 :   struct CheckPaymentState *cps = cls;
     359             : 
     360           2 :   cps->cpo = NULL;
     361           2 :   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
     362             :               "check payment: expected paid: %s: %d\n",
     363             :               TALER_TESTING_interpreter_get_current_label (
     364             :                 cps->is),
     365             :               cps->expect_paid);
     366           2 :   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
     367             :               "check payment: paid: %d\n",
     368             :               paid);
     369           2 :   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
     370             :               "check payment: url: %s\n",
     371             :               payment_redirect_url);
     372             : 
     373           2 :   if (paid != cps->expect_paid)
     374           0 :     TALER_TESTING_FAIL (cps->is);
     375             : 
     376           2 :   if (cps->http_status != http_status)
     377           0 :     TALER_TESTING_FAIL (cps->is);
     378             : 
     379           2 :   TALER_TESTING_interpreter_next (cps->is);
     380             : }
     381             : 
     382             : /**
     383             :  * Run a /check-payment CMD.
     384             :  *
     385             :  * @param cmd the command currenly being run.
     386             :  * @param cls closure.
     387             :  * @param is interpreter state.
     388             :  */
     389             : static void
     390           2 : check_payment_run (void *cls,
     391             :                    const struct TALER_TESTING_Command *cmd,
     392             :                    struct TALER_TESTING_Interpreter *is)
     393             : {
     394           2 :   struct CheckPaymentState *cps = cls;
     395             :   const struct TALER_TESTING_Command *proposal_cmd;
     396             :   const char *order_id;
     397             : 
     398           2 :   cps->is = is;
     399           2 :   proposal_cmd = TALER_TESTING_interpreter_lookup_command (
     400             :     is, cps->proposal_reference);
     401             : 
     402           2 :   if (NULL == proposal_cmd)
     403           0 :     TALER_TESTING_FAIL (is);
     404             : 
     405           2 :   if (GNUNET_OK != TALER_TESTING_get_trait_order_id (
     406             :     proposal_cmd, 0, &order_id))
     407           0 :     TALER_TESTING_FAIL (is);
     408             : 
     409           2 :   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
     410             :               "Checking for order id `%s'\n",
     411             :               order_id);
     412             : 
     413           2 :   cps->cpo = TALER_MERCHANT_check_payment
     414             :     (cps->ctx,
     415             :      cps->merchant_url,
     416             :      "default", // only default instance for now.
     417             :      order_id,
     418             :      NULL,
     419             :      NULL,
     420             :      NULL,
     421             :      check_payment_cb,
     422             :      cps);
     423             : 
     424           2 :   GNUNET_assert (NULL != cps->cpo); 
     425             : }
     426             : 
     427             : /**
     428             :  * Make a "check payment" test command.
     429             :  *
     430             :  * @param label command label.
     431             :  * @param merchant_url merchant base url
     432             :  * @param ctx CURL context.
     433             :  * @param http_status expected HTTP response code.
     434             :  * @param proposal_reference the proposal whose payment status
     435             :  *        is going to be checked.
     436             :  * @param expect_paid GNUNET_YES if we expect the proposal to be
     437             :  *        paid, GNUNET_NO otherwise.
     438             :  *
     439             :  * @return the command
     440             :  */
     441             : struct TALER_TESTING_Command
     442           2 : TALER_TESTING_cmd_check_payment (const char *label,
     443             :                                  const char *merchant_url,
     444             :                                  struct GNUNET_CURL_Context *ctx,
     445             :                                  unsigned int http_status,
     446             :                                  const char *proposal_reference,
     447             :                                  unsigned int expect_paid)
     448             : {
     449             :   struct CheckPaymentState *cps;
     450             :   struct TALER_TESTING_Command cmd;
     451             : 
     452           2 :   cps = GNUNET_new (struct CheckPaymentState);
     453           2 :   cps->http_status = http_status;
     454           2 :   cps->proposal_reference = proposal_reference;
     455           2 :   cps->expect_paid = expect_paid;
     456           2 :   cps->ctx = ctx;
     457           2 :   cps->merchant_url = merchant_url;
     458             : 
     459           2 :   cmd.cls = cps;
     460           2 :   cmd.label = label;
     461           2 :   cmd.run = &check_payment_run;
     462           2 :   cmd.cleanup = &check_payment_cleanup;
     463             : 
     464           2 :   return cmd;
     465             : 
     466             : }
     467             : 
     468             : /**
     469             :  * Parse the @a coins specification and grow the @a pc
     470             :  * array with the coins found, updating @a npc.
     471             :  *
     472             :  * @param[in,out] pc pointer to array of coins found
     473             :  * @param[in,out] npc length of array at @a pc
     474             :  * @param[in] coins string specifying coins to add to @a pc,
     475             :  *            clobbered in the process
     476             :  * @param is interpreter state
     477             :  * @param amount_with_fee total amount to be paid for a contract.
     478             :  * @param amount_without_fee to be removed, there is no
     479             :  *        per-contract fee, only per-coin exists.
     480             :  * @param refund_fee per-contract? per-coin?
     481             :  *
     482             :  * @return #GNUNET_OK on success
     483             :  */
     484             : static int
     485          12 : build_coins (struct TALER_MERCHANT_PayCoin **pc,
     486             :              unsigned int *npc,
     487             :              char *coins,
     488             :              struct TALER_TESTING_Interpreter *is,
     489             :              const char *amount_with_fee,
     490             :              const char *amount_without_fee,
     491             :              const char *refund_fee)
     492             : {
     493             :   char *token;
     494             : 
     495          38 :   for (token = strtok (coins, ";");
     496             :        NULL != token;
     497          14 :        token = strtok (NULL, ";"))
     498             :   {
     499             :     const struct TALER_TESTING_Command *coin_cmd;
     500             :     char *ctok;
     501             :     unsigned int ci;
     502             :     struct TALER_MERCHANT_PayCoin *icoin;
     503             :     const struct TALER_EXCHANGE_DenomPublicKey *dpk;
     504             : 
     505             :     /* Token syntax is "LABEL[/NUMBER]" */
     506          14 :     ctok = strchr (token, '/');
     507          14 :     ci = 0;
     508          14 :     if (NULL != ctok)
     509             :     {
     510           0 :       *ctok = '\0';
     511           0 :       ctok++;
     512           0 :       if (1 != sscanf (ctok,
     513             :                        "%u",
     514             :                        &ci))
     515             :       {
     516           0 :         GNUNET_break (0);
     517           0 :         return GNUNET_SYSERR;
     518             :       }
     519             :     }
     520             : 
     521          14 :     coin_cmd = TALER_TESTING_interpreter_lookup_command
     522             :       (is, token);
     523             : 
     524          14 :     if (NULL == coin_cmd)
     525             :     {
     526           0 :       GNUNET_break (0);
     527           0 :       return GNUNET_SYSERR;
     528             :     }
     529             : 
     530          14 :     GNUNET_array_grow (*pc,
     531             :                        *npc,
     532             :                        (*npc) + 1);
     533             : 
     534          14 :     icoin = &(*pc)[(*npc)-1];
     535             : 
     536             :     struct TALER_CoinSpendPrivateKeyP *coin_priv; 
     537             :     struct TALER_DenominationSignature *denom_sig;
     538             :     const struct TALER_Amount *denom_value;
     539             :     const struct TALER_EXCHANGE_DenomPublicKey *denom_pub;
     540             : 
     541          14 :     GNUNET_assert
     542             :       (GNUNET_OK == TALER_TESTING_get_trait_coin_priv
     543             :         (coin_cmd, 0, &coin_priv));
     544             : 
     545          14 :     GNUNET_assert
     546             :       (GNUNET_OK == TALER_TESTING_get_trait_denom_pub
     547             :         (coin_cmd, 0, &denom_pub));
     548             : 
     549          14 :     GNUNET_assert
     550             :       (GNUNET_OK == TALER_TESTING_get_trait_denom_sig
     551             :         (coin_cmd, 0, &denom_sig));
     552             : 
     553          14 :     GNUNET_assert
     554             :       (GNUNET_OK == TALER_TESTING_get_trait_amount_obj
     555             :         (coin_cmd, 0, &denom_value));
     556             : 
     557          14 :     icoin->coin_priv = *coin_priv;
     558          14 :     icoin->denom_pub = denom_pub->key;
     559          14 :     icoin->denom_sig = *denom_sig;
     560          14 :     icoin->denom_value = *denom_value;
     561          14 :     icoin->amount_with_fee = *denom_value;
     562             :     
     563          14 :     GNUNET_assert (NULL != (dpk = TALER_TESTING_find_pk
     564             :       (is->keys, &icoin->denom_value)));
     565             : 
     566          14 :     GNUNET_assert (GNUNET_SYSERR != TALER_amount_subtract
     567             :       (&icoin->amount_without_fee,
     568             :        &icoin->denom_value,
     569             :        &dpk->fee_deposit));
     570             : 
     571          14 :     GNUNET_assert
     572             :       (GNUNET_OK == TALER_TESTING_get_trait_url
     573             :         (coin_cmd, 0, &icoin->exchange_url)); 
     574             : 
     575          14 :     GNUNET_assert
     576             :       (GNUNET_OK == TALER_string_to_amount
     577             :         (refund_fee, &icoin->refund_fee));
     578             :   }
     579             : 
     580          12 :   return GNUNET_OK;
     581             : }
     582             : 
     583             : 
     584             : /**
     585             :  * Function called with the result of a /pay operation.
     586             :  * Checks whether the merchant signature is valid and the
     587             :  * HTTP response code matches our expectation.
     588             :  *
     589             :  * @param cls closure with the interpreter state
     590             :  * @param http_status HTTP response code, #MHD_HTTP_OK (200)
     591             :  *        for successful deposit; 0 if the exchange's reply is
     592             :  *        bogus (fails to follow the protocol)
     593             :  * @param ec taler-specific error object
     594             :  * @param obj the received JSON reply, should be kept as proof
     595             :  *        (and, in case of errors, be forwarded to the customer)
     596             :  */
     597             : static void
     598           9 : pay_cb (void *cls,
     599             :         unsigned int http_status,
     600             :         enum TALER_ErrorCode ec,
     601             :         const json_t *obj)
     602             : {
     603           9 :   struct PayState *ps = cls;
     604             : 
     605             :   struct GNUNET_CRYPTO_EddsaSignature sig;
     606             :   const char *error_name;
     607             :   unsigned int error_line;
     608             :   const struct GNUNET_CRYPTO_EddsaPublicKey *merchant_pub;
     609             :   const struct TALER_TESTING_Command *proposal_cmd;
     610             : 
     611           9 :   ps->po = NULL;
     612           9 :   if (ps->http_status != http_status)
     613             :   {
     614           0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     615             :                 "Unexpected response code %u (%d) to command %s\n",
     616             :                 http_status,
     617             :                 ec,
     618             :                 TALER_TESTING_interpreter_get_current_label (
     619             :                   ps->is));
     620           0 :     TALER_TESTING_FAIL (ps->is);
     621             :   }
     622           9 :   if (MHD_HTTP_OK == http_status)
     623             :   {
     624             :     /* Check signature */
     625             :     struct PaymentResponsePS mr;
     626          10 :     struct GNUNET_JSON_Specification spec[] = {
     627             :       GNUNET_JSON_spec_fixed_auto ("sig",
     628             :                                    &sig),
     629           5 :       GNUNET_JSON_spec_fixed_auto ("h_contract_terms",
     630             :                                    &ps->h_contract_terms),
     631             :       GNUNET_JSON_spec_end ()
     632             :     };
     633             : 
     634           5 :     GNUNET_assert (GNUNET_OK == GNUNET_JSON_parse (
     635             :       obj, spec,
     636             :       &error_name,
     637             :       &error_line));
     638             : 
     639           5 :     mr.purpose.purpose = htonl (
     640             :       TALER_SIGNATURE_MERCHANT_PAYMENT_OK);
     641           5 :     mr.purpose.size = htonl (sizeof (mr));
     642           5 :     mr.h_contract_terms = ps->h_contract_terms;
     643             : 
     644             :     /* proposal reference was used at least once, at this point */
     645           5 :     GNUNET_assert
     646             :       ( NULL !=
     647             :       ( proposal_cmd = TALER_TESTING_interpreter_lookup_command
     648             :       (ps->is, ps->proposal_reference)));
     649             : 
     650           5 :     if (GNUNET_OK != TALER_TESTING_get_trait_peer_key_pub
     651             :         (proposal_cmd, 0, &merchant_pub))
     652           0 :       TALER_TESTING_FAIL (ps->is);
     653             : 
     654           5 :     if (GNUNET_OK != GNUNET_CRYPTO_eddsa_verify (
     655             :       TALER_SIGNATURE_MERCHANT_PAYMENT_OK,
     656             :       &mr.purpose, &sig,
     657             :       merchant_pub))
     658             :     {
     659           0 :       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     660             :                   "Merchant signature given in response to /pay"
     661             :                   " invalid\n");
     662           0 :       TALER_TESTING_FAIL (ps->is);
     663             :     }
     664             :   }
     665             : 
     666           9 :   TALER_TESTING_interpreter_next (ps->is);
     667             : }
     668             : 
     669             : /**
     670             :  * Callback for a "pay abort" operation.  Mainly, check HTTP
     671             :  * response code was as expected and stores refund permissions
     672             :  * in the state.
     673             :  *
     674             :  * @param cls closure.
     675             :  * @param http_status HTTP response code.
     676             :  * @param ec Taler error code.
     677             :  * @param merchant_pub public key of the merchant refunding the
     678             :  *        contract.
     679             :  * @param h_contract the contract involved in the refund.
     680             :  * @param num_refunds how many refund permissions have been
     681             :  *        issued.
     682             :  * @param res array containing the refund permissions.
     683             :  * @param obj raw response body.
     684             :  */
     685             : static void
     686           2 : pay_abort_cb (void *cls,
     687             :               unsigned int http_status,
     688             :               enum TALER_ErrorCode ec,
     689             :               const struct TALER_MerchantPublicKeyP *merchant_pub,
     690             :               const struct GNUNET_HashCode *h_contract,
     691             :               unsigned int num_refunds,
     692             :               const struct TALER_MERCHANT_RefundEntry *res,
     693             :               const json_t *obj)
     694             : {
     695           2 :   struct PayAbortState *pas = cls;
     696             : 
     697           2 :   pas->pao = NULL;
     698           2 :   if (pas->http_status != http_status)
     699             :   {
     700           0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     701             :                 "Unexpected response code %u (%d) to command %s\n",
     702             :                 http_status,
     703             :                 ec,
     704             :                 TALER_TESTING_interpreter_get_current_label
     705             :                   (pas->is));
     706           0 :     TALER_TESTING_FAIL (pas->is);
     707             :   }
     708           2 :   if ( (MHD_HTTP_OK == http_status) &&
     709             :        (TALER_EC_NONE == ec) )
     710             :   {
     711           1 :     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
     712             :                 "Received %u refunds\n",
     713             :                 num_refunds);
     714           1 :     pas->num_refunds = num_refunds;
     715             : 
     716           1 :     pas->res = GNUNET_new_array
     717             :       (num_refunds, struct TALER_MERCHANT_RefundEntry);
     718             : 
     719           1 :     memcpy (pas->res, res,
     720             :             num_refunds * sizeof
     721             :               (struct TALER_MERCHANT_RefundEntry));
     722           1 :     pas->h_contract = *h_contract;
     723           1 :     pas->merchant_pub = *merchant_pub;
     724             :   }
     725             : 
     726           2 :   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
     727             :               "Successful pay-abort (HTTP status: %u)\n",
     728             :               http_status);
     729           2 :   TALER_TESTING_interpreter_next (pas->is);
     730             : }
     731             : 
     732             : 
     733             : /**
     734             :  * Function used by both "pay" and "abort" operations.
     735             :  * It prepares data and sends the "pay" request to the
     736             :  * backend.
     737             :  *
     738             :  * @param merchant_url base URL of the merchant serving the
     739             :  *        request.
     740             :  * @param ctx CURL context.
     741             :  * @param coin_reference reference to the CMD(s) that offer
     742             :  *        "coins" traits.  It is possible to give multiple
     743             :  *        references by using semicolons to separate them.
     744             :  * @param proposal_refere reference to a "proposal" CMD.
     745             :  * @param is interpreter state.
     746             :  * @param amount_with_fee amount to be paid, including deposit
     747             :  *        fee.
     748             :  * @param amount_without_fee amount to be paid, without deposit
     749             :  *        fee.
     750             :  * @param refund_fee refund fee.
     751             :  * @param api_func "lib" function that will be called to either
     752             :  *        issue a "pay" or "abort" request.
     753             :  * @param api_cb callback for @a api_func.
     754             :  * @param cls closure.
     755             :  *
     756             :  * @return handle to the operation, NULL if errors occur.
     757             :  */
     758             : static struct TALER_MERCHANT_Pay *
     759          12 : _pay_run (const char *merchant_url,
     760             :           struct GNUNET_CURL_Context *ctx,
     761             :           const char *coin_reference,
     762             :           const char *proposal_reference,
     763             :           struct TALER_TESTING_Interpreter *is,
     764             :           const char *amount_with_fee,
     765             :           const char *amount_without_fee,
     766             :           const char *refund_fee,
     767             :           struct TALER_MERCHANT_Pay * (*api_func) (),
     768             :           void (*api_cb) (),
     769             :           void *cls)
     770             : {
     771             :   json_t *ct;
     772             :   const struct TALER_TESTING_Command *proposal_cmd;
     773             :   const char *contract_terms;
     774             :   const char *order_id;
     775             :   struct GNUNET_TIME_Absolute refund_deadline;
     776             :   struct GNUNET_TIME_Absolute pay_deadline;
     777             :   struct GNUNET_TIME_Absolute timestamp;
     778             :   struct TALER_MerchantPublicKeyP merchant_pub;
     779             :   struct GNUNET_HashCode h_wire;
     780             :   const struct GNUNET_HashCode *h_proposal;
     781             :   struct TALER_Amount total_amount;
     782             :   struct TALER_Amount max_fee;
     783             :   const char *error_name;
     784             :   unsigned int error_line;
     785             :   struct TALER_MERCHANT_PayCoin *pay_coins;
     786             :   unsigned int npay_coins;
     787             :   char *cr;
     788             :   struct TALER_MerchantSignatureP *merchant_sig;
     789             :   struct TALER_MERCHANT_Pay *ret;
     790             : 
     791          12 :   proposal_cmd = TALER_TESTING_interpreter_lookup_command
     792             :     (is, proposal_reference);
     793             : 
     794          12 :   if (NULL == proposal_cmd)
     795             :   {
     796           0 :     GNUNET_break (0);
     797           0 :     return NULL;
     798             :   }
     799             : 
     800          12 :   if (GNUNET_OK != TALER_TESTING_get_trait_contract_terms
     801             :     (proposal_cmd, 0, &contract_terms))
     802             :   {
     803           0 :     GNUNET_break (0);
     804           0 :     return NULL;
     805             :   }
     806             : 
     807             :   json_error_t error;
     808          12 :   if (NULL ==
     809          12 :      (ct = json_loads (contract_terms,
     810             :                        JSON_COMPACT,
     811             :                        &error)))
     812             :   {
     813           0 :     GNUNET_break (0);
     814           0 :     return NULL;
     815             :   }
     816             :   /* Get information that needs to be put verbatim in the
     817             :    * deposit permission */
     818          12 :   struct GNUNET_JSON_Specification spec[] = {
     819             :     GNUNET_JSON_spec_string ("order_id",
     820             :                              &order_id),
     821             :     GNUNET_JSON_spec_absolute_time ("refund_deadline",
     822             :                                     &refund_deadline),
     823             :     GNUNET_JSON_spec_absolute_time ("pay_deadline",
     824             :                                     &pay_deadline),
     825             :     GNUNET_JSON_spec_absolute_time ("timestamp",
     826             :                                     &timestamp),
     827             :     GNUNET_JSON_spec_fixed_auto ("merchant_pub",
     828             :                                  &merchant_pub),
     829             :     GNUNET_JSON_spec_fixed_auto ("H_wire",
     830             :                                  &h_wire),
     831             :     TALER_JSON_spec_amount ("amount",
     832             :                             &total_amount),
     833             :     TALER_JSON_spec_amount ("max_fee",
     834             :                             &max_fee),
     835             :     GNUNET_JSON_spec_end()
     836             :   };
     837          12 :   if (GNUNET_OK !=
     838          12 :       GNUNET_JSON_parse (ct,
     839             :                          spec,
     840             :                          &error_name,
     841             :                          &error_line))
     842             :   {
     843           0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     844             :                 "Parser failed on %s:%u\n",
     845             :                 error_name,
     846             :                 error_line);
     847           0 :     fprintf (stderr, "%s\n", contract_terms);
     848           0 :     GNUNET_break_op (0);
     849           0 :     json_decref (ct);
     850           0 :     return NULL;
     851             :   }
     852             : 
     853          12 :   cr = GNUNET_strdup (coin_reference);
     854          12 :   pay_coins = NULL;
     855          12 :   npay_coins = 0;
     856          12 :   if (GNUNET_OK !=
     857          12 :       build_coins (&pay_coins,
     858             :                    &npay_coins,
     859             :                    cr,
     860             :                    is,
     861             :                    amount_with_fee,
     862             :                    amount_without_fee,
     863             :                    refund_fee))
     864             :   {
     865           0 :     GNUNET_array_grow (pay_coins,
     866             :                        npay_coins,
     867             :                        0);
     868           0 :     GNUNET_free (cr);
     869           0 :     GNUNET_break (0);
     870           0 :     return NULL;
     871             :   }
     872             : 
     873          12 :   GNUNET_free (cr);
     874          12 :   if (GNUNET_OK != TALER_TESTING_get_trait_merchant_sig
     875             :     (proposal_cmd, 0, &merchant_sig))
     876             :   {
     877           0 :     GNUNET_break (0);
     878           0 :     return NULL;
     879             :   }
     880             : 
     881             : 
     882          12 :   if (GNUNET_OK != TALER_TESTING_get_trait_h_contract_terms
     883             :     (proposal_cmd, 0, &h_proposal))
     884             :   {
     885           0 :     GNUNET_break (0);
     886           0 :     return NULL;
     887             :   }
     888             : 
     889          12 :   ret = api_func (ctx,
     890             :                   merchant_url,
     891             :                   "default", // instance
     892             :                   h_proposal,
     893             :                   &total_amount,
     894             :                   &max_fee,
     895             :                   &merchant_pub,
     896             :                   merchant_sig,
     897             :                   timestamp,
     898             :                   refund_deadline,
     899             :                   pay_deadline,
     900             :                   &h_wire,
     901             :                   order_id,
     902             :                   npay_coins,
     903             :                   pay_coins,
     904             :                   api_cb,
     905             :                   cls);
     906             : 
     907          12 :   GNUNET_array_grow (pay_coins,
     908             :                      npay_coins,
     909             :                      0);
     910          12 :   return ret;
     911             : }
     912             : 
     913             : /**
     914             :  * Run a "pay" CMD.
     915             :  *
     916             :  * @param cls closure.
     917             :  * @param cmd current CMD being run.
     918             :  * @param is interpreter state.
     919             :  */
     920             : static void
     921           9 : pay_run (void *cls,
     922             :          const struct TALER_TESTING_Command *cmd,
     923             :          struct TALER_TESTING_Interpreter *is)
     924             : {
     925             : 
     926           9 :   struct PayState *ps = cls;
     927             :   
     928           9 :   ps->is = is;
     929           9 :   if ( NULL == 
     930           9 :      ( ps->po = _pay_run (ps->merchant_url,
     931             :                           ps->ctx,
     932             :                           ps->coin_reference,
     933             :                           ps->proposal_reference,
     934             :                           is,
     935             :                           ps->amount_with_fee,
     936             :                           ps->amount_without_fee,
     937             :                           ps->refund_fee,
     938             :                           &TALER_MERCHANT_pay_wallet,
     939             :                           &pay_cb,
     940             :                           ps)) )
     941           0 :     TALER_TESTING_FAIL (is);
     942             : }
     943             : 
     944             : /**
     945             :  * Free a "pay" CMD, and cancel it if need be.
     946             :  *
     947             :  * @param cls closure.
     948             :  * @param cmd command currently being freed.
     949             :  */
     950             : static void
     951           9 : pay_cleanup (void *cls,
     952             :              const struct TALER_TESTING_Command *cmd)
     953             : {
     954           9 :   struct PayState *ps = cls;
     955             : 
     956           9 :   if (NULL != ps->po)
     957             :   {
     958           0 :     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
     959             :                 "Command `%s' did not complete.\n",
     960             :                 TALER_TESTING_interpreter_get_current_label (
     961             :                   ps->is));
     962           0 :     TALER_MERCHANT_pay_cancel (ps->po);
     963             :   }
     964             : 
     965           9 :   GNUNET_free (ps);
     966           9 : }
     967             : 
     968             : 
     969             : /**
     970             :  * Offer internal data useful to other commands.
     971             :  *
     972             :  * @param cls closure
     973             :  * @param ret[out] result
     974             :  * @param trait name of the trait
     975             :  * @param index index number of the object to extract.
     976             :  * @return #GNUNET_OK on success
     977             :  */
     978             : static int
     979          18 : pay_traits (void *cls,
     980             :             void **ret,
     981             :             const char *trait,
     982             :             unsigned int index)
     983             : {
     984             : 
     985          18 :   struct PayState *ps = cls;
     986             :   const char *order_id;
     987             :   const struct TALER_TESTING_Command *proposal_cmd;
     988             :   struct GNUNET_CRYPTO_EddsaPublicKey *merchant_pub;
     989             : 
     990          18 :   if ( NULL ==
     991          18 :      ( proposal_cmd = TALER_TESTING_interpreter_lookup_command
     992             :        (ps->is, ps->proposal_reference)))
     993             :   {
     994           0 :     GNUNET_break (0);
     995           0 :     return GNUNET_SYSERR;
     996             :   }
     997             : 
     998          18 :   if (GNUNET_OK != TALER_TESTING_get_trait_order_id
     999             :       (proposal_cmd, 0, &order_id))
    1000             :   {
    1001           0 :     GNUNET_break (0);
    1002           0 :     return GNUNET_SYSERR;
    1003             :   }
    1004             : 
    1005          18 :   if (GNUNET_OK != TALER_TESTING_get_trait_peer_key_pub
    1006             :       (proposal_cmd,
    1007             :        0,
    1008             :        (const struct GNUNET_CRYPTO_EddsaPublicKey **)
    1009             :          &merchant_pub))
    1010             :   {
    1011           0 :     GNUNET_break (0);
    1012           0 :     return GNUNET_SYSERR;
    1013             :   }
    1014             : 
    1015         126 :   struct TALER_TESTING_Trait traits[] = {
    1016          18 :     TALER_TESTING_make_trait_amount
    1017             :       (AMOUNT_WITH_FEE, ps->amount_with_fee),
    1018          18 :     TALER_TESTING_make_trait_amount
    1019             :       (AMOUNT_WITHOUT_FEE, ps->amount_without_fee),
    1020          18 :     TALER_TESTING_make_trait_amount
    1021             :       (REFUND_FEE, ps->refund_fee),
    1022          18 :     TALER_TESTING_make_trait_proposal_reference
    1023             :       (0, ps->proposal_reference),
    1024          18 :     TALER_TESTING_make_trait_coin_reference
    1025             :       (0, ps->coin_reference),
    1026          18 :     TALER_TESTING_make_trait_order_id (0, order_id),
    1027          18 :     TALER_TESTING_make_trait_peer_key_pub (0, merchant_pub),
    1028             :     TALER_TESTING_trait_end ()
    1029             :   };
    1030             : 
    1031          18 :   return TALER_TESTING_get_trait (traits,
    1032             :                                   ret,
    1033             :                                   trait,
    1034             :                                   index);
    1035             : 
    1036             :   return GNUNET_SYSERR;
    1037             : }
    1038             : 
    1039             : /**
    1040             :  * Make a "pay" test command.
    1041             :  *
    1042             :  * @param label command label.
    1043             :  * @param merchant_url merchant base url
    1044             :  * @param ctx CURL context.
    1045             :  * @param http_status expected HTTP response code.
    1046             :  * @param proposal_reference the proposal whose payment status
    1047             :  *        is going to be checked.
    1048             :  * @param coin_reference reference to any command which is able
    1049             :  *        to provide coins to use for paying.
    1050             :  * @param amount_with_fee amount to pay, including the deposit
    1051             :  *        fee
    1052             :  * @param amount_without_fee amount to pay, no fees included.
    1053             :  * @param refund_fee fee for refunding this payment.
    1054             :  *
    1055             :  * @return the command
    1056             :  */
    1057             : struct TALER_TESTING_Command
    1058           9 : TALER_TESTING_cmd_pay (const char *label,
    1059             :                        const char *merchant_url,
    1060             :                        struct GNUNET_CURL_Context *ctx,
    1061             :                        unsigned int http_status,
    1062             :                        const char *proposal_reference,
    1063             :                        const char *coin_reference,
    1064             :                        const char *amount_with_fee,
    1065             :                        const char *amount_without_fee,
    1066             :                        const char *refund_fee)
    1067             : {
    1068             :   struct PayState *ps;
    1069             :   struct TALER_TESTING_Command cmd;
    1070             : 
    1071           9 :   ps = GNUNET_new (struct PayState);
    1072           9 :   ps->http_status = http_status;
    1073           9 :   ps->proposal_reference = proposal_reference;
    1074           9 :   ps->coin_reference = coin_reference;
    1075           9 :   ps->ctx = ctx;
    1076           9 :   ps->merchant_url = merchant_url;
    1077           9 :   ps->amount_with_fee = amount_with_fee;
    1078           9 :   ps->amount_without_fee = amount_without_fee;
    1079           9 :   ps->refund_fee = refund_fee;
    1080             : 
    1081           9 :   cmd.cls = ps;
    1082           9 :   cmd.label = label;
    1083           9 :   cmd.run = &pay_run;
    1084           9 :   cmd.cleanup = &pay_cleanup;
    1085           9 :   cmd.traits = &pay_traits;
    1086             : 
    1087           9 :   return cmd;
    1088             : 
    1089             : }
    1090             : 
    1091             : 
    1092             : /**
    1093             :  * Free a "pay abort" CMD, and cancel it if need be.
    1094             :  *
    1095             :  * @param cls closure.
    1096             :  * @param cmd command currently being freed.
    1097             :  */
    1098             : static void
    1099           2 : pay_abort_cleanup (void *cls,
    1100             :                    const struct TALER_TESTING_Command *cmd)
    1101             : {
    1102           2 :   struct PayAbortState *pas = cls;
    1103             : 
    1104           2 :   if (NULL != pas->pao)
    1105             :   {
    1106           0 :     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
    1107             :                 "Command `%s' did not complete.\n",
    1108             :                 TALER_TESTING_interpreter_get_current_label (
    1109             :                   pas->is));
    1110           0 :     TALER_MERCHANT_pay_cancel (pas->pao);
    1111             :   }
    1112             : 
    1113           2 :   GNUNET_free (pas);
    1114           2 : }
    1115             : 
    1116             : /**
    1117             :  * Run a "pay abort" CMD.
    1118             :  *
    1119             :  * @param cls closure
    1120             :  * @param cmd command being run.
    1121             :  * @param is interpreter state
    1122             :  */
    1123             : static void
    1124           2 : pay_abort_run (void *cls,
    1125             :                const struct TALER_TESTING_Command *cmd,
    1126             :                struct TALER_TESTING_Interpreter *is)
    1127             : {
    1128             :   
    1129           2 :   struct PayAbortState *pas = cls;
    1130             :   const struct TALER_TESTING_Command *pay_cmd;
    1131             : 
    1132             :   const char *proposal_reference;
    1133             :   const char *coin_reference;
    1134             :   const char *amount_with_fee;
    1135             :   const char *amount_without_fee;
    1136             :   const char *refund_fee;
    1137             :   
    1138           2 :   pas->is = is;
    1139           2 :   pay_cmd = TALER_TESTING_interpreter_lookup_command
    1140             :     (is, pas->pay_reference);
    1141           2 :   if (NULL == pay_cmd)
    1142           0 :     TALER_TESTING_FAIL (is);
    1143             :   
    1144           2 :   if (GNUNET_OK != TALER_TESTING_get_trait_proposal_reference
    1145             :       (pay_cmd, 0, &proposal_reference))
    1146           0 :     TALER_TESTING_FAIL (is);
    1147             : 
    1148           2 :   if (GNUNET_OK != TALER_TESTING_get_trait_coin_reference
    1149             :       (pay_cmd, 0, &coin_reference))
    1150           0 :     TALER_TESTING_FAIL (is);
    1151             : 
    1152           2 :   if (GNUNET_OK != TALER_TESTING_get_trait_amount
    1153             :     (pay_cmd, AMOUNT_WITH_FEE, &amount_with_fee))
    1154           0 :     TALER_TESTING_FAIL (is);
    1155             : 
    1156           2 :   if (GNUNET_OK != TALER_TESTING_get_trait_amount
    1157             :     (pay_cmd, AMOUNT_WITHOUT_FEE, &amount_without_fee))
    1158           0 :     TALER_TESTING_FAIL (is);
    1159             : 
    1160           2 :   if (GNUNET_OK != TALER_TESTING_get_trait_amount
    1161             :     (pay_cmd, REFUND_FEE, &refund_fee))
    1162           0 :     TALER_TESTING_FAIL (is);
    1163             : 
    1164           2 :   if ( NULL ==
    1165           2 :      ( pas->pao = _pay_run (pas->merchant_url,
    1166             :                             pas->ctx,
    1167             :                             coin_reference,
    1168             :                             proposal_reference,
    1169             :                             is,
    1170             :                             amount_with_fee,
    1171             :                             amount_without_fee,
    1172             :                             refund_fee,
    1173             :                             &TALER_MERCHANT_pay_abort,
    1174             :                             &pay_abort_cb,
    1175             :                             pas)) )
    1176           0 :     TALER_TESTING_FAIL (is);
    1177             : }
    1178             : 
    1179             : /**
    1180             :  * Offer internal data useful to other commands.
    1181             :  *
    1182             :  * @param cls closure
    1183             :  * @param ret[out] result (could be anything)
    1184             :  * @param trait name of the trait
    1185             :  * @param index index number of the object to extract.
    1186             :  * @return #GNUNET_OK on success
    1187             :  */
    1188             : static int
    1189           4 : pay_abort_traits (void *cls,
    1190             :                   void **ret,
    1191             :                   const char *trait,
    1192             :                   unsigned int index)
    1193             : {
    1194           4 :   struct PayAbortState *pas = cls;
    1195             : 
    1196          16 :   struct TALER_TESTING_Trait traits[] = {
    1197           4 :     TALER_TESTING_make_trait_peer_key_pub
    1198             :       (0, &pas->merchant_pub.eddsa_pub),
    1199             :     TALER_TESTING_make_trait_h_contract_terms
    1200           4 :       (0, &pas->h_contract),
    1201             :     TALER_TESTING_make_trait_refund_entry
    1202           4 :       (0, pas->res),
    1203           4 :     TALER_TESTING_make_trait_uint (0, &pas->num_refunds),
    1204             :     TALER_TESTING_trait_end ()
    1205             :   };
    1206             : 
    1207           4 :   return TALER_TESTING_get_trait (traits,
    1208             :                                   ret,
    1209             :                                   trait,
    1210             :                                   index);
    1211             : 
    1212             :   return GNUNET_SYSERR;
    1213             : }
    1214             : 
    1215             : /**
    1216             :  * Make a "pay abort" test command.
    1217             :  *
    1218             :  * @param label command label
    1219             :  * @param merchant_url merchant base URL
    1220             :  * @param pay_reference reference to the payment to abort
    1221             :  * @param ctx main CURL context
    1222             :  * @param http_status expected HTTP response code
    1223             :  *
    1224             :  * @return the command
    1225             :  */
    1226             : struct TALER_TESTING_Command
    1227           2 : TALER_TESTING_cmd_pay_abort (const char *label,
    1228             :                              const char *merchant_url,
    1229             :                              const char *pay_reference,
    1230             :                              struct GNUNET_CURL_Context *ctx,
    1231             :                              unsigned int http_status)
    1232             : {
    1233             :   struct PayAbortState *pas;
    1234             :   struct TALER_TESTING_Command cmd;
    1235             : 
    1236           2 :   pas = GNUNET_new (struct PayAbortState);
    1237           2 :   pas->http_status = http_status;
    1238           2 :   pas->pay_reference = pay_reference;
    1239           2 :   pas->ctx = ctx;
    1240           2 :   pas->merchant_url = merchant_url;
    1241             : 
    1242           2 :   cmd.cls = pas;
    1243           2 :   cmd.label = label;
    1244           2 :   cmd.run = &pay_abort_run;
    1245           2 :   cmd.cleanup = &pay_abort_cleanup;
    1246           2 :   cmd.traits = &pay_abort_traits;
    1247             :   
    1248           2 :   return cmd;
    1249             : }
    1250             : 
    1251             : /**
    1252             :  * Function called with the result of a /pay again operation,
    1253             :  * check signature and HTTP response code are good.
    1254             :  *
    1255             :  * @param cls closure with the interpreter state
    1256             :  * @param http_status HTTP response code, #MHD_HTTP_OK (200)
    1257             :  *        for successful deposit; 0 if the exchange's reply is
    1258             :  *        bogus (fails to follow the protocol)
    1259             :  * @param ec taler-specific error object
    1260             :  * @param obj the received JSON reply, should be kept as proof
    1261             :  *        (and, in case of errors, be forwarded to the customer)
    1262             :  */
    1263             : static void
    1264           1 : pay_again_cb (void *cls,
    1265             :               unsigned int http_status,
    1266             :               enum TALER_ErrorCode ec,
    1267             :               const json_t *obj)
    1268             : {
    1269           1 :   struct PayAgainState *pas = cls;
    1270             :   struct GNUNET_CRYPTO_EddsaSignature sig;
    1271             :   const char *error_name;
    1272             :   unsigned int error_line;
    1273             :   const struct TALER_TESTING_Command *pay_cmd;
    1274             :   const struct GNUNET_CRYPTO_EddsaPublicKey *merchant_pub;
    1275             : 
    1276           1 :   pas->pao = NULL;
    1277           1 :   if (pas->http_status != http_status)
    1278             :   {
    1279           0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    1280             :                 "Unexpected response code %u (%d) to command %s\n",
    1281             :                 http_status,
    1282             :                 ec,
    1283             :                 TALER_TESTING_interpreter_get_current_label
    1284             :                   (pas->is));
    1285           0 :     TALER_TESTING_interpreter_fail (pas->is);
    1286           0 :     return;
    1287             :   }
    1288             : 
    1289           1 :   if ( NULL ==
    1290           1 :      ( pay_cmd = TALER_TESTING_interpreter_lookup_command
    1291             :        (pas->is, pas->pay_reference)))
    1292           0 :     TALER_TESTING_FAIL (pas->is);
    1293             : 
    1294           1 :   if (MHD_HTTP_OK == http_status)
    1295             :   {
    1296             :     struct PaymentResponsePS mr;
    1297             :     /* Check signature */
    1298           1 :     struct GNUNET_JSON_Specification spec[] = {
    1299             :       GNUNET_JSON_spec_fixed_auto ("sig",
    1300             :                                    &sig),
    1301             :       GNUNET_JSON_spec_fixed_auto ("h_contract_terms",
    1302             :                                    &mr.h_contract_terms),
    1303             :       GNUNET_JSON_spec_end ()
    1304             :     };
    1305             : 
    1306           1 :     GNUNET_assert (GNUNET_OK == GNUNET_JSON_parse (obj,
    1307             :                                                    spec,
    1308             :                                                    &error_name,
    1309             :                                                    &error_line));
    1310           1 :     mr.purpose.purpose = htonl
    1311             :       (TALER_SIGNATURE_MERCHANT_PAYMENT_OK);
    1312           1 :     mr.purpose.size = htonl (sizeof (mr));
    1313             : 
    1314           1 :     if (GNUNET_OK != TALER_TESTING_get_trait_peer_key_pub
    1315             :         (pay_cmd, 0, &merchant_pub))
    1316           0 :       TALER_TESTING_FAIL (pas->is);
    1317             : 
    1318           1 :     if (GNUNET_OK != GNUNET_CRYPTO_eddsa_verify
    1319             :       (TALER_SIGNATURE_MERCHANT_PAYMENT_OK,
    1320             :        &mr.purpose,
    1321             :        &sig,
    1322             :        merchant_pub))
    1323             :     {
    1324           0 :       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    1325             :                   "Merchant signature given in"
    1326             :                   " response to /pay invalid\n");
    1327           0 :       TALER_TESTING_FAIL (pas->is);
    1328             :     }
    1329             :   }
    1330             : 
    1331           1 :   TALER_TESTING_interpreter_next (pas->is);
    1332             : }
    1333             : 
    1334             : /**
    1335             :  * Run a "pay again" CMD.
    1336             :  *
    1337             :  * @param cls closure.
    1338             :  * @param cmd command currently being run.
    1339             :  * @param is interpreter state.
    1340             :  */
    1341             : static void
    1342           1 : pay_again_run (void *cls,
    1343             :                const struct TALER_TESTING_Command *cmd,
    1344             :                struct TALER_TESTING_Interpreter *is)
    1345             : {
    1346           1 :   struct PayAgainState *pas = cls;
    1347             :   const struct TALER_TESTING_Command *pay_cmd;
    1348             : 
    1349             :   const char *proposal_reference;
    1350             :   const char *amount_with_fee;
    1351             :   const char *amount_without_fee;
    1352             :   
    1353           1 :   pas->is = is;
    1354           1 :   pay_cmd = TALER_TESTING_interpreter_lookup_command
    1355             :     (is, pas->pay_reference);
    1356           1 :   if (NULL == pay_cmd)
    1357           0 :     TALER_TESTING_FAIL (is);
    1358             :   
    1359           1 :   if (GNUNET_OK != TALER_TESTING_get_trait_proposal_reference
    1360             :       (pay_cmd, 0, &proposal_reference))
    1361           0 :     TALER_TESTING_FAIL (is);
    1362             : 
    1363           1 :   if (GNUNET_OK != TALER_TESTING_get_trait_amount
    1364             :     (pay_cmd, AMOUNT_WITH_FEE, &amount_with_fee))
    1365           0 :     TALER_TESTING_FAIL (is);
    1366             : 
    1367           1 :   if (GNUNET_OK != TALER_TESTING_get_trait_amount
    1368             :     (pay_cmd, AMOUNT_WITHOUT_FEE, &amount_without_fee))
    1369           0 :     TALER_TESTING_FAIL (is);
    1370             : 
    1371           1 :   if ( NULL ==
    1372           1 :      ( pas->pao = _pay_run (pas->merchant_url,
    1373             :                             pas->ctx,
    1374             :                             pas->coin_reference,
    1375             :                             proposal_reference,
    1376             :                             is,
    1377             :                             amount_with_fee,
    1378             :                             amount_without_fee,
    1379             :                             pas->refund_fee,
    1380             :                             &TALER_MERCHANT_pay_wallet,
    1381             :                             &pay_again_cb,
    1382             :                             pas)) )
    1383           0 :     TALER_TESTING_FAIL (is);
    1384             : }
    1385             : 
    1386             : /**
    1387             :  * Free and possibly cancel a "pay again" CMD.
    1388             :  *
    1389             :  * @param cls closure.
    1390             :  * @param cmd command currently being freed.
    1391             :  */
    1392             : static void
    1393           1 : pay_again_cleanup (void *cls,
    1394             :                    const struct TALER_TESTING_Command *cmd)
    1395             : {
    1396           1 :   struct PayAgainState *pas = cls;
    1397             : 
    1398           1 :   if (NULL != pas->pao)
    1399             :   {
    1400           0 :     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
    1401             :                 "Command `%s' did not complete.\n",
    1402             :                 TALER_TESTING_interpreter_get_current_label (
    1403             :                   pas->is));
    1404           0 :     TALER_MERCHANT_pay_cancel (pas->pao);
    1405             :   }
    1406             : 
    1407           1 :   GNUNET_free (pas);
    1408           1 : }
    1409             : 
    1410             : /**
    1411             :  * Make a "pay again" test command.  Its purpose is to
    1412             :  * take all the data from a aborted "pay" CMD, and use
    1413             :  * good coins - found in @a coin_reference - to correctly
    1414             :  * pay for it.
    1415             :  *
    1416             :  * @param label command label
    1417             :  * @param merchant_url merchant base URL
    1418             :  * @param pay_reference reference to the payment to replay
    1419             :  * @param coin_reference reference to the coins to use
    1420             :  * @param ctx main CURL context
    1421             :  * @param http_status expected HTTP response code
    1422             :  *
    1423             :  * @return the command
    1424             :  */
    1425             : struct TALER_TESTING_Command
    1426           1 : TALER_TESTING_cmd_pay_again (const char *label,
    1427             :                              const char *merchant_url,
    1428             :                              const char *pay_reference,
    1429             :                              const char *coin_reference,
    1430             :                              const char *refund_fee,
    1431             :                              struct GNUNET_CURL_Context *ctx,
    1432             :                              unsigned int http_status)
    1433             : {
    1434             : 
    1435             :   struct PayAgainState *pas;
    1436             :   struct TALER_TESTING_Command cmd;
    1437             : 
    1438           1 :   pas = GNUNET_new (struct PayAgainState);
    1439           1 :   pas->http_status = http_status;
    1440           1 :   pas->pay_reference = pay_reference;
    1441           1 :   pas->coin_reference = coin_reference;
    1442           1 :   pas->ctx = ctx;
    1443           1 :   pas->merchant_url = merchant_url;
    1444           1 :   pas->refund_fee = refund_fee;
    1445             : 
    1446           1 :   cmd.cls = pas;
    1447           1 :   cmd.label = label;
    1448           1 :   cmd.run = &pay_again_run;
    1449           1 :   cmd.cleanup = &pay_again_cleanup;
    1450             :   
    1451           1 :   return cmd;
    1452             : }
    1453             : 
    1454             : 
    1455             : /**
    1456             :  * Callback used to work out the response from the exchange
    1457             :  * to a refund operation.  Currently only checks if the response
    1458             :  * code is as expected.
    1459             :  *
    1460             :  * @param cls closure
    1461             :  * @param http_status HTTP response code, #MHD_HTTP_OK (200) for
    1462             :  *        successful deposit; 0 if the exchange's reply is bogus
    1463             :  *        (fails to follow the protocol)
    1464             :  * @param ec taler-specific error code, #TALER_EC_NONE on success
    1465             :  * @param sign_key exchange key used to sign @a obj, or NULL
    1466             :  * @param obj the received JSON reply, should be kept as proof
    1467             :  *        (and, in particular, be forwarded to the customer)
    1468             :  */
    1469             : static void
    1470           1 : abort_refund_cb (void *cls,
    1471             :                  unsigned int http_status,
    1472             :                  enum TALER_ErrorCode ec,
    1473             :                  const struct TALER_ExchangePublicKeyP *sign_key,
    1474             :                  const json_t *obj)
    1475             : {
    1476           1 :   struct PayAbortRefundState *pars = cls;
    1477             : 
    1478           1 :   pars->rh = NULL;
    1479           1 :   if (pars->http_status != http_status)
    1480             :   {
    1481           0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    1482             :                 "Unexpected response code %u (%d) to command %s\n",
    1483             :                 http_status,
    1484             :                 ec,
    1485             :                 TALER_TESTING_interpreter_get_current_label
    1486             :                   (pars->is));
    1487           0 :     TALER_TESTING_interpreter_fail (pars->is);
    1488           0 :     return;
    1489             :   }
    1490           1 :   TALER_TESTING_interpreter_next (pars->is);
    1491             : }
    1492             : 
    1493             : /**
    1494             :  * Free the state of a "pay abort refund" CMD, and possibly
    1495             :  * cancel a pending operation.
    1496             :  *
    1497             :  * @param cls closure.
    1498             :  * @param cmd the command currently being freed.
    1499             :  */
    1500             : static void
    1501           1 : pay_abort_refund_cleanup (void *cls,
    1502             :                           const struct TALER_TESTING_Command *cmd)
    1503             : {
    1504           1 :   struct PayAbortRefundState *pars = cls;
    1505             : 
    1506           1 :   if (NULL != pars->rh)
    1507             :   {
    1508           0 :     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
    1509             :                 "Command `%s' did not complete.\n",
    1510             :                 TALER_TESTING_interpreter_get_current_label (
    1511             :                   pars->is));
    1512           0 :     TALER_EXCHANGE_refund_cancel (pars->rh);
    1513             :   }
    1514           1 :   GNUNET_free (pars);
    1515           1 : }
    1516             : 
    1517             : /**
    1518             :  * Run a "pay abort refund" CMD.
    1519             :  *
    1520             :  * @param cls closure.
    1521             :  * @param cmd command currently being run.
    1522             :  * @param is interpreter state.
    1523             :  */
    1524             : static void
    1525           1 : pay_abort_refund_run (void *cls,
    1526             :                       const struct TALER_TESTING_Command *cmd,
    1527             :                       struct TALER_TESTING_Interpreter *is)
    1528             : {
    1529           1 :   struct PayAbortRefundState *pars = cls;
    1530             :   struct TALER_Amount refund_fee;
    1531             :   struct TALER_Amount refund_amount;
    1532             :   const struct TALER_MERCHANT_RefundEntry *refund_entry;
    1533             :   unsigned int *num_refunds;
    1534             :   const struct TALER_TESTING_Command *abort_cmd;
    1535             :   const struct GNUNET_CRYPTO_EddsaPublicKey *merchant_pub;
    1536             :   const struct GNUNET_HashCode *h_contract_terms;
    1537             : 
    1538           1 :   pars->is = is;
    1539             : 
    1540           1 :   if ( NULL ==
    1541           1 :      ( abort_cmd = TALER_TESTING_interpreter_lookup_command
    1542             :        (is, pars->abort_reference)) )
    1543           0 :     TALER_TESTING_FAIL (is);
    1544             : 
    1545           1 :   if (GNUNET_OK != TALER_TESTING_get_trait_uint
    1546             :       (abort_cmd, 0, &num_refunds))
    1547           0 :     TALER_TESTING_FAIL (is);
    1548             : 
    1549           1 :   if (pars->num_coins >= *num_refunds)
    1550           0 :     TALER_TESTING_FAIL (is);
    1551             : 
    1552           1 :   if (GNUNET_OK != TALER_TESTING_get_trait_h_contract_terms
    1553             :       (abort_cmd, 0, &h_contract_terms))
    1554           0 :     TALER_TESTING_FAIL (is);
    1555             : 
    1556           1 :   if (GNUNET_OK != TALER_TESTING_get_trait_peer_key_pub
    1557             :       (abort_cmd, 0, &merchant_pub))
    1558           0 :     TALER_TESTING_FAIL (is);
    1559             : 
    1560           1 :   if (GNUNET_OK != TALER_TESTING_get_trait_refund_entry
    1561             :       (abort_cmd, 0, &refund_entry))
    1562           0 :     TALER_TESTING_FAIL (is);
    1563             : 
    1564           1 :   GNUNET_assert (GNUNET_OK == TALER_string_to_amount 
    1565             :     (pars->refund_amount, &refund_amount));
    1566           1 :   GNUNET_assert (GNUNET_OK == TALER_string_to_amount 
    1567             :     (pars->refund_fee, &refund_fee));
    1568             : 
    1569           3 :   pars->rh = TALER_EXCHANGE_refund2
    1570             :     (pars->exchange,
    1571             :      &refund_amount,
    1572             :      &refund_fee,
    1573             :      h_contract_terms,
    1574           1 :      &refund_entry->coin_pub,
    1575           1 :      refund_entry->rtransaction_id,
    1576             :      (const struct TALER_MerchantPublicKeyP *) merchant_pub,
    1577           1 :      &refund_entry->merchant_sig,
    1578             :      &abort_refund_cb,
    1579             :      pars);
    1580             : 
    1581           1 :   GNUNET_assert (NULL != pars->rh);
    1582             : }
    1583             : 
    1584             : 
    1585             : /**
    1586             :  * Make a "pay abort refund" CMD.  This command uses the
    1587             :  * refund permission from a "pay abort" CMD, and redeems it
    1588             :  * at the exchange.
    1589             :  *
    1590             :  * @param label command label.
    1591             :  * @param exchange connection label to the exchange.
    1592             :  * @param abort_reference reference to the "pay abort" CMD that
    1593             :  *        will offer the refund permission.
    1594             :  * @param num_coins how many coins are expected to be refunded.
    1595             :  * @param refund_amount the amount we are going to redeem as
    1596             :  *        refund.
    1597             :  * @param refund_fee the refund fee (merchant pays it)
    1598             :  * @param http_status expected HTTP response code.
    1599             :  */
    1600             : struct TALER_TESTING_Command
    1601           1 : TALER_TESTING_cmd_pay_abort_refund
    1602             :   (const char *label,
    1603             :    struct TALER_EXCHANGE_Handle *exchange,
    1604             :    const char *abort_reference,
    1605             :    unsigned int num_coins,
    1606             :    const char *refund_amount,
    1607             :    const char *refund_fee,
    1608             :    unsigned int http_status)
    1609             : {
    1610             :   struct PayAbortRefundState *pars;
    1611             :   struct TALER_TESTING_Command cmd;
    1612             : 
    1613           1 :   pars = GNUNET_new (struct PayAbortRefundState);
    1614           1 :   pars->abort_reference = abort_reference;
    1615           1 :   pars->num_coins = num_coins;
    1616           1 :   pars->refund_amount = refund_amount;
    1617           1 :   pars->refund_fee = refund_fee;
    1618           1 :   pars->http_status = http_status;
    1619           1 :   pars->exchange = exchange;
    1620             : 
    1621           1 :   cmd.cls = pars;
    1622           1 :   cmd.label = label;
    1623           1 :   cmd.run = &pay_abort_refund_run;
    1624           1 :   cmd.cleanup = &pay_abort_refund_cleanup;
    1625             : 
    1626           1 :   return cmd;
    1627             : }
    1628             : 
    1629             : /* end of testing_api_cmd_pay.c */

Generated by: LCOV version 1.13