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/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_GetContractsHandle *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 6 : get_cb (void *cls,
96 : const struct TALER_EXCHANGE_GetContractsResponse *dr)
97 : {
98 6 : struct ContractGetState *ds = cls;
99 : const struct TALER_TESTING_Command *ref;
100 :
101 6 : ds->dh = NULL;
102 6 : if (ds->expected_response_code != dr->hr.http_status)
103 : {
104 0 : TALER_TESTING_unexpected_status (ds->is,
105 : dr->hr.http_status,
106 : ds->expected_response_code);
107 0 : return;
108 : }
109 6 : ref = TALER_TESTING_interpreter_lookup_command (ds->is,
110 : ds->contract_ref);
111 6 : GNUNET_assert (NULL != ref);
112 6 : if (MHD_HTTP_OK == dr->hr.http_status)
113 : {
114 : const struct TALER_PurseMergePrivateKeyP *mp;
115 : const json_t *ct;
116 :
117 6 : ds->purse_pub = dr->details.ok.purse_pub;
118 6 : if (ds->merge)
119 : {
120 3 : if (GNUNET_OK !=
121 3 : TALER_TESTING_get_trait_merge_priv (ref,
122 : &mp))
123 : {
124 0 : GNUNET_break (0);
125 0 : TALER_TESTING_interpreter_fail (ds->is);
126 0 : return;
127 : }
128 3 : ds->contract_terms =
129 3 : TALER_CRYPTO_contract_decrypt_for_merge (
130 3 : &ds->contract_priv,
131 3 : &ds->purse_pub,
132 3 : dr->details.ok.econtract,
133 3 : dr->details.ok.econtract_size,
134 : &ds->merge_priv);
135 3 : if (0 !=
136 3 : GNUNET_memcmp (mp,
137 : &ds->merge_priv))
138 : {
139 0 : GNUNET_break (0);
140 0 : TALER_TESTING_interpreter_fail (ds->is);
141 0 : return;
142 : }
143 : }
144 : else
145 : {
146 3 : ds->contract_terms =
147 3 : TALER_CRYPTO_contract_decrypt_for_deposit (
148 3 : &ds->contract_priv,
149 3 : dr->details.ok.econtract,
150 3 : dr->details.ok.econtract_size);
151 : }
152 6 : if (NULL == ds->contract_terms)
153 : {
154 0 : GNUNET_break (0);
155 0 : TALER_TESTING_interpreter_fail (ds->is);
156 0 : return;
157 : }
158 6 : if (GNUNET_OK !=
159 6 : TALER_TESTING_get_trait_contract_terms (ref,
160 : &ct))
161 : {
162 0 : GNUNET_break (0);
163 0 : TALER_TESTING_interpreter_fail (ds->is);
164 0 : return;
165 : }
166 6 : if (1 != /* 1: equal, 0: not equal */
167 6 : json_equal (ct,
168 6 : ds->contract_terms))
169 : {
170 0 : GNUNET_break (0);
171 0 : TALER_TESTING_interpreter_fail (ds->is);
172 0 : return;
173 : }
174 : }
175 6 : 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 6 : get_run (void *cls,
188 : const struct TALER_TESTING_Command *cmd,
189 : struct TALER_TESTING_Interpreter *is)
190 : {
191 6 : 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 6 : ds->is = is;
198 6 : exchange_url = TALER_TESTING_get_exchange_url (is);
199 6 : if (NULL == exchange_url)
200 : {
201 0 : GNUNET_break (0);
202 0 : return;
203 : }
204 6 : ref = TALER_TESTING_interpreter_lookup_command (ds->is,
205 : ds->contract_ref);
206 6 : GNUNET_assert (NULL != ref);
207 6 : if (GNUNET_OK !=
208 6 : TALER_TESTING_get_trait_contract_priv (ref,
209 : &contract_priv))
210 : {
211 0 : GNUNET_break (0);
212 0 : TALER_TESTING_interpreter_fail (ds->is);
213 0 : return;
214 : }
215 6 : ds->contract_priv = *contract_priv;
216 6 : ds->dh = TALER_EXCHANGE_get_contracts_create (
217 : TALER_TESTING_interpreter_get_context (is),
218 : exchange_url,
219 : contract_priv);
220 6 : if (NULL == ds->dh)
221 : {
222 0 : GNUNET_break (0);
223 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
224 : "Could not GET contract\n");
225 0 : TALER_TESTING_interpreter_fail (is);
226 0 : return;
227 : }
228 6 : if (TALER_EC_NONE !=
229 6 : TALER_EXCHANGE_get_contracts_start (ds->dh,
230 : &get_cb,
231 : ds))
232 : {
233 0 : GNUNET_break (0);
234 0 : TALER_EXCHANGE_get_contracts_cancel (ds->dh);
235 0 : ds->dh = NULL;
236 0 : TALER_TESTING_interpreter_fail (is);
237 0 : return;
238 : }
239 : }
240 :
241 :
242 : /**
243 : * Free the state of a "get" CMD, and possibly cancel a
244 : * pending operation thereof.
245 : *
246 : * @param cls closure, must be a `struct ContractGetState`.
247 : * @param cmd the command which is being cleaned up.
248 : */
249 : static void
250 6 : get_cleanup (void *cls,
251 : const struct TALER_TESTING_Command *cmd)
252 : {
253 6 : struct ContractGetState *ds = cls;
254 :
255 6 : if (NULL != ds->dh)
256 : {
257 0 : TALER_TESTING_command_incomplete (ds->is,
258 : cmd->label);
259 0 : TALER_EXCHANGE_get_contracts_cancel (ds->dh);
260 0 : ds->dh = NULL;
261 : }
262 6 : json_decref (ds->contract_terms);
263 6 : GNUNET_free (ds);
264 6 : }
265 :
266 :
267 : /**
268 : * Offer internal data from a "get" CMD, to other commands.
269 : *
270 : * @param cls closure.
271 : * @param[out] ret result.
272 : * @param trait name of the trait.
273 : * @param index index number of the object to offer.
274 : * @return #GNUNET_OK on success.
275 : */
276 : static enum GNUNET_GenericReturnValue
277 29 : get_traits (void *cls,
278 : const void **ret,
279 : const char *trait,
280 : unsigned int index)
281 : {
282 29 : struct ContractGetState *ds = cls;
283 : struct TALER_TESTING_Trait traits[] = {
284 29 : TALER_TESTING_make_trait_merge_priv (&ds->merge_priv),
285 29 : TALER_TESTING_make_trait_purse_pub (&ds->purse_pub),
286 29 : TALER_TESTING_make_trait_contract_terms (ds->contract_terms),
287 29 : TALER_TESTING_trait_end ()
288 : };
289 :
290 : /* skip 'merge_priv' if we are in 'merge' mode */
291 29 : return TALER_TESTING_get_trait (&traits[ds->merge ? 0 : 1],
292 : ret,
293 : trait,
294 : index);
295 : }
296 :
297 :
298 : struct TALER_TESTING_Command
299 6 : TALER_TESTING_cmd_contract_get (
300 : const char *label,
301 : unsigned int expected_http_status,
302 : bool for_merge,
303 : const char *contract_ref)
304 : {
305 : struct ContractGetState *ds;
306 :
307 6 : ds = GNUNET_new (struct ContractGetState);
308 6 : ds->expected_response_code = expected_http_status;
309 6 : ds->contract_ref = contract_ref;
310 6 : ds->merge = for_merge;
311 : {
312 6 : struct TALER_TESTING_Command cmd = {
313 : .cls = ds,
314 : .label = label,
315 : .run = &get_run,
316 : .cleanup = &get_cleanup,
317 : .traits = &get_traits
318 : };
319 :
320 6 : return cmd;
321 : }
322 : }
323 :
324 :
325 : /* end of testing_api_cmd_contract_get.c */
|