LCOV - code coverage report
Current view: top level - testing - testing_api_cmd_get_exchange.c (source / functions) Coverage Total Hit
Test: coverage.info Lines: 57.4 % 155 89
Test Date: 2026-10-17 15:46:49 Functions: 100.0 % 7 7

            Line data    Source code
       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           36 : cert_cb (struct GetExchangeState *ges,
     105              :          const struct TALER_EXCHANGE_KeysResponse *kr,
     106              :          struct TALER_EXCHANGE_Keys *keys)
     107              : {
     108           36 :   const struct TALER_EXCHANGE_HttpResponse *hr = &kr->hr;
     109           36 :   struct TALER_TESTING_Interpreter *is = ges->is;
     110              : 
     111           36 :   ges->exchange = NULL;
     112           36 :   ges->reply_time = GNUNET_TIME_absolute_get ();
     113           36 :   if (NULL != ges->keys)
     114            0 :     TALER_EXCHANGE_keys_decref (ges->keys);
     115           36 :   ges->keys = keys;
     116           36 :   switch (hr->http_status)
     117              :   {
     118           36 :   case MHD_HTTP_OK:
     119           36 :     ges->my_denom_date = kr->details.ok.keys->last_denom_issue_date;
     120           36 :     if (ges->wait_for_keys)
     121              :     {
     122           36 :       ges->wait_for_keys = false;
     123           36 :       TALER_TESTING_interpreter_next (is);
     124           36 :       return;
     125              :     }
     126            0 :     return;
     127            0 :   default:
     128            0 :     GNUNET_break (0);
     129            0 :     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
     130              :                 "/keys responded with HTTP status %u\n",
     131              :                 hr->http_status);
     132            0 :     if (ges->wait_for_keys)
     133              :     {
     134            0 :       ges->wait_for_keys = false;
     135            0 :       TALER_TESTING_interpreter_fail (is);
     136            0 :       return;
     137              :     }
     138            0 :     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           36 : get_exchange_run (void *cls,
     152              :                   const struct TALER_TESTING_Command *cmd,
     153              :                   struct TALER_TESTING_Interpreter *is)
     154              : {
     155           36 :   struct GetExchangeState *ges = cls;
     156           36 :   struct TALER_EXCHANGE_Keys *xkeys = NULL;
     157              : 
     158              :   (void) cmd;
     159           36 :   if (NULL == ges->exchange_url)
     160              :   {
     161            0 :     GNUNET_break (0);
     162            0 :     TALER_TESTING_interpreter_fail (is);
     163            0 :     return;
     164              :   }
     165           36 :   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            8 :       = TALER_TESTING_interpreter_lookup_command (is,
     174              :                                                   ges->last_keys_ref);
     175            8 :     if (NULL == state_cmd)
     176              :     {
     177              :       /* Command providing serialized keys not found.  */
     178            0 :       GNUNET_break (0);
     179            0 :       TALER_TESTING_interpreter_fail (is);
     180            0 :       return;
     181              :     }
     182            8 :     if (GNUNET_OK !=
     183            8 :         TALER_TESTING_get_trait_keys (state_cmd,
     184              :                                       &old_keys))
     185              :     {
     186            0 :       GNUNET_break (0);
     187            0 :       TALER_TESTING_interpreter_fail (is);
     188            0 :       return;
     189              :     }
     190            8 :     if (NULL == old_keys)
     191              :     {
     192            0 :       GNUNET_break (0);
     193            0 :       TALER_TESTING_interpreter_fail (is);
     194            0 :       return;
     195              :     }
     196            8 :     if (GNUNET_OK !=
     197            8 :         TALER_TESTING_get_trait_exchange_url (state_cmd,
     198              :                                               &exchange_url))
     199              :     {
     200            0 :       GNUNET_break (0);
     201            0 :       TALER_TESTING_interpreter_fail (is);
     202            0 :       return;
     203              :     }
     204            8 :     if (0 != strcmp (exchange_url,
     205            8 :                      ges->exchange_url))
     206              :     {
     207            0 :       GNUNET_break (0);
     208            0 :       TALER_TESTING_interpreter_fail (is);
     209            0 :       return;
     210              :     }
     211            8 :     s_keys = TALER_EXCHANGE_keys_to_json (old_keys);
     212            8 :     if (NULL == s_keys)
     213              :     {
     214            0 :       GNUNET_break (0);
     215            0 :       TALER_TESTING_interpreter_fail (is);
     216            0 :       return;
     217              :     }
     218            8 :     xkeys = TALER_EXCHANGE_keys_from_json (s_keys);
     219            8 :     if (NULL == xkeys)
     220              :     {
     221            0 :       GNUNET_break (0);
     222            0 :       json_dumpf (s_keys,
     223              :                   stderr,
     224              :                   JSON_INDENT (2));
     225            0 :       json_decref (s_keys);
     226            0 :       TALER_TESTING_interpreter_fail (is);
     227            0 :       return;
     228              :     }
     229            8 :     json_decref (s_keys);
     230              :   }
     231           36 :   if (NULL != ges->master_priv_file)
     232              :   {
     233           36 :     if (GNUNET_SYSERR ==
     234           36 :         GNUNET_CRYPTO_eddsa_key_from_file (ges->master_priv_file,
     235              :                                            GNUNET_YES,
     236              :                                            &ges->master_priv.eddsa_priv))
     237              :     {
     238            0 :       GNUNET_break (0);
     239            0 :       TALER_EXCHANGE_keys_decref (xkeys);
     240            0 :       TALER_TESTING_interpreter_fail (is);
     241            0 :       return;
     242              :     }
     243              :   }
     244           36 :   ges->is = is;
     245              :   ges->exchange
     246           36 :     = TALER_EXCHANGE_get_keys_create (
     247              :         TALER_TESTING_interpreter_get_context (is),
     248           36 :         ges->exchange_url);
     249           36 :   if (NULL == ges->exchange)
     250              :   {
     251            0 :     GNUNET_break (0);
     252            0 :     TALER_EXCHANGE_keys_decref (xkeys);
     253            0 :     TALER_TESTING_interpreter_fail (is);
     254            0 :     return;
     255              :   }
     256           36 :   if (NULL != xkeys)
     257              :   {
     258            8 :     TALER_EXCHANGE_get_keys_set_options (
     259              :       ges->exchange,
     260              :       TALER_EXCHANGE_get_keys_option_last_keys (xkeys));
     261              :   }
     262           36 :   TALER_EXCHANGE_keys_decref (xkeys);
     263           36 :   ges->request_time = GNUNET_TIME_absolute_get ();
     264           36 :   if (TALER_EC_NONE !=
     265           36 :       TALER_EXCHANGE_get_keys_start (ges->exchange,
     266              :                                      &cert_cb,
     267              :                                      ges))
     268              :   {
     269            0 :     GNUNET_break (0);
     270            0 :     TALER_EXCHANGE_get_keys_cancel (ges->exchange);
     271            0 :     ges->exchange = NULL;
     272            0 :     TALER_TESTING_interpreter_fail (is);
     273            0 :     return;
     274              :   }
     275           36 :   if (! ges->wait_for_keys)
     276            0 :     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           36 : get_exchange_cleanup (void *cls,
     288              :                       const struct TALER_TESTING_Command *cmd)
     289              : {
     290           36 :   struct GetExchangeState *ges = cls;
     291              : 
     292           36 :   if (NULL != ges->exchange)
     293              :   {
     294            0 :     TALER_EXCHANGE_get_keys_cancel (ges->exchange);
     295            0 :     ges->exchange = NULL;
     296              :   }
     297           36 :   TALER_EXCHANGE_keys_decref (ges->keys);
     298           36 :   ges->keys = NULL;
     299           36 :   GNUNET_free (ges->master_priv_file);
     300           36 :   GNUNET_free (ges->exchange_url);
     301           36 :   GNUNET_free (ges);
     302           36 : }
     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         1556 : get_exchange_traits (void *cls,
     316              :                      const void **ret,
     317              :                      const char *trait,
     318              :                      unsigned int index)
     319              : {
     320         1556 :   struct GetExchangeState *ges = cls;
     321         1556 :   unsigned int off = (NULL == ges->master_priv_file) ? 1 : 0;
     322              : 
     323         1556 :   if (NULL != ges->keys)
     324              :   {
     325              :     struct TALER_TESTING_Trait traits[] = {
     326         1556 :       TALER_TESTING_make_trait_master_priv (&ges->master_priv),
     327         1556 :       TALER_TESTING_make_trait_master_pub (&ges->keys->master_pub),
     328         1556 :       TALER_TESTING_make_trait_keys (ges->keys),
     329         1556 :       TALER_TESTING_make_trait_exchange_url (ges->exchange_url),
     330         1556 :       TALER_TESTING_make_trait_timestamp (0,
     331         1556 :                                           &ges->my_denom_date),
     332         1556 :       TALER_TESTING_make_trait_absolute_time (0,
     333         1556 :                                               &ges->request_time),
     334         1556 :       TALER_TESTING_make_trait_absolute_time (1,
     335         1556 :                                               &ges->reply_time),
     336         1556 :       TALER_TESTING_trait_end ()
     337              :     };
     338              : 
     339         1556 :     return TALER_TESTING_get_trait (&traits[off],
     340              :                                     ret,
     341              :                                     trait,
     342              :                                     index);
     343              :   }
     344              :   else
     345              :   {
     346              :     struct TALER_TESTING_Trait traits[] = {
     347            0 :       TALER_TESTING_make_trait_master_priv (&ges->master_priv),
     348            0 :       TALER_TESTING_make_trait_exchange_url (ges->exchange_url),
     349            0 :       TALER_TESTING_make_trait_timestamp (0,
     350            0 :                                           &ges->my_denom_date),
     351            0 :       TALER_TESTING_make_trait_absolute_time (0,
     352            0 :                                               &ges->request_time),
     353            0 :       TALER_TESTING_make_trait_absolute_time (1,
     354            0 :                                               &ges->reply_time),
     355            0 :       TALER_TESTING_trait_end ()
     356              :     };
     357              : 
     358            0 :     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           36 : get_exchange_base_url (
     374              :   const struct GNUNET_CONFIGURATION_Handle *cfg)
     375              : {
     376              :   char *exchange_url;
     377              : 
     378           36 :   if (GNUNET_OK !=
     379           36 :       GNUNET_CONFIGURATION_get_value_string (cfg,
     380              :                                              "exchange",
     381              :                                              "BASE_URL",
     382              :                                              &exchange_url))
     383              :   {
     384            0 :     GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
     385              :                                "exchange",
     386              :                                "BASE_URL");
     387            0 :     return NULL;
     388              :   }
     389           36 :   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           36 : get_exchange_master_priv_file (
     402              :   const struct GNUNET_CONFIGURATION_Handle *cfg)
     403              : {
     404              :   char *fn;
     405              : 
     406           36 :   if (GNUNET_OK !=
     407           36 :       GNUNET_CONFIGURATION_get_value_filename (cfg,
     408              :                                                "exchange-offline",
     409              :                                                "MASTER_PRIV_FILE",
     410              :                                                &fn))
     411              :   {
     412            0 :     GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
     413              :                                "exchange-offline",
     414              :                                "MASTER_PRIV_FILE");
     415            0 :     return NULL;
     416              :   }
     417           36 :   return fn;
     418              : }
     419              : 
     420              : 
     421              : struct TALER_TESTING_Command
     422           36 : 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           36 :   ges = GNUNET_new (struct GetExchangeState);
     432           36 :   ges->exchange_url = get_exchange_base_url (cfg);
     433           36 :   ges->last_keys_ref = last_keys_ref;
     434           36 :   if (load_private_key)
     435           36 :     ges->master_priv_file = get_exchange_master_priv_file (cfg);
     436           36 :   ges->wait_for_keys = wait_for_keys;
     437              :   {
     438           36 :     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           36 :     return cmd;
     448              :   }
     449              : }
        

Generated by: LCOV version 2.0-1