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

Generated by: LCOV version 2.0-1