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 "platform.h"
25 : #include "taler_json_lib.h"
26 : #include <gnunet/gnunet_curl_lib.h>
27 : #include "taler_testing_lib.h"
28 : #include "taler_signatures.h"
29 : #include "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 6 : get_cb (void *cls,
96 : const struct TALER_EXCHANGE_ContractGetResponse *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_contract_get (
217 : TALER_TESTING_interpreter_get_context (is),
218 : exchange_url,
219 : contract_priv,
220 : &get_cb,
221 : ds);
222 6 : if (NULL == ds->dh)
223 : {
224 0 : GNUNET_break (0);
225 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
226 : "Could not GET contract\n");
227 0 : TALER_TESTING_interpreter_fail (is);
228 0 : 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 6 : get_cleanup (void *cls,
242 : const struct TALER_TESTING_Command *cmd)
243 : {
244 6 : struct ContractGetState *ds = cls;
245 :
246 6 : if (NULL != ds->dh)
247 : {
248 0 : TALER_TESTING_command_incomplete (ds->is,
249 : cmd->label);
250 0 : TALER_EXCHANGE_contract_get_cancel (ds->dh);
251 0 : ds->dh = NULL;
252 : }
253 6 : json_decref (ds->contract_terms);
254 6 : GNUNET_free (ds);
255 6 : }
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 29 : get_traits (void *cls,
269 : const void **ret,
270 : const char *trait,
271 : unsigned int index)
272 : {
273 29 : struct ContractGetState *ds = cls;
274 : struct TALER_TESTING_Trait traits[] = {
275 29 : TALER_TESTING_make_trait_merge_priv (&ds->merge_priv),
276 29 : TALER_TESTING_make_trait_purse_pub (&ds->purse_pub),
277 29 : TALER_TESTING_make_trait_contract_terms (ds->contract_terms),
278 29 : TALER_TESTING_trait_end ()
279 : };
280 :
281 : /* skip 'merge_priv' if we are in 'merge' mode */
282 29 : 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 6 : 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 6 : ds = GNUNET_new (struct ContractGetState);
299 6 : ds->expected_response_code = expected_http_status;
300 6 : ds->contract_ref = contract_ref;
301 6 : ds->merge = for_merge;
302 : {
303 6 : 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 6 : return cmd;
312 : }
313 : }
314 :
315 :
316 : /* end of testing_api_cmd_contract_get.c */
|