testing_api_cmd_get_exchange.c (10680B)
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 cert_cb (void *cls, 94 const struct TALER_EXCHANGE_KeysResponse *kr, 95 struct TALER_EXCHANGE_Keys *keys) 96 { 97 struct GetExchangeState *ges = cls; 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 (TALER_TESTING_interpreter_get_context (is), 236 ges->exchange_url, 237 xkeys, 238 &cert_cb, 239 ges); 240 TALER_EXCHANGE_keys_decref (xkeys); 241 if (NULL == ges->exchange) 242 { 243 GNUNET_break (0); 244 TALER_TESTING_interpreter_fail (is); 245 return; 246 } 247 if (! ges->wait_for_keys) 248 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 get_exchange_cleanup (void *cls, 260 const struct TALER_TESTING_Command *cmd) 261 { 262 struct GetExchangeState *ges = cls; 263 264 if (NULL != ges->exchange) 265 { 266 TALER_EXCHANGE_get_keys_cancel (ges->exchange); 267 ges->exchange = NULL; 268 } 269 TALER_EXCHANGE_keys_decref (ges->keys); 270 ges->keys = NULL; 271 GNUNET_free (ges->master_priv_file); 272 GNUNET_free (ges->exchange_url); 273 GNUNET_free (ges); 274 } 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 get_exchange_traits (void *cls, 288 const void **ret, 289 const char *trait, 290 unsigned int index) 291 { 292 struct GetExchangeState *ges = cls; 293 unsigned int off = (NULL == ges->master_priv_file) ? 1 : 0; 294 295 if (NULL != ges->keys) 296 { 297 struct TALER_TESTING_Trait traits[] = { 298 TALER_TESTING_make_trait_master_priv (&ges->master_priv), 299 TALER_TESTING_make_trait_master_pub (&ges->keys->master_pub), 300 TALER_TESTING_make_trait_keys (ges->keys), 301 TALER_TESTING_make_trait_exchange_url (ges->exchange_url), 302 TALER_TESTING_make_trait_timestamp (0, 303 &ges->my_denom_date), 304 TALER_TESTING_trait_end () 305 }; 306 307 return TALER_TESTING_get_trait (&traits[off], 308 ret, 309 trait, 310 index); 311 } 312 else 313 { 314 struct TALER_TESTING_Trait traits[] = { 315 TALER_TESTING_make_trait_master_priv (&ges->master_priv), 316 TALER_TESTING_make_trait_exchange_url (ges->exchange_url), 317 TALER_TESTING_make_trait_timestamp (0, 318 &ges->my_denom_date), 319 TALER_TESTING_trait_end () 320 }; 321 322 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 get_exchange_base_url ( 338 const struct GNUNET_CONFIGURATION_Handle *cfg) 339 { 340 char *exchange_url; 341 342 if (GNUNET_OK != 343 GNUNET_CONFIGURATION_get_value_string (cfg, 344 "exchange", 345 "BASE_URL", 346 &exchange_url)) 347 { 348 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, 349 "exchange", 350 "BASE_URL"); 351 return NULL; 352 } 353 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 get_exchange_master_priv_file ( 366 const struct GNUNET_CONFIGURATION_Handle *cfg) 367 { 368 char *fn; 369 370 if (GNUNET_OK != 371 GNUNET_CONFIGURATION_get_value_filename (cfg, 372 "exchange-offline", 373 "MASTER_PRIV_FILE", 374 &fn)) 375 { 376 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, 377 "exchange-offline", 378 "MASTER_PRIV_FILE"); 379 return NULL; 380 } 381 return fn; 382 } 383 384 385 struct TALER_TESTING_Command 386 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 ges = GNUNET_new (struct GetExchangeState); 396 ges->exchange_url = get_exchange_base_url (cfg); 397 ges->last_keys_ref = last_keys_ref; 398 if (load_private_key) 399 ges->master_priv_file = get_exchange_master_priv_file (cfg); 400 ges->wait_for_keys = wait_for_keys; 401 { 402 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 return cmd; 412 } 413 }