testing_api_cmd_get_exchange.c (11132B)
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 * Are we waiting for /keys before continuing? 80 */ 81 bool wait_for_keys; 82 }; 83 84 85 /** 86 * Function called with information about who is auditing 87 * a particular exchange and what keys the exchange is using. 88 * 89 * @param ges our command state 90 * @param kr response from /keys 91 * @param[in] keys the keys of the exchange 92 */ 93 static void 94 cert_cb (struct GetExchangeState *ges, 95 const struct TALER_EXCHANGE_KeysResponse *kr, 96 struct TALER_EXCHANGE_Keys *keys) 97 { 98 const struct TALER_EXCHANGE_HttpResponse *hr = &kr->hr; 99 struct TALER_TESTING_Interpreter *is = ges->is; 100 101 ges->exchange = NULL; 102 if (NULL != ges->keys) 103 TALER_EXCHANGE_keys_decref (ges->keys); 104 ges->keys = keys; 105 switch (hr->http_status) 106 { 107 case MHD_HTTP_OK: 108 if (ges->wait_for_keys) 109 { 110 ges->wait_for_keys = false; 111 TALER_TESTING_interpreter_next (is); 112 return; 113 } 114 ges->my_denom_date = kr->details.ok.keys->last_denom_issue_date; 115 return; 116 default: 117 GNUNET_break (0); 118 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 119 "/keys responded with HTTP status %u\n", 120 hr->http_status); 121 if (ges->wait_for_keys) 122 { 123 ges->wait_for_keys = false; 124 TALER_TESTING_interpreter_fail (is); 125 return; 126 } 127 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 get_exchange_run (void *cls, 141 const struct TALER_TESTING_Command *cmd, 142 struct TALER_TESTING_Interpreter *is) 143 { 144 struct GetExchangeState *ges = cls; 145 struct TALER_EXCHANGE_Keys *xkeys = NULL; 146 147 (void) cmd; 148 if (NULL == ges->exchange_url) 149 { 150 GNUNET_break (0); 151 TALER_TESTING_interpreter_fail (is); 152 return; 153 } 154 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 = TALER_TESTING_interpreter_lookup_command (is, 163 ges->last_keys_ref); 164 if (NULL == state_cmd) 165 { 166 /* Command providing serialized keys not found. */ 167 GNUNET_break (0); 168 TALER_TESTING_interpreter_fail (is); 169 return; 170 } 171 if (GNUNET_OK != 172 TALER_TESTING_get_trait_keys (state_cmd, 173 &old_keys)) 174 { 175 GNUNET_break (0); 176 TALER_TESTING_interpreter_fail (is); 177 return; 178 } 179 if (NULL == old_keys) 180 { 181 GNUNET_break (0); 182 TALER_TESTING_interpreter_fail (is); 183 return; 184 } 185 if (GNUNET_OK != 186 TALER_TESTING_get_trait_exchange_url (state_cmd, 187 &exchange_url)) 188 { 189 GNUNET_break (0); 190 TALER_TESTING_interpreter_fail (is); 191 return; 192 } 193 if (0 != strcmp (exchange_url, 194 ges->exchange_url)) 195 { 196 GNUNET_break (0); 197 TALER_TESTING_interpreter_fail (is); 198 return; 199 } 200 s_keys = TALER_EXCHANGE_keys_to_json (old_keys); 201 if (NULL == s_keys) 202 { 203 GNUNET_break (0); 204 TALER_TESTING_interpreter_fail (is); 205 return; 206 } 207 xkeys = TALER_EXCHANGE_keys_from_json (s_keys); 208 if (NULL == xkeys) 209 { 210 GNUNET_break (0); 211 json_dumpf (s_keys, 212 stderr, 213 JSON_INDENT (2)); 214 json_decref (s_keys); 215 TALER_TESTING_interpreter_fail (is); 216 return; 217 } 218 json_decref (s_keys); 219 } 220 if (NULL != ges->master_priv_file) 221 { 222 if (GNUNET_SYSERR == 223 GNUNET_CRYPTO_eddsa_key_from_file (ges->master_priv_file, 224 GNUNET_YES, 225 &ges->master_priv.eddsa_priv)) 226 { 227 GNUNET_break (0); 228 TALER_EXCHANGE_keys_decref (xkeys); 229 TALER_TESTING_interpreter_fail (is); 230 return; 231 } 232 } 233 ges->is = is; 234 ges->exchange 235 = TALER_EXCHANGE_get_keys_create ( 236 TALER_TESTING_interpreter_get_context (is), 237 ges->exchange_url); 238 if (NULL == ges->exchange) 239 { 240 GNUNET_break (0); 241 TALER_EXCHANGE_keys_decref (xkeys); 242 TALER_TESTING_interpreter_fail (is); 243 return; 244 } 245 if (NULL != xkeys) 246 { 247 TALER_EXCHANGE_get_keys_set_options ( 248 ges->exchange, 249 TALER_EXCHANGE_get_keys_option_last_keys (xkeys)); 250 } 251 TALER_EXCHANGE_keys_decref (xkeys); 252 if (TALER_EC_NONE != 253 TALER_EXCHANGE_get_keys_start (ges->exchange, 254 &cert_cb, 255 ges)) 256 { 257 GNUNET_break (0); 258 TALER_EXCHANGE_get_keys_cancel (ges->exchange); 259 ges->exchange = NULL; 260 TALER_TESTING_interpreter_fail (is); 261 return; 262 } 263 if (! ges->wait_for_keys) 264 TALER_TESTING_interpreter_next (is); 265 } 266 267 268 /** 269 * Cleanup the state. 270 * 271 * @param cls closure. 272 * @param cmd the command which is being cleaned up. 273 */ 274 static void 275 get_exchange_cleanup (void *cls, 276 const struct TALER_TESTING_Command *cmd) 277 { 278 struct GetExchangeState *ges = cls; 279 280 if (NULL != ges->exchange) 281 { 282 TALER_EXCHANGE_get_keys_cancel (ges->exchange); 283 ges->exchange = NULL; 284 } 285 TALER_EXCHANGE_keys_decref (ges->keys); 286 ges->keys = NULL; 287 GNUNET_free (ges->master_priv_file); 288 GNUNET_free (ges->exchange_url); 289 GNUNET_free (ges); 290 } 291 292 293 /** 294 * Offer internal data to a "get_exchange" CMD state to other commands. 295 * 296 * @param cls closure 297 * @param[out] ret result (could be anything) 298 * @param trait name of the trait 299 * @param index index number of the object to offer. 300 * @return #GNUNET_OK on success 301 */ 302 static enum GNUNET_GenericReturnValue 303 get_exchange_traits (void *cls, 304 const void **ret, 305 const char *trait, 306 unsigned int index) 307 { 308 struct GetExchangeState *ges = cls; 309 unsigned int off = (NULL == ges->master_priv_file) ? 1 : 0; 310 311 if (NULL != ges->keys) 312 { 313 struct TALER_TESTING_Trait traits[] = { 314 TALER_TESTING_make_trait_master_priv (&ges->master_priv), 315 TALER_TESTING_make_trait_master_pub (&ges->keys->master_pub), 316 TALER_TESTING_make_trait_keys (ges->keys), 317 TALER_TESTING_make_trait_exchange_url (ges->exchange_url), 318 TALER_TESTING_make_trait_timestamp (0, 319 &ges->my_denom_date), 320 TALER_TESTING_trait_end () 321 }; 322 323 return TALER_TESTING_get_trait (&traits[off], 324 ret, 325 trait, 326 index); 327 } 328 else 329 { 330 struct TALER_TESTING_Trait traits[] = { 331 TALER_TESTING_make_trait_master_priv (&ges->master_priv), 332 TALER_TESTING_make_trait_exchange_url (ges->exchange_url), 333 TALER_TESTING_make_trait_timestamp (0, 334 &ges->my_denom_date), 335 TALER_TESTING_trait_end () 336 }; 337 338 return TALER_TESTING_get_trait (&traits[off], 339 ret, 340 trait, 341 index); 342 } 343 } 344 345 346 /** 347 * Get the base URL of the exchange from @a cfg. 348 * 349 * @param cfg configuration to evaluate 350 * @return base URL of the exchange according to @a cfg 351 */ 352 static char * 353 get_exchange_base_url ( 354 const struct GNUNET_CONFIGURATION_Handle *cfg) 355 { 356 char *exchange_url; 357 358 if (GNUNET_OK != 359 GNUNET_CONFIGURATION_get_value_string (cfg, 360 "exchange", 361 "BASE_URL", 362 &exchange_url)) 363 { 364 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, 365 "exchange", 366 "BASE_URL"); 367 return NULL; 368 } 369 return exchange_url; 370 } 371 372 373 /** 374 * Get the file name of the master private key file of the exchange from @a 375 * cfg. 376 * 377 * @param cfg configuration to evaluate 378 * @return base URL of the exchange according to @a cfg 379 */ 380 static char * 381 get_exchange_master_priv_file ( 382 const struct GNUNET_CONFIGURATION_Handle *cfg) 383 { 384 char *fn; 385 386 if (GNUNET_OK != 387 GNUNET_CONFIGURATION_get_value_filename (cfg, 388 "exchange-offline", 389 "MASTER_PRIV_FILE", 390 &fn)) 391 { 392 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, 393 "exchange-offline", 394 "MASTER_PRIV_FILE"); 395 return NULL; 396 } 397 return fn; 398 } 399 400 401 struct TALER_TESTING_Command 402 TALER_TESTING_cmd_get_exchange ( 403 const char *label, 404 const struct GNUNET_CONFIGURATION_Handle *cfg, 405 const char *last_keys_ref, 406 bool wait_for_keys, 407 bool load_private_key) 408 { 409 struct GetExchangeState *ges; 410 411 ges = GNUNET_new (struct GetExchangeState); 412 ges->exchange_url = get_exchange_base_url (cfg); 413 ges->last_keys_ref = last_keys_ref; 414 if (load_private_key) 415 ges->master_priv_file = get_exchange_master_priv_file (cfg); 416 ges->wait_for_keys = wait_for_keys; 417 { 418 struct TALER_TESTING_Command cmd = { 419 .cls = ges, 420 .label = label, 421 .run = &get_exchange_run, 422 .cleanup = &get_exchange_cleanup, 423 .traits = &get_exchange_traits, 424 .name = "exchange" 425 }; 426 427 return cmd; 428 } 429 }