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 : #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 6 : get_cb (void *cls,
94 : const struct TALER_EXCHANGE_GetContractsResponse *dr)
95 : {
96 6 : struct ContractGetState *ds = cls;
97 : const struct TALER_TESTING_Command *ref;
98 :
99 6 : ds->dh = NULL;
100 6 : if (ds->expected_response_code != dr->hr.http_status)
101 : {
102 0 : TALER_TESTING_unexpected_status (ds->is,
103 : dr->hr.http_status,
104 : ds->expected_response_code);
105 0 : return;
106 : }
107 6 : ref = TALER_TESTING_interpreter_lookup_command (ds->is,
108 : ds->contract_ref);
109 6 : GNUNET_assert (NULL != ref);
110 6 : if (MHD_HTTP_OK == dr->hr.http_status)
111 : {
112 : const struct TALER_PurseMergePrivateKeyP *mp;
113 : const json_t *ct;
114 :
115 6 : ds->purse_pub = dr->details.ok.purse_pub;
116 6 : if (ds->merge)
117 : {
118 3 : if (GNUNET_OK !=
119 3 : TALER_TESTING_get_trait_merge_priv (ref,
120 : &mp))
121 : {
122 0 : GNUNET_break (0);
123 0 : TALER_TESTING_interpreter_fail (ds->is);
124 0 : return;
125 : }
126 3 : ds->contract_terms =
127 3 : TALER_CRYPTO_contract_decrypt_for_merge (
128 3 : &ds->contract_priv,
129 3 : &ds->purse_pub,
130 3 : dr->details.ok.econtract,
131 3 : dr->details.ok.econtract_size,
132 : &ds->merge_priv);
133 3 : if (0 !=
134 3 : GNUNET_memcmp (mp,
135 : &ds->merge_priv))
136 : {
137 0 : GNUNET_break (0);
138 0 : TALER_TESTING_interpreter_fail (ds->is);
139 0 : return;
140 : }
141 : }
142 : else
143 : {
144 3 : ds->contract_terms =
145 3 : TALER_CRYPTO_contract_decrypt_for_deposit (
146 3 : &ds->contract_priv,
147 3 : dr->details.ok.econtract,
148 3 : dr->details.ok.econtract_size);
149 : }
150 6 : if (NULL == ds->contract_terms)
151 : {
152 0 : GNUNET_break (0);
153 0 : TALER_TESTING_interpreter_fail (ds->is);
154 0 : return;
155 : }
156 6 : if (GNUNET_OK !=
157 6 : TALER_TESTING_get_trait_contract_terms (ref,
158 : &ct))
159 : {
160 0 : GNUNET_break (0);
161 0 : TALER_TESTING_interpreter_fail (ds->is);
162 0 : return;
163 : }
164 6 : if (1 != /* 1: equal, 0: not equal */
165 6 : json_equal (ct,
166 6 : ds->contract_terms))
167 : {
168 0 : GNUNET_break (0);
169 0 : TALER_TESTING_interpreter_fail (ds->is);
170 0 : return;
171 : }
172 : }
173 6 : 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 6 : get_run (void *cls,
186 : const struct TALER_TESTING_Command *cmd,
187 : struct TALER_TESTING_Interpreter *is)
188 : {
189 6 : 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 6 : ds->is = is;
196 6 : exchange_url = TALER_TESTING_get_exchange_url (is);
197 6 : if (NULL == exchange_url)
198 : {
199 0 : GNUNET_break (0);
200 0 : return;
201 : }
202 6 : ref = TALER_TESTING_interpreter_lookup_command (ds->is,
203 : ds->contract_ref);
204 6 : GNUNET_assert (NULL != ref);
205 6 : if (GNUNET_OK !=
206 6 : TALER_TESTING_get_trait_contract_priv (ref,
207 : &contract_priv))
208 : {
209 0 : GNUNET_break (0);
210 0 : TALER_TESTING_interpreter_fail (ds->is);
211 0 : return;
212 : }
213 6 : ds->contract_priv = *contract_priv;
214 6 : ds->dh = TALER_EXCHANGE_get_contracts_create (
215 : TALER_TESTING_interpreter_get_context (is),
216 : exchange_url,
217 : contract_priv);
218 6 : if (NULL == ds->dh)
219 : {
220 0 : GNUNET_break (0);
221 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
222 : "Could not GET contract\n");
223 0 : TALER_TESTING_interpreter_fail (is);
224 0 : return;
225 : }
226 6 : if (TALER_EC_NONE !=
227 6 : TALER_EXCHANGE_get_contracts_start (ds->dh,
228 : &get_cb,
229 : ds))
230 : {
231 0 : GNUNET_break (0);
232 0 : TALER_EXCHANGE_get_contracts_cancel (ds->dh);
233 0 : ds->dh = NULL;
234 0 : TALER_TESTING_interpreter_fail (is);
235 0 : 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 6 : get_cleanup (void *cls,
249 : const struct TALER_TESTING_Command *cmd)
250 : {
251 6 : struct ContractGetState *ds = cls;
252 :
253 6 : if (NULL != ds->dh)
254 : {
255 0 : TALER_TESTING_command_incomplete (ds->is,
256 : cmd->label);
257 0 : TALER_EXCHANGE_get_contracts_cancel (ds->dh);
258 0 : ds->dh = NULL;
259 : }
260 6 : json_decref (ds->contract_terms);
261 6 : GNUNET_free (ds);
262 6 : }
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 29 : get_traits (void *cls,
276 : const void **ret,
277 : const char *trait,
278 : unsigned int index)
279 : {
280 29 : struct ContractGetState *ds = cls;
281 : struct TALER_TESTING_Trait traits[] = {
282 29 : TALER_TESTING_make_trait_merge_priv (&ds->merge_priv),
283 29 : TALER_TESTING_make_trait_purse_pub (&ds->purse_pub),
284 29 : TALER_TESTING_make_trait_contract_terms (ds->contract_terms),
285 29 : TALER_TESTING_trait_end ()
286 : };
287 :
288 : /* skip 'merge_priv' if we are in 'merge' mode */
289 29 : 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 6 : 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 6 : ds = GNUNET_new (struct ContractGetState);
306 6 : ds->expected_response_code = expected_http_status;
307 6 : ds->contract_ref = contract_ref;
308 6 : ds->merge = for_merge;
309 : {
310 6 : 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 6 : return cmd;
319 : }
320 : }
321 :
322 :
323 : /* end of testing_api_cmd_contract_get.c */
|