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

Generated by: LCOV version 2.0-1