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