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