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_get_exchange.c (11902B)


      1 /*
      2   This file is part of TALER
      3   (C) 2023 Taler Systems SA
      4 
      5   TALER is free software; you can redistribute it and/or modify
      6   it under the terms of the GNU General Public License as
      7   published by the Free Software Foundation; either version 3, or
      8   (at your option) any later version.
      9 
     10   TALER is distributed in the hope that it will be useful, but
     11   WITHOUT ANY WARRANTY; without even the implied warranty of
     12   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     13   GNU General Public License for more details.
     14 
     15   You should have received a copy of the GNU General Public
     16   License along with TALER; see the file COPYING.  If not, see
     17   <http://www.gnu.org/licenses/>
     18 */
     19 /**
     20  * @file testing/testing_api_cmd_get_exchange.c
     21  * @brief Command to get an exchange handle
     22  * @author Christian Grothoff
     23  */
     24 #include "taler/taler_json_lib.h"
     25 #include <gnunet/gnunet_curl_lib.h>
     26 struct GetExchangeState;
     27 #define TALER_EXCHANGE_GET_KEYS_RESULT_CLOSURE struct GetExchangeState
     28 #include "taler/taler_testing_lib.h"
     29 
     30 
     31 /**
     32  * State for a "get exchange" CMD.
     33  */
     34 struct GetExchangeState
     35 {
     36 
     37   /**
     38    * Master private key of the exchange.
     39    */
     40   struct TALER_MasterPrivateKeyP master_priv;
     41 
     42   /**
     43    * Our interpreter state.
     44    */
     45   struct TALER_TESTING_Interpreter *is;
     46 
     47   /**
     48    * Exchange handle we produced.
     49    */
     50   struct TALER_EXCHANGE_GetKeysHandle *exchange;
     51 
     52   /**
     53    * Keys of the exchange.
     54    */
     55   struct TALER_EXCHANGE_Keys *keys;
     56 
     57   /**
     58    * URL of the exchange.
     59    */
     60   char *exchange_url;
     61 
     62   /**
     63    * Filename of the master private key of the exchange.
     64    */
     65   char *master_priv_file;
     66 
     67   /**
     68    * Label of a command to use to obtain existing
     69    * keys.
     70    */
     71   const char *last_keys_ref;
     72 
     73   /**
     74    * Last denomination date we received when doing this request.
     75    */
     76   struct GNUNET_TIME_Timestamp my_denom_date;
     77 
     78   /**
     79    * When did we send the /keys request?
     80    */
     81   struct GNUNET_TIME_Absolute request_time;
     82 
     83   /**
     84    * When did we receive the reply to the /keys request?
     85    */
     86   struct GNUNET_TIME_Absolute reply_time;
     87 
     88   /**
     89    * Are we waiting for /keys before continuing?
     90    */
     91   bool wait_for_keys;
     92 };
     93 
     94 
     95 /**
     96  * Function called with information about who is auditing
     97  * a particular exchange and what keys the exchange is using.
     98  *
     99  * @param ges our command state
    100  * @param kr response from /keys
    101  * @param[in] keys the keys of the exchange
    102  */
    103 static void
    104 cert_cb (struct GetExchangeState *ges,
    105          const struct TALER_EXCHANGE_KeysResponse *kr,
    106          struct TALER_EXCHANGE_Keys *keys)
    107 {
    108   const struct TALER_EXCHANGE_HttpResponse *hr = &kr->hr;
    109   struct TALER_TESTING_Interpreter *is = ges->is;
    110 
    111   ges->exchange = NULL;
    112   ges->reply_time = GNUNET_TIME_absolute_get ();
    113   if (NULL != ges->keys)
    114     TALER_EXCHANGE_keys_decref (ges->keys);
    115   ges->keys = keys;
    116   switch (hr->http_status)
    117   {
    118   case MHD_HTTP_OK:
    119     ges->my_denom_date = kr->details.ok.keys->last_denom_issue_date;
    120     if (ges->wait_for_keys)
    121     {
    122       ges->wait_for_keys = false;
    123       TALER_TESTING_interpreter_next (is);
    124       return;
    125     }
    126     return;
    127   default:
    128     GNUNET_break (0);
    129     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
    130                 "/keys responded with HTTP status %u\n",
    131                 hr->http_status);
    132     if (ges->wait_for_keys)
    133     {
    134       ges->wait_for_keys = false;
    135       TALER_TESTING_interpreter_fail (is);
    136       return;
    137     }
    138     return;
    139   }
    140 }
    141 
    142 
    143 /**
    144  * Run the "get_exchange" command.
    145  *
    146  * @param cls closure.
    147  * @param cmd the command currently being executed.
    148  * @param is the interpreter state.
    149  */
    150 static void
    151 get_exchange_run (void *cls,
    152                   const struct TALER_TESTING_Command *cmd,
    153                   struct TALER_TESTING_Interpreter *is)
    154 {
    155   struct GetExchangeState *ges = cls;
    156   struct TALER_EXCHANGE_Keys *xkeys = NULL;
    157 
    158   (void) cmd;
    159   if (NULL == ges->exchange_url)
    160   {
    161     GNUNET_break (0);
    162     TALER_TESTING_interpreter_fail (is);
    163     return;
    164   }
    165   if (NULL != ges->last_keys_ref)
    166   {
    167     const struct TALER_TESTING_Command *state_cmd;
    168     struct TALER_EXCHANGE_Keys *old_keys;
    169     const char *exchange_url;
    170     json_t *s_keys;
    171 
    172     state_cmd
    173       = TALER_TESTING_interpreter_lookup_command (is,
    174                                                   ges->last_keys_ref);
    175     if (NULL == state_cmd)
    176     {
    177       /* Command providing serialized keys not found.  */
    178       GNUNET_break (0);
    179       TALER_TESTING_interpreter_fail (is);
    180       return;
    181     }
    182     if (GNUNET_OK !=
    183         TALER_TESTING_get_trait_keys (state_cmd,
    184                                       &old_keys))
    185     {
    186       GNUNET_break (0);
    187       TALER_TESTING_interpreter_fail (is);
    188       return;
    189     }
    190     if (NULL == old_keys)
    191     {
    192       GNUNET_break (0);
    193       TALER_TESTING_interpreter_fail (is);
    194       return;
    195     }
    196     if (GNUNET_OK !=
    197         TALER_TESTING_get_trait_exchange_url (state_cmd,
    198                                               &exchange_url))
    199     {
    200       GNUNET_break (0);
    201       TALER_TESTING_interpreter_fail (is);
    202       return;
    203     }
    204     if (0 != strcmp (exchange_url,
    205                      ges->exchange_url))
    206     {
    207       GNUNET_break (0);
    208       TALER_TESTING_interpreter_fail (is);
    209       return;
    210     }
    211     s_keys = TALER_EXCHANGE_keys_to_json (old_keys);
    212     if (NULL == s_keys)
    213     {
    214       GNUNET_break (0);
    215       TALER_TESTING_interpreter_fail (is);
    216       return;
    217     }
    218     xkeys = TALER_EXCHANGE_keys_from_json (s_keys);
    219     if (NULL == xkeys)
    220     {
    221       GNUNET_break (0);
    222       json_dumpf (s_keys,
    223                   stderr,
    224                   JSON_INDENT (2));
    225       json_decref (s_keys);
    226       TALER_TESTING_interpreter_fail (is);
    227       return;
    228     }
    229     json_decref (s_keys);
    230   }
    231   if (NULL != ges->master_priv_file)
    232   {
    233     if (GNUNET_SYSERR ==
    234         GNUNET_CRYPTO_eddsa_key_from_file (ges->master_priv_file,
    235                                            GNUNET_YES,
    236                                            &ges->master_priv.eddsa_priv))
    237     {
    238       GNUNET_break (0);
    239       TALER_EXCHANGE_keys_decref (xkeys);
    240       TALER_TESTING_interpreter_fail (is);
    241       return;
    242     }
    243   }
    244   ges->is = is;
    245   ges->exchange
    246     = TALER_EXCHANGE_get_keys_create (
    247         TALER_TESTING_interpreter_get_context (is),
    248         ges->exchange_url);
    249   if (NULL == ges->exchange)
    250   {
    251     GNUNET_break (0);
    252     TALER_EXCHANGE_keys_decref (xkeys);
    253     TALER_TESTING_interpreter_fail (is);
    254     return;
    255   }
    256   if (NULL != xkeys)
    257   {
    258     TALER_EXCHANGE_get_keys_set_options (
    259       ges->exchange,
    260       TALER_EXCHANGE_get_keys_option_last_keys (xkeys));
    261   }
    262   TALER_EXCHANGE_keys_decref (xkeys);
    263   ges->request_time = GNUNET_TIME_absolute_get ();
    264   if (TALER_EC_NONE !=
    265       TALER_EXCHANGE_get_keys_start (ges->exchange,
    266                                      &cert_cb,
    267                                      ges))
    268   {
    269     GNUNET_break (0);
    270     TALER_EXCHANGE_get_keys_cancel (ges->exchange);
    271     ges->exchange = NULL;
    272     TALER_TESTING_interpreter_fail (is);
    273     return;
    274   }
    275   if (! ges->wait_for_keys)
    276     TALER_TESTING_interpreter_next (is);
    277 }
    278 
    279 
    280 /**
    281  * Cleanup the state.
    282  *
    283  * @param cls closure.
    284  * @param cmd the command which is being cleaned up.
    285  */
    286 static void
    287 get_exchange_cleanup (void *cls,
    288                       const struct TALER_TESTING_Command *cmd)
    289 {
    290   struct GetExchangeState *ges = cls;
    291 
    292   if (NULL != ges->exchange)
    293   {
    294     TALER_EXCHANGE_get_keys_cancel (ges->exchange);
    295     ges->exchange = NULL;
    296   }
    297   TALER_EXCHANGE_keys_decref (ges->keys);
    298   ges->keys = NULL;
    299   GNUNET_free (ges->master_priv_file);
    300   GNUNET_free (ges->exchange_url);
    301   GNUNET_free (ges);
    302 }
    303 
    304 
    305 /**
    306  * Offer internal data to a "get_exchange" CMD state to other commands.
    307  *
    308  * @param cls closure
    309  * @param[out] ret result (could be anything)
    310  * @param trait name of the trait
    311  * @param index index number of the object to offer.
    312  * @return #GNUNET_OK on success
    313  */
    314 static enum GNUNET_GenericReturnValue
    315 get_exchange_traits (void *cls,
    316                      const void **ret,
    317                      const char *trait,
    318                      unsigned int index)
    319 {
    320   struct GetExchangeState *ges = cls;
    321   unsigned int off = (NULL == ges->master_priv_file) ? 1 : 0;
    322 
    323   if (NULL != ges->keys)
    324   {
    325     struct TALER_TESTING_Trait traits[] = {
    326       TALER_TESTING_make_trait_master_priv (&ges->master_priv),
    327       TALER_TESTING_make_trait_master_pub (&ges->keys->master_pub),
    328       TALER_TESTING_make_trait_keys (ges->keys),
    329       TALER_TESTING_make_trait_exchange_url (ges->exchange_url),
    330       TALER_TESTING_make_trait_timestamp (0,
    331                                           &ges->my_denom_date),
    332       TALER_TESTING_make_trait_absolute_time (0,
    333                                               &ges->request_time),
    334       TALER_TESTING_make_trait_absolute_time (1,
    335                                               &ges->reply_time),
    336       TALER_TESTING_trait_end ()
    337     };
    338 
    339     return TALER_TESTING_get_trait (&traits[off],
    340                                     ret,
    341                                     trait,
    342                                     index);
    343   }
    344   else
    345   {
    346     struct TALER_TESTING_Trait traits[] = {
    347       TALER_TESTING_make_trait_master_priv (&ges->master_priv),
    348       TALER_TESTING_make_trait_exchange_url (ges->exchange_url),
    349       TALER_TESTING_make_trait_timestamp (0,
    350                                           &ges->my_denom_date),
    351       TALER_TESTING_make_trait_absolute_time (0,
    352                                               &ges->request_time),
    353       TALER_TESTING_make_trait_absolute_time (1,
    354                                               &ges->reply_time),
    355       TALER_TESTING_trait_end ()
    356     };
    357 
    358     return TALER_TESTING_get_trait (&traits[off],
    359                                     ret,
    360                                     trait,
    361                                     index);
    362   }
    363 }
    364 
    365 
    366 /**
    367  * Get the base URL of the exchange from @a cfg.
    368  *
    369  * @param cfg configuration to evaluate
    370  * @return base URL of the exchange according to @a cfg
    371  */
    372 static char *
    373 get_exchange_base_url (
    374   const struct GNUNET_CONFIGURATION_Handle *cfg)
    375 {
    376   char *exchange_url;
    377 
    378   if (GNUNET_OK !=
    379       GNUNET_CONFIGURATION_get_value_string (cfg,
    380                                              "exchange",
    381                                              "BASE_URL",
    382                                              &exchange_url))
    383   {
    384     GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
    385                                "exchange",
    386                                "BASE_URL");
    387     return NULL;
    388   }
    389   return exchange_url;
    390 }
    391 
    392 
    393 /**
    394  * Get the file name of the master private key file of the exchange from @a
    395  * cfg.
    396  *
    397  * @param cfg configuration to evaluate
    398  * @return base URL of the exchange according to @a cfg
    399  */
    400 static char *
    401 get_exchange_master_priv_file (
    402   const struct GNUNET_CONFIGURATION_Handle *cfg)
    403 {
    404   char *fn;
    405 
    406   if (GNUNET_OK !=
    407       GNUNET_CONFIGURATION_get_value_filename (cfg,
    408                                                "exchange-offline",
    409                                                "MASTER_PRIV_FILE",
    410                                                &fn))
    411   {
    412     GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
    413                                "exchange-offline",
    414                                "MASTER_PRIV_FILE");
    415     return NULL;
    416   }
    417   return fn;
    418 }
    419 
    420 
    421 struct TALER_TESTING_Command
    422 TALER_TESTING_cmd_get_exchange (
    423   const char *label,
    424   const struct GNUNET_CONFIGURATION_Handle *cfg,
    425   const char *last_keys_ref,
    426   bool wait_for_keys,
    427   bool load_private_key)
    428 {
    429   struct GetExchangeState *ges;
    430 
    431   ges = GNUNET_new (struct GetExchangeState);
    432   ges->exchange_url = get_exchange_base_url (cfg);
    433   ges->last_keys_ref = last_keys_ref;
    434   if (load_private_key)
    435     ges->master_priv_file = get_exchange_master_priv_file (cfg);
    436   ges->wait_for_keys = wait_for_keys;
    437   {
    438     struct TALER_TESTING_Command cmd = {
    439       .cls = ges,
    440       .label = label,
    441       .run = &get_exchange_run,
    442       .cleanup = &get_exchange_cleanup,
    443       .traits = &get_exchange_traits,
    444       .name = "exchange"
    445     };
    446 
    447     return cmd;
    448   }
    449 }