testing_api_cmd_contract_get.c (8176B)
1 /* 2 This file is part of TALER 3 Copyright (C) 2022 Taler Systems SA 4 5 TALER is free software; you can redistribute it and/or modify it 6 under the terms of the GNU General Public License as published by 7 the Free Software Foundation; either version 3, or (at your 8 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 GNU 13 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_contract_get.c 21 * @brief command for testing GET /contracts/$CPUB 22 * @author Christian Grothoff 23 */ 24 #include "taler/taler_json_lib.h" 25 #include <gnunet/gnunet_curl_lib.h> 26 #include "taler/taler_testing_lib.h" 27 #include "taler/taler_signatures.h" 28 29 30 /** 31 * State for a "contract get" CMD. 32 */ 33 struct ContractGetState 34 { 35 36 /** 37 * JSON string describing the resulting contract. 38 */ 39 json_t *contract_terms; 40 41 /** 42 * Private key to decrypt the contract. 43 */ 44 struct TALER_ContractDiffiePrivateP contract_priv; 45 46 /** 47 * Set to the returned merge key. 48 */ 49 struct TALER_PurseMergePrivateKeyP merge_priv; 50 51 /** 52 * Public key of the purse. 53 */ 54 struct TALER_PurseContractPublicKeyP purse_pub; 55 56 /** 57 * Reference to the command that uploaded the contract. 58 */ 59 const char *contract_ref; 60 61 /** 62 * ContractGet handle while operation is running. 63 */ 64 struct TALER_EXCHANGE_GetContractsHandle *dh; 65 66 /** 67 * Interpreter state. 68 */ 69 struct TALER_TESTING_Interpreter *is; 70 71 /** 72 * Expected HTTP response code. 73 */ 74 unsigned int expected_response_code; 75 76 /** 77 * True if this is for a 'merge' operation, 78 * 'false' if this is for a 'deposit' operation. 79 */ 80 bool merge; 81 82 }; 83 84 85 /** 86 * Callback to analyze the /contracts/$CPUB response, just used to check if 87 * the response code is acceptable. 88 * 89 * @param cls closure. 90 * @param dr get response details 91 */ 92 static void 93 get_cb (void *cls, 94 const struct TALER_EXCHANGE_GetContractsResponse *dr) 95 { 96 struct ContractGetState *ds = cls; 97 const struct TALER_TESTING_Command *ref; 98 99 ds->dh = NULL; 100 if (ds->expected_response_code != dr->hr.http_status) 101 { 102 TALER_TESTING_unexpected_status (ds->is, 103 dr->hr.http_status, 104 ds->expected_response_code); 105 return; 106 } 107 ref = TALER_TESTING_interpreter_lookup_command (ds->is, 108 ds->contract_ref); 109 GNUNET_assert (NULL != ref); 110 if (MHD_HTTP_OK == dr->hr.http_status) 111 { 112 const struct TALER_PurseMergePrivateKeyP *mp; 113 const json_t *ct; 114 115 ds->purse_pub = dr->details.ok.purse_pub; 116 if (ds->merge) 117 { 118 if (GNUNET_OK != 119 TALER_TESTING_get_trait_merge_priv (ref, 120 &mp)) 121 { 122 GNUNET_break (0); 123 TALER_TESTING_interpreter_fail (ds->is); 124 return; 125 } 126 ds->contract_terms = 127 TALER_CRYPTO_contract_decrypt_for_merge ( 128 &ds->contract_priv, 129 &ds->purse_pub, 130 dr->details.ok.econtract, 131 dr->details.ok.econtract_size, 132 &ds->merge_priv); 133 if (0 != 134 GNUNET_memcmp (mp, 135 &ds->merge_priv)) 136 { 137 GNUNET_break (0); 138 TALER_TESTING_interpreter_fail (ds->is); 139 return; 140 } 141 } 142 else 143 { 144 ds->contract_terms = 145 TALER_CRYPTO_contract_decrypt_for_deposit ( 146 &ds->contract_priv, 147 dr->details.ok.econtract, 148 dr->details.ok.econtract_size); 149 } 150 if (NULL == ds->contract_terms) 151 { 152 GNUNET_break (0); 153 TALER_TESTING_interpreter_fail (ds->is); 154 return; 155 } 156 if (GNUNET_OK != 157 TALER_TESTING_get_trait_contract_terms (ref, 158 &ct)) 159 { 160 GNUNET_break (0); 161 TALER_TESTING_interpreter_fail (ds->is); 162 return; 163 } 164 if (1 != /* 1: equal, 0: not equal */ 165 json_equal (ct, 166 ds->contract_terms)) 167 { 168 GNUNET_break (0); 169 TALER_TESTING_interpreter_fail (ds->is); 170 return; 171 } 172 } 173 TALER_TESTING_interpreter_next (ds->is); 174 } 175 176 177 /** 178 * Run the command. 179 * 180 * @param cls closure. 181 * @param cmd the command to execute. 182 * @param is the interpreter state. 183 */ 184 static void 185 get_run (void *cls, 186 const struct TALER_TESTING_Command *cmd, 187 struct TALER_TESTING_Interpreter *is) 188 { 189 struct ContractGetState *ds = cls; 190 const struct TALER_ContractDiffiePrivateP *contract_priv; 191 const struct TALER_TESTING_Command *ref; 192 const char *exchange_url; 193 194 (void) cmd; 195 ds->is = is; 196 exchange_url = TALER_TESTING_get_exchange_url (is); 197 if (NULL == exchange_url) 198 { 199 GNUNET_break (0); 200 return; 201 } 202 ref = TALER_TESTING_interpreter_lookup_command (ds->is, 203 ds->contract_ref); 204 GNUNET_assert (NULL != ref); 205 if (GNUNET_OK != 206 TALER_TESTING_get_trait_contract_priv (ref, 207 &contract_priv)) 208 { 209 GNUNET_break (0); 210 TALER_TESTING_interpreter_fail (ds->is); 211 return; 212 } 213 ds->contract_priv = *contract_priv; 214 ds->dh = TALER_EXCHANGE_get_contracts_create ( 215 TALER_TESTING_interpreter_get_context (is), 216 exchange_url, 217 contract_priv); 218 if (NULL == ds->dh) 219 { 220 GNUNET_break (0); 221 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 222 "Could not GET contract\n"); 223 TALER_TESTING_interpreter_fail (is); 224 return; 225 } 226 if (TALER_EC_NONE != 227 TALER_EXCHANGE_get_contracts_start (ds->dh, 228 &get_cb, 229 ds)) 230 { 231 GNUNET_break (0); 232 TALER_EXCHANGE_get_contracts_cancel (ds->dh); 233 ds->dh = NULL; 234 TALER_TESTING_interpreter_fail (is); 235 return; 236 } 237 } 238 239 240 /** 241 * Free the state of a "get" CMD, and possibly cancel a 242 * pending operation thereof. 243 * 244 * @param cls closure, must be a `struct ContractGetState`. 245 * @param cmd the command which is being cleaned up. 246 */ 247 static void 248 get_cleanup (void *cls, 249 const struct TALER_TESTING_Command *cmd) 250 { 251 struct ContractGetState *ds = cls; 252 253 if (NULL != ds->dh) 254 { 255 TALER_TESTING_command_incomplete (ds->is, 256 cmd->label); 257 TALER_EXCHANGE_get_contracts_cancel (ds->dh); 258 ds->dh = NULL; 259 } 260 json_decref (ds->contract_terms); 261 GNUNET_free (ds); 262 } 263 264 265 /** 266 * Offer internal data from a "get" CMD, to other commands. 267 * 268 * @param cls closure. 269 * @param[out] ret result. 270 * @param trait name of the trait. 271 * @param index index number of the object to offer. 272 * @return #GNUNET_OK on success. 273 */ 274 static enum GNUNET_GenericReturnValue 275 get_traits (void *cls, 276 const void **ret, 277 const char *trait, 278 unsigned int index) 279 { 280 struct ContractGetState *ds = cls; 281 struct TALER_TESTING_Trait traits[] = { 282 TALER_TESTING_make_trait_merge_priv (&ds->merge_priv), 283 TALER_TESTING_make_trait_purse_pub (&ds->purse_pub), 284 TALER_TESTING_make_trait_contract_terms (ds->contract_terms), 285 TALER_TESTING_trait_end () 286 }; 287 288 /* skip 'merge_priv' if we are in 'merge' mode */ 289 return TALER_TESTING_get_trait (&traits[ds->merge ? 0 : 1], 290 ret, 291 trait, 292 index); 293 } 294 295 296 struct TALER_TESTING_Command 297 TALER_TESTING_cmd_contract_get ( 298 const char *label, 299 unsigned int expected_http_status, 300 bool for_merge, 301 const char *contract_ref) 302 { 303 struct ContractGetState *ds; 304 305 ds = GNUNET_new (struct ContractGetState); 306 ds->expected_response_code = expected_http_status; 307 ds->contract_ref = contract_ref; 308 ds->merge = for_merge; 309 { 310 struct TALER_TESTING_Command cmd = { 311 .cls = ds, 312 .label = label, 313 .run = &get_run, 314 .cleanup = &get_cleanup, 315 .traits = &get_traits 316 }; 317 318 return cmd; 319 } 320 } 321 322 323 /* end of testing_api_cmd_contract_get.c */