LCOV - code coverage report
Current view: top level - testing - testing_api_cmd_get_exchange.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 79 136 58.1 %
Date: 2025-06-05 21:03:14 Functions: 7 7 100.0 %

          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 "platform.h"
      25             : #include "taler_json_lib.h"
      26             : #include <gnunet/gnunet_curl_lib.h>
      27             : #include "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        1104 : get_exchange_traits (void *cls,
     288             :                      const void **ret,
     289             :                      const char *trait,
     290             :                      unsigned int index)
     291             : {
     292        1104 :   struct GetExchangeState *ges = cls;
     293        1104 :   unsigned int off = (NULL == ges->master_priv_file) ? 1 : 0;
     294             : 
     295        1104 :   if (NULL != ges->keys)
     296             :   {
     297             :     struct TALER_TESTING_Trait traits[] = {
     298        1104 :       TALER_TESTING_make_trait_master_priv (&ges->master_priv),
     299        1104 :       TALER_TESTING_make_trait_master_pub (&ges->keys->master_pub),
     300        1104 :       TALER_TESTING_make_trait_keys (ges->keys),
     301        1104 :       TALER_TESTING_make_trait_exchange_url (ges->exchange_url),
     302        1104 :       TALER_TESTING_make_trait_timestamp (0,
     303        1104 :                                           &ges->my_denom_date),
     304        1104 :       TALER_TESTING_trait_end ()
     305             :     };
     306             : 
     307        1104 :     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 1.16