testing_api_cmd_get_exchange.c (11160B)
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 cert_cb (struct GetExchangeState *ges, 96 const struct TALER_EXCHANGE_KeysResponse *kr, 97 struct TALER_EXCHANGE_Keys *keys) 98 { 99 const struct TALER_EXCHANGE_HttpResponse *hr = &kr->hr; 100 struct TALER_TESTING_Interpreter *is = ges->is; 101 102 ges->exchange = NULL; 103 if (NULL != ges->keys) 104 TALER_EXCHANGE_keys_decref (ges->keys); 105 ges->keys = keys; 106 switch (hr->http_status) 107 { 108 case MHD_HTTP_OK: 109 if (ges->wait_for_keys) 110 { 111 ges->wait_for_keys = false; 112 TALER_TESTING_interpreter_next (is); 113 return; 114 } 115 ges->my_denom_date = kr->details.ok.keys->last_denom_issue_date; 116 return; 117 default: 118 GNUNET_break (0); 119 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 120 "/keys responded with HTTP status %u\n", 121 hr->http_status); 122 if (ges->wait_for_keys) 123 { 124 ges->wait_for_keys = false; 125 TALER_TESTING_interpreter_fail (is); 126 return; 127 } 128 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 get_exchange_run (void *cls, 142 const struct TALER_TESTING_Command *cmd, 143 struct TALER_TESTING_Interpreter *is) 144 { 145 struct GetExchangeState *ges = cls; 146 struct TALER_EXCHANGE_Keys *xkeys = NULL; 147 148 (void) cmd; 149 if (NULL == ges->exchange_url) 150 { 151 GNUNET_break (0); 152 TALER_TESTING_interpreter_fail (is); 153 return; 154 } 155 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 = TALER_TESTING_interpreter_lookup_command (is, 164 ges->last_keys_ref); 165 if (NULL == state_cmd) 166 { 167 /* Command providing serialized keys not found. */ 168 GNUNET_break (0); 169 TALER_TESTING_interpreter_fail (is); 170 return; 171 } 172 if (GNUNET_OK != 173 TALER_TESTING_get_trait_keys (state_cmd, 174 &old_keys)) 175 { 176 GNUNET_break (0); 177 TALER_TESTING_interpreter_fail (is); 178 return; 179 } 180 if (NULL == old_keys) 181 { 182 GNUNET_break (0); 183 TALER_TESTING_interpreter_fail (is); 184 return; 185 } 186 if (GNUNET_OK != 187 TALER_TESTING_get_trait_exchange_url (state_cmd, 188 &exchange_url)) 189 { 190 GNUNET_break (0); 191 TALER_TESTING_interpreter_fail (is); 192 return; 193 } 194 if (0 != strcmp (exchange_url, 195 ges->exchange_url)) 196 { 197 GNUNET_break (0); 198 TALER_TESTING_interpreter_fail (is); 199 return; 200 } 201 s_keys = TALER_EXCHANGE_keys_to_json (old_keys); 202 if (NULL == s_keys) 203 { 204 GNUNET_break (0); 205 TALER_TESTING_interpreter_fail (is); 206 return; 207 } 208 xkeys = TALER_EXCHANGE_keys_from_json (s_keys); 209 if (NULL == xkeys) 210 { 211 GNUNET_break (0); 212 json_dumpf (s_keys, 213 stderr, 214 JSON_INDENT (2)); 215 json_decref (s_keys); 216 TALER_TESTING_interpreter_fail (is); 217 return; 218 } 219 json_decref (s_keys); 220 } 221 if (NULL != ges->master_priv_file) 222 { 223 if (GNUNET_SYSERR == 224 GNUNET_CRYPTO_eddsa_key_from_file (ges->master_priv_file, 225 GNUNET_YES, 226 &ges->master_priv.eddsa_priv)) 227 { 228 GNUNET_break (0); 229 TALER_EXCHANGE_keys_decref (xkeys); 230 TALER_TESTING_interpreter_fail (is); 231 return; 232 } 233 } 234 ges->is = is; 235 ges->exchange 236 = TALER_EXCHANGE_get_keys_create ( 237 TALER_TESTING_interpreter_get_context (is), 238 ges->exchange_url); 239 if (NULL == ges->exchange) 240 { 241 GNUNET_break (0); 242 TALER_EXCHANGE_keys_decref (xkeys); 243 TALER_TESTING_interpreter_fail (is); 244 return; 245 } 246 if (NULL != xkeys) 247 { 248 TALER_EXCHANGE_get_keys_set_options ( 249 ges->exchange, 250 TALER_EXCHANGE_get_keys_option_last_keys (xkeys)); 251 } 252 TALER_EXCHANGE_keys_decref (xkeys); 253 if (TALER_EC_NONE != 254 TALER_EXCHANGE_get_keys_start (ges->exchange, 255 &cert_cb, 256 ges)) 257 { 258 GNUNET_break (0); 259 TALER_EXCHANGE_get_keys_cancel (ges->exchange); 260 ges->exchange = NULL; 261 TALER_TESTING_interpreter_fail (is); 262 return; 263 } 264 if (! ges->wait_for_keys) 265 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 get_exchange_cleanup (void *cls, 277 const struct TALER_TESTING_Command *cmd) 278 { 279 struct GetExchangeState *ges = cls; 280 281 if (NULL != ges->exchange) 282 { 283 TALER_EXCHANGE_get_keys_cancel (ges->exchange); 284 ges->exchange = NULL; 285 } 286 TALER_EXCHANGE_keys_decref (ges->keys); 287 ges->keys = NULL; 288 GNUNET_free (ges->master_priv_file); 289 GNUNET_free (ges->exchange_url); 290 GNUNET_free (ges); 291 } 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 get_exchange_traits (void *cls, 305 const void **ret, 306 const char *trait, 307 unsigned int index) 308 { 309 struct GetExchangeState *ges = cls; 310 unsigned int off = (NULL == ges->master_priv_file) ? 1 : 0; 311 312 if (NULL != ges->keys) 313 { 314 struct TALER_TESTING_Trait traits[] = { 315 TALER_TESTING_make_trait_master_priv (&ges->master_priv), 316 TALER_TESTING_make_trait_master_pub (&ges->keys->master_pub), 317 TALER_TESTING_make_trait_keys (ges->keys), 318 TALER_TESTING_make_trait_exchange_url (ges->exchange_url), 319 TALER_TESTING_make_trait_timestamp (0, 320 &ges->my_denom_date), 321 TALER_TESTING_trait_end () 322 }; 323 324 return TALER_TESTING_get_trait (&traits[off], 325 ret, 326 trait, 327 index); 328 } 329 else 330 { 331 struct TALER_TESTING_Trait traits[] = { 332 TALER_TESTING_make_trait_master_priv (&ges->master_priv), 333 TALER_TESTING_make_trait_exchange_url (ges->exchange_url), 334 TALER_TESTING_make_trait_timestamp (0, 335 &ges->my_denom_date), 336 TALER_TESTING_trait_end () 337 }; 338 339 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 get_exchange_base_url ( 355 const struct GNUNET_CONFIGURATION_Handle *cfg) 356 { 357 char *exchange_url; 358 359 if (GNUNET_OK != 360 GNUNET_CONFIGURATION_get_value_string (cfg, 361 "exchange", 362 "BASE_URL", 363 &exchange_url)) 364 { 365 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, 366 "exchange", 367 "BASE_URL"); 368 return NULL; 369 } 370 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 get_exchange_master_priv_file ( 383 const struct GNUNET_CONFIGURATION_Handle *cfg) 384 { 385 char *fn; 386 387 if (GNUNET_OK != 388 GNUNET_CONFIGURATION_get_value_filename (cfg, 389 "exchange-offline", 390 "MASTER_PRIV_FILE", 391 &fn)) 392 { 393 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, 394 "exchange-offline", 395 "MASTER_PRIV_FILE"); 396 return NULL; 397 } 398 return fn; 399 } 400 401 402 struct TALER_TESTING_Command 403 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 ges = GNUNET_new (struct GetExchangeState); 413 ges->exchange_url = get_exchange_base_url (cfg); 414 ges->last_keys_ref = last_keys_ref; 415 if (load_private_key) 416 ges->master_priv_file = get_exchange_master_priv_file (cfg); 417 ges->wait_for_keys = wait_for_keys; 418 { 419 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 return cmd; 429 } 430 }