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 (11132B)


      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    * Are we waiting for /keys before continuing?
     80    */
     81   bool wait_for_keys;
     82 };
     83 
     84 
     85 /**
     86  * Function called with information about who is auditing
     87  * a particular exchange and what keys the exchange is using.
     88  *
     89  * @param ges our command state
     90  * @param kr response from /keys
     91  * @param[in] keys the keys of the exchange
     92  */
     93 static void
     94 cert_cb (struct GetExchangeState *ges,
     95          const struct TALER_EXCHANGE_KeysResponse *kr,
     96          struct TALER_EXCHANGE_Keys *keys)
     97 {
     98   const struct TALER_EXCHANGE_HttpResponse *hr = &kr->hr;
     99   struct TALER_TESTING_Interpreter *is = ges->is;
    100 
    101   ges->exchange = NULL;
    102   if (NULL != ges->keys)
    103     TALER_EXCHANGE_keys_decref (ges->keys);
    104   ges->keys = keys;
    105   switch (hr->http_status)
    106   {
    107   case MHD_HTTP_OK:
    108     if (ges->wait_for_keys)
    109     {
    110       ges->wait_for_keys = false;
    111       TALER_TESTING_interpreter_next (is);
    112       return;
    113     }
    114     ges->my_denom_date = kr->details.ok.keys->last_denom_issue_date;
    115     return;
    116   default:
    117     GNUNET_break (0);
    118     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
    119                 "/keys responded with HTTP status %u\n",
    120                 hr->http_status);
    121     if (ges->wait_for_keys)
    122     {
    123       ges->wait_for_keys = false;
    124       TALER_TESTING_interpreter_fail (is);
    125       return;
    126     }
    127     return;
    128   }
    129 }
    130 
    131 
    132 /**
    133  * Run the "get_exchange" command.
    134  *
    135  * @param cls closure.
    136  * @param cmd the command currently being executed.
    137  * @param is the interpreter state.
    138  */
    139 static void
    140 get_exchange_run (void *cls,
    141                   const struct TALER_TESTING_Command *cmd,
    142                   struct TALER_TESTING_Interpreter *is)
    143 {
    144   struct GetExchangeState *ges = cls;
    145   struct TALER_EXCHANGE_Keys *xkeys = NULL;
    146 
    147   (void) cmd;
    148   if (NULL == ges->exchange_url)
    149   {
    150     GNUNET_break (0);
    151     TALER_TESTING_interpreter_fail (is);
    152     return;
    153   }
    154   if (NULL != ges->last_keys_ref)
    155   {
    156     const struct TALER_TESTING_Command *state_cmd;
    157     struct TALER_EXCHANGE_Keys *old_keys;
    158     const char *exchange_url;
    159     json_t *s_keys;
    160 
    161     state_cmd
    162       = TALER_TESTING_interpreter_lookup_command (is,
    163                                                   ges->last_keys_ref);
    164     if (NULL == state_cmd)
    165     {
    166       /* Command providing serialized keys not found.  */
    167       GNUNET_break (0);
    168       TALER_TESTING_interpreter_fail (is);
    169       return;
    170     }
    171     if (GNUNET_OK !=
    172         TALER_TESTING_get_trait_keys (state_cmd,
    173                                       &old_keys))
    174     {
    175       GNUNET_break (0);
    176       TALER_TESTING_interpreter_fail (is);
    177       return;
    178     }
    179     if (NULL == old_keys)
    180     {
    181       GNUNET_break (0);
    182       TALER_TESTING_interpreter_fail (is);
    183       return;
    184     }
    185     if (GNUNET_OK !=
    186         TALER_TESTING_get_trait_exchange_url (state_cmd,
    187                                               &exchange_url))
    188     {
    189       GNUNET_break (0);
    190       TALER_TESTING_interpreter_fail (is);
    191       return;
    192     }
    193     if (0 != strcmp (exchange_url,
    194                      ges->exchange_url))
    195     {
    196       GNUNET_break (0);
    197       TALER_TESTING_interpreter_fail (is);
    198       return;
    199     }
    200     s_keys = TALER_EXCHANGE_keys_to_json (old_keys);
    201     if (NULL == s_keys)
    202     {
    203       GNUNET_break (0);
    204       TALER_TESTING_interpreter_fail (is);
    205       return;
    206     }
    207     xkeys = TALER_EXCHANGE_keys_from_json (s_keys);
    208     if (NULL == xkeys)
    209     {
    210       GNUNET_break (0);
    211       json_dumpf (s_keys,
    212                   stderr,
    213                   JSON_INDENT (2));
    214       json_decref (s_keys);
    215       TALER_TESTING_interpreter_fail (is);
    216       return;
    217     }
    218     json_decref (s_keys);
    219   }
    220   if (NULL != ges->master_priv_file)
    221   {
    222     if (GNUNET_SYSERR ==
    223         GNUNET_CRYPTO_eddsa_key_from_file (ges->master_priv_file,
    224                                            GNUNET_YES,
    225                                            &ges->master_priv.eddsa_priv))
    226     {
    227       GNUNET_break (0);
    228       TALER_EXCHANGE_keys_decref (xkeys);
    229       TALER_TESTING_interpreter_fail (is);
    230       return;
    231     }
    232   }
    233   ges->is = is;
    234   ges->exchange
    235     = TALER_EXCHANGE_get_keys_create (
    236         TALER_TESTING_interpreter_get_context (is),
    237         ges->exchange_url);
    238   if (NULL == ges->exchange)
    239   {
    240     GNUNET_break (0);
    241     TALER_EXCHANGE_keys_decref (xkeys);
    242     TALER_TESTING_interpreter_fail (is);
    243     return;
    244   }
    245   if (NULL != xkeys)
    246   {
    247     TALER_EXCHANGE_get_keys_set_options (
    248       ges->exchange,
    249       TALER_EXCHANGE_get_keys_option_last_keys (xkeys));
    250   }
    251   TALER_EXCHANGE_keys_decref (xkeys);
    252   if (TALER_EC_NONE !=
    253       TALER_EXCHANGE_get_keys_start (ges->exchange,
    254                                      &cert_cb,
    255                                      ges))
    256   {
    257     GNUNET_break (0);
    258     TALER_EXCHANGE_get_keys_cancel (ges->exchange);
    259     ges->exchange = NULL;
    260     TALER_TESTING_interpreter_fail (is);
    261     return;
    262   }
    263   if (! ges->wait_for_keys)
    264     TALER_TESTING_interpreter_next (is);
    265 }
    266 
    267 
    268 /**
    269  * Cleanup the state.
    270  *
    271  * @param cls closure.
    272  * @param cmd the command which is being cleaned up.
    273  */
    274 static void
    275 get_exchange_cleanup (void *cls,
    276                       const struct TALER_TESTING_Command *cmd)
    277 {
    278   struct GetExchangeState *ges = cls;
    279 
    280   if (NULL != ges->exchange)
    281   {
    282     TALER_EXCHANGE_get_keys_cancel (ges->exchange);
    283     ges->exchange = NULL;
    284   }
    285   TALER_EXCHANGE_keys_decref (ges->keys);
    286   ges->keys = NULL;
    287   GNUNET_free (ges->master_priv_file);
    288   GNUNET_free (ges->exchange_url);
    289   GNUNET_free (ges);
    290 }
    291 
    292 
    293 /**
    294  * Offer internal data to a "get_exchange" CMD state to other commands.
    295  *
    296  * @param cls closure
    297  * @param[out] ret result (could be anything)
    298  * @param trait name of the trait
    299  * @param index index number of the object to offer.
    300  * @return #GNUNET_OK on success
    301  */
    302 static enum GNUNET_GenericReturnValue
    303 get_exchange_traits (void *cls,
    304                      const void **ret,
    305                      const char *trait,
    306                      unsigned int index)
    307 {
    308   struct GetExchangeState *ges = cls;
    309   unsigned int off = (NULL == ges->master_priv_file) ? 1 : 0;
    310 
    311   if (NULL != ges->keys)
    312   {
    313     struct TALER_TESTING_Trait traits[] = {
    314       TALER_TESTING_make_trait_master_priv (&ges->master_priv),
    315       TALER_TESTING_make_trait_master_pub (&ges->keys->master_pub),
    316       TALER_TESTING_make_trait_keys (ges->keys),
    317       TALER_TESTING_make_trait_exchange_url (ges->exchange_url),
    318       TALER_TESTING_make_trait_timestamp (0,
    319                                           &ges->my_denom_date),
    320       TALER_TESTING_trait_end ()
    321     };
    322 
    323     return TALER_TESTING_get_trait (&traits[off],
    324                                     ret,
    325                                     trait,
    326                                     index);
    327   }
    328   else
    329   {
    330     struct TALER_TESTING_Trait traits[] = {
    331       TALER_TESTING_make_trait_master_priv (&ges->master_priv),
    332       TALER_TESTING_make_trait_exchange_url (ges->exchange_url),
    333       TALER_TESTING_make_trait_timestamp (0,
    334                                           &ges->my_denom_date),
    335       TALER_TESTING_trait_end ()
    336     };
    337 
    338     return TALER_TESTING_get_trait (&traits[off],
    339                                     ret,
    340                                     trait,
    341                                     index);
    342   }
    343 }
    344 
    345 
    346 /**
    347  * Get the base URL of the exchange from @a cfg.
    348  *
    349  * @param cfg configuration to evaluate
    350  * @return base URL of the exchange according to @a cfg
    351  */
    352 static char *
    353 get_exchange_base_url (
    354   const struct GNUNET_CONFIGURATION_Handle *cfg)
    355 {
    356   char *exchange_url;
    357 
    358   if (GNUNET_OK !=
    359       GNUNET_CONFIGURATION_get_value_string (cfg,
    360                                              "exchange",
    361                                              "BASE_URL",
    362                                              &exchange_url))
    363   {
    364     GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
    365                                "exchange",
    366                                "BASE_URL");
    367     return NULL;
    368   }
    369   return exchange_url;
    370 }
    371 
    372 
    373 /**
    374  * Get the file name of the master private key file of the exchange from @a
    375  * cfg.
    376  *
    377  * @param cfg configuration to evaluate
    378  * @return base URL of the exchange according to @a cfg
    379  */
    380 static char *
    381 get_exchange_master_priv_file (
    382   const struct GNUNET_CONFIGURATION_Handle *cfg)
    383 {
    384   char *fn;
    385 
    386   if (GNUNET_OK !=
    387       GNUNET_CONFIGURATION_get_value_filename (cfg,
    388                                                "exchange-offline",
    389                                                "MASTER_PRIV_FILE",
    390                                                &fn))
    391   {
    392     GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
    393                                "exchange-offline",
    394                                "MASTER_PRIV_FILE");
    395     return NULL;
    396   }
    397   return fn;
    398 }
    399 
    400 
    401 struct TALER_TESTING_Command
    402 TALER_TESTING_cmd_get_exchange (
    403   const char *label,
    404   const struct GNUNET_CONFIGURATION_Handle *cfg,
    405   const char *last_keys_ref,
    406   bool wait_for_keys,
    407   bool load_private_key)
    408 {
    409   struct GetExchangeState *ges;
    410 
    411   ges = GNUNET_new (struct GetExchangeState);
    412   ges->exchange_url = get_exchange_base_url (cfg);
    413   ges->last_keys_ref = last_keys_ref;
    414   if (load_private_key)
    415     ges->master_priv_file = get_exchange_master_priv_file (cfg);
    416   ges->wait_for_keys = wait_for_keys;
    417   {
    418     struct TALER_TESTING_Command cmd = {
    419       .cls = ges,
    420       .label = label,
    421       .run = &get_exchange_run,
    422       .cleanup = &get_exchange_cleanup,
    423       .traits = &get_exchange_traits,
    424       .name = "exchange"
    425     };
    426 
    427     return cmd;
    428   }
    429 }