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