exchange

Base system with REST service to issue digital coins, run by the payment service provider
Log | Files | Refs | Submodules | README | LICENSE

testing_api_cmd_contract_get.c (8176B)


      1 /*
      2   This file is part of TALER
      3   Copyright (C) 2022 Taler Systems SA
      4 
      5   TALER is free software; you can redistribute it and/or modify it
      6   under the terms of the GNU General Public License as published by
      7   the Free Software Foundation; either version 3, or (at your
      8   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 GNU
     13   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/testing_api_cmd_contract_get.c
     21  * @brief command for testing GET /contracts/$CPUB
     22  * @author Christian Grothoff
     23  */
     24 #include "taler/taler_json_lib.h"
     25 #include <gnunet/gnunet_curl_lib.h>
     26 #include "taler/taler_testing_lib.h"
     27 #include "taler/taler_signatures.h"
     28 
     29 
     30 /**
     31  * State for a "contract get" CMD.
     32  */
     33 struct ContractGetState
     34 {
     35 
     36   /**
     37    * JSON string describing the resulting contract.
     38    */
     39   json_t *contract_terms;
     40 
     41   /**
     42    * Private key to decrypt the contract.
     43    */
     44   struct TALER_ContractDiffiePrivateP contract_priv;
     45 
     46   /**
     47    * Set to the returned merge key.
     48    */
     49   struct TALER_PurseMergePrivateKeyP merge_priv;
     50 
     51   /**
     52    * Public key of the purse.
     53    */
     54   struct TALER_PurseContractPublicKeyP purse_pub;
     55 
     56   /**
     57    * Reference to the command that uploaded the contract.
     58    */
     59   const char *contract_ref;
     60 
     61   /**
     62    * ContractGet handle while operation is running.
     63    */
     64   struct TALER_EXCHANGE_GetContractsHandle *dh;
     65 
     66   /**
     67    * Interpreter state.
     68    */
     69   struct TALER_TESTING_Interpreter *is;
     70 
     71   /**
     72    * Expected HTTP response code.
     73    */
     74   unsigned int expected_response_code;
     75 
     76   /**
     77    * True if this is for a 'merge' operation,
     78    * 'false' if this is for a 'deposit' operation.
     79    */
     80   bool merge;
     81 
     82 };
     83 
     84 
     85 /**
     86  * Callback to analyze the /contracts/$CPUB response, just used to check if
     87  * the response code is acceptable.
     88  *
     89  * @param cls closure.
     90  * @param dr get response details
     91  */
     92 static void
     93 get_cb (void *cls,
     94         const struct TALER_EXCHANGE_GetContractsResponse *dr)
     95 {
     96   struct ContractGetState *ds = cls;
     97   const struct TALER_TESTING_Command *ref;
     98 
     99   ds->dh = NULL;
    100   if (ds->expected_response_code != dr->hr.http_status)
    101   {
    102     TALER_TESTING_unexpected_status (ds->is,
    103                                      dr->hr.http_status,
    104                                      ds->expected_response_code);
    105     return;
    106   }
    107   ref = TALER_TESTING_interpreter_lookup_command (ds->is,
    108                                                   ds->contract_ref);
    109   GNUNET_assert (NULL != ref);
    110   if (MHD_HTTP_OK == dr->hr.http_status)
    111   {
    112     const struct TALER_PurseMergePrivateKeyP *mp;
    113     const json_t *ct;
    114 
    115     ds->purse_pub = dr->details.ok.purse_pub;
    116     if (ds->merge)
    117     {
    118       if (GNUNET_OK !=
    119           TALER_TESTING_get_trait_merge_priv (ref,
    120                                               &mp))
    121       {
    122         GNUNET_break (0);
    123         TALER_TESTING_interpreter_fail (ds->is);
    124         return;
    125       }
    126       ds->contract_terms =
    127         TALER_CRYPTO_contract_decrypt_for_merge (
    128           &ds->contract_priv,
    129           &ds->purse_pub,
    130           dr->details.ok.econtract,
    131           dr->details.ok.econtract_size,
    132           &ds->merge_priv);
    133       if (0 !=
    134           GNUNET_memcmp (mp,
    135                          &ds->merge_priv))
    136       {
    137         GNUNET_break (0);
    138         TALER_TESTING_interpreter_fail (ds->is);
    139         return;
    140       }
    141     }
    142     else
    143     {
    144       ds->contract_terms =
    145         TALER_CRYPTO_contract_decrypt_for_deposit (
    146           &ds->contract_priv,
    147           dr->details.ok.econtract,
    148           dr->details.ok.econtract_size);
    149     }
    150     if (NULL == ds->contract_terms)
    151     {
    152       GNUNET_break (0);
    153       TALER_TESTING_interpreter_fail (ds->is);
    154       return;
    155     }
    156     if (GNUNET_OK !=
    157         TALER_TESTING_get_trait_contract_terms (ref,
    158                                                 &ct))
    159     {
    160       GNUNET_break (0);
    161       TALER_TESTING_interpreter_fail (ds->is);
    162       return;
    163     }
    164     if (1 != /* 1: equal, 0: not equal */
    165         json_equal (ct,
    166                     ds->contract_terms))
    167     {
    168       GNUNET_break (0);
    169       TALER_TESTING_interpreter_fail (ds->is);
    170       return;
    171     }
    172   }
    173   TALER_TESTING_interpreter_next (ds->is);
    174 }
    175 
    176 
    177 /**
    178  * Run the command.
    179  *
    180  * @param cls closure.
    181  * @param cmd the command to execute.
    182  * @param is the interpreter state.
    183  */
    184 static void
    185 get_run (void *cls,
    186          const struct TALER_TESTING_Command *cmd,
    187          struct TALER_TESTING_Interpreter *is)
    188 {
    189   struct ContractGetState *ds = cls;
    190   const struct TALER_ContractDiffiePrivateP *contract_priv;
    191   const struct TALER_TESTING_Command *ref;
    192   const char *exchange_url;
    193 
    194   (void) cmd;
    195   ds->is = is;
    196   exchange_url = TALER_TESTING_get_exchange_url (is);
    197   if (NULL == exchange_url)
    198   {
    199     GNUNET_break (0);
    200     return;
    201   }
    202   ref = TALER_TESTING_interpreter_lookup_command (ds->is,
    203                                                   ds->contract_ref);
    204   GNUNET_assert (NULL != ref);
    205   if (GNUNET_OK !=
    206       TALER_TESTING_get_trait_contract_priv (ref,
    207                                              &contract_priv))
    208   {
    209     GNUNET_break (0);
    210     TALER_TESTING_interpreter_fail (ds->is);
    211     return;
    212   }
    213   ds->contract_priv = *contract_priv;
    214   ds->dh = TALER_EXCHANGE_get_contracts_create (
    215     TALER_TESTING_interpreter_get_context (is),
    216     exchange_url,
    217     contract_priv);
    218   if (NULL == ds->dh)
    219   {
    220     GNUNET_break (0);
    221     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    222                 "Could not GET contract\n");
    223     TALER_TESTING_interpreter_fail (is);
    224     return;
    225   }
    226   if (TALER_EC_NONE !=
    227       TALER_EXCHANGE_get_contracts_start (ds->dh,
    228                                           &get_cb,
    229                                           ds))
    230   {
    231     GNUNET_break (0);
    232     TALER_EXCHANGE_get_contracts_cancel (ds->dh);
    233     ds->dh = NULL;
    234     TALER_TESTING_interpreter_fail (is);
    235     return;
    236   }
    237 }
    238 
    239 
    240 /**
    241  * Free the state of a "get" CMD, and possibly cancel a
    242  * pending operation thereof.
    243  *
    244  * @param cls closure, must be a `struct ContractGetState`.
    245  * @param cmd the command which is being cleaned up.
    246  */
    247 static void
    248 get_cleanup (void *cls,
    249              const struct TALER_TESTING_Command *cmd)
    250 {
    251   struct ContractGetState *ds = cls;
    252 
    253   if (NULL != ds->dh)
    254   {
    255     TALER_TESTING_command_incomplete (ds->is,
    256                                       cmd->label);
    257     TALER_EXCHANGE_get_contracts_cancel (ds->dh);
    258     ds->dh = NULL;
    259   }
    260   json_decref (ds->contract_terms);
    261   GNUNET_free (ds);
    262 }
    263 
    264 
    265 /**
    266  * Offer internal data from a "get" CMD, to other commands.
    267  *
    268  * @param cls closure.
    269  * @param[out] ret result.
    270  * @param trait name of the trait.
    271  * @param index index number of the object to offer.
    272  * @return #GNUNET_OK on success.
    273  */
    274 static enum GNUNET_GenericReturnValue
    275 get_traits (void *cls,
    276             const void **ret,
    277             const char *trait,
    278             unsigned int index)
    279 {
    280   struct ContractGetState *ds = cls;
    281   struct TALER_TESTING_Trait traits[] = {
    282     TALER_TESTING_make_trait_merge_priv (&ds->merge_priv),
    283     TALER_TESTING_make_trait_purse_pub (&ds->purse_pub),
    284     TALER_TESTING_make_trait_contract_terms (ds->contract_terms),
    285     TALER_TESTING_trait_end ()
    286   };
    287 
    288   /* skip 'merge_priv' if we are in 'merge' mode */
    289   return TALER_TESTING_get_trait (&traits[ds->merge ? 0 : 1],
    290                                   ret,
    291                                   trait,
    292                                   index);
    293 }
    294 
    295 
    296 struct TALER_TESTING_Command
    297 TALER_TESTING_cmd_contract_get (
    298   const char *label,
    299   unsigned int expected_http_status,
    300   bool for_merge,
    301   const char *contract_ref)
    302 {
    303   struct ContractGetState *ds;
    304 
    305   ds = GNUNET_new (struct ContractGetState);
    306   ds->expected_response_code = expected_http_status;
    307   ds->contract_ref = contract_ref;
    308   ds->merge = for_merge;
    309   {
    310     struct TALER_TESTING_Command cmd = {
    311       .cls = ds,
    312       .label = label,
    313       .run = &get_run,
    314       .cleanup = &get_cleanup,
    315       .traits = &get_traits
    316     };
    317 
    318     return cmd;
    319   }
    320 }
    321 
    322 
    323 /* end of testing_api_cmd_contract_get.c */