Line data Source code
1 : /*
2 : This file is part of TALER
3 : (C) 2023 Taler Systems SA
4 :
5 : TALER is free software; you can redistribute it and/or modify
6 : it under the terms of the GNU General Public License as
7 : published by the Free Software Foundation; either version 3, or
8 : (at your 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
13 : GNU 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_get_exchange.c
21 : * @brief Command to get an exchange handle
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 :
29 :
30 : /**
31 : * State for a "get exchange" CMD.
32 : */
33 : struct GetExchangeState
34 : {
35 :
36 : /**
37 : * Master private key of the exchange.
38 : */
39 : struct TALER_MasterPrivateKeyP master_priv;
40 :
41 : /**
42 : * Our interpreter state.
43 : */
44 : struct TALER_TESTING_Interpreter *is;
45 :
46 : /**
47 : * Exchange handle we produced.
48 : */
49 : struct TALER_EXCHANGE_GetKeysHandle *exchange;
50 :
51 : /**
52 : * Keys of the exchange.
53 : */
54 : struct TALER_EXCHANGE_Keys *keys;
55 :
56 : /**
57 : * URL of the exchange.
58 : */
59 : char *exchange_url;
60 :
61 : /**
62 : * Filename of the master private key of the exchange.
63 : */
64 : char *master_priv_file;
65 :
66 : /**
67 : * Label of a command to use to obtain existing
68 : * keys.
69 : */
70 : const char *last_keys_ref;
71 :
72 : /**
73 : * Last denomination date we received when doing this request.
74 : */
75 : struct GNUNET_TIME_Timestamp my_denom_date;
76 :
77 : /**
78 : * Are we waiting for /keys before continuing?
79 : */
80 : bool wait_for_keys;
81 : };
82 :
83 :
84 : /**
85 : * Function called with information about who is auditing
86 : * a particular exchange and what keys the exchange is using.
87 : *
88 : * @param cls closure
89 : * @param kr response from /keys
90 : * @param[in] keys the keys of the exchange
91 : */
92 : static void
93 28 : cert_cb (void *cls,
94 : const struct TALER_EXCHANGE_KeysResponse *kr,
95 : struct TALER_EXCHANGE_Keys *keys)
96 : {
97 28 : struct GetExchangeState *ges = cls;
98 28 : const struct TALER_EXCHANGE_HttpResponse *hr = &kr->hr;
99 28 : struct TALER_TESTING_Interpreter *is = ges->is;
100 :
101 28 : ges->exchange = NULL;
102 28 : if (NULL != ges->keys)
103 0 : TALER_EXCHANGE_keys_decref (ges->keys);
104 28 : ges->keys = keys;
105 28 : switch (hr->http_status)
106 : {
107 28 : case MHD_HTTP_OK:
108 28 : if (ges->wait_for_keys)
109 : {
110 28 : ges->wait_for_keys = false;
111 28 : TALER_TESTING_interpreter_next (is);
112 28 : return;
113 : }
114 0 : ges->my_denom_date = kr->details.ok.keys->last_denom_issue_date;
115 0 : return;
116 0 : default:
117 0 : GNUNET_break (0);
118 0 : GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
119 : "/keys responded with HTTP status %u\n",
120 : hr->http_status);
121 0 : if (ges->wait_for_keys)
122 : {
123 0 : ges->wait_for_keys = false;
124 0 : TALER_TESTING_interpreter_fail (is);
125 0 : return;
126 : }
127 0 : return;
128 : }
129 : }
130 :
131 :
132 : /**
133 : * Run the "get_exchange" command.
134 : *
135 : * @param cls closure.
136 : * @param cmd the command currently being executed.
137 : * @param is the interpreter state.
138 : */
139 : static void
140 28 : get_exchange_run (void *cls,
141 : const struct TALER_TESTING_Command *cmd,
142 : struct TALER_TESTING_Interpreter *is)
143 : {
144 28 : struct GetExchangeState *ges = cls;
145 28 : struct TALER_EXCHANGE_Keys *xkeys = NULL;
146 :
147 : (void) cmd;
148 28 : if (NULL == ges->exchange_url)
149 : {
150 0 : GNUNET_break (0);
151 0 : TALER_TESTING_interpreter_fail (is);
152 0 : return;
153 : }
154 28 : if (NULL != ges->last_keys_ref)
155 : {
156 : const struct TALER_TESTING_Command *state_cmd;
157 : struct TALER_EXCHANGE_Keys *old_keys;
158 : const char *exchange_url;
159 : json_t *s_keys;
160 :
161 : state_cmd
162 8 : = TALER_TESTING_interpreter_lookup_command (is,
163 : ges->last_keys_ref);
164 8 : if (NULL == state_cmd)
165 : {
166 : /* Command providing serialized keys not found. */
167 0 : GNUNET_break (0);
168 0 : TALER_TESTING_interpreter_fail (is);
169 0 : return;
170 : }
171 8 : if (GNUNET_OK !=
172 8 : TALER_TESTING_get_trait_keys (state_cmd,
173 : &old_keys))
174 : {
175 0 : GNUNET_break (0);
176 0 : TALER_TESTING_interpreter_fail (is);
177 0 : return;
178 : }
179 8 : if (NULL == old_keys)
180 : {
181 0 : GNUNET_break (0);
182 0 : TALER_TESTING_interpreter_fail (is);
183 0 : return;
184 : }
185 8 : if (GNUNET_OK !=
186 8 : TALER_TESTING_get_trait_exchange_url (state_cmd,
187 : &exchange_url))
188 : {
189 0 : GNUNET_break (0);
190 0 : TALER_TESTING_interpreter_fail (is);
191 0 : return;
192 : }
193 8 : if (0 != strcmp (exchange_url,
194 8 : ges->exchange_url))
195 : {
196 0 : GNUNET_break (0);
197 0 : TALER_TESTING_interpreter_fail (is);
198 0 : return;
199 : }
200 8 : s_keys = TALER_EXCHANGE_keys_to_json (old_keys);
201 8 : if (NULL == s_keys)
202 : {
203 0 : GNUNET_break (0);
204 0 : TALER_TESTING_interpreter_fail (is);
205 0 : return;
206 : }
207 8 : xkeys = TALER_EXCHANGE_keys_from_json (s_keys);
208 8 : if (NULL == xkeys)
209 : {
210 0 : GNUNET_break (0);
211 0 : json_dumpf (s_keys,
212 : stderr,
213 : JSON_INDENT (2));
214 0 : json_decref (s_keys);
215 0 : TALER_TESTING_interpreter_fail (is);
216 0 : return;
217 : }
218 8 : json_decref (s_keys);
219 : }
220 28 : if (NULL != ges->master_priv_file)
221 : {
222 28 : if (GNUNET_SYSERR ==
223 28 : GNUNET_CRYPTO_eddsa_key_from_file (ges->master_priv_file,
224 : GNUNET_YES,
225 : &ges->master_priv.eddsa_priv))
226 : {
227 0 : GNUNET_break (0);
228 0 : TALER_EXCHANGE_keys_decref (xkeys);
229 0 : TALER_TESTING_interpreter_fail (is);
230 0 : return;
231 : }
232 : }
233 28 : ges->is = is;
234 : ges->exchange
235 28 : = TALER_EXCHANGE_get_keys (TALER_TESTING_interpreter_get_context (is),
236 28 : ges->exchange_url,
237 : xkeys,
238 : &cert_cb,
239 : ges);
240 28 : TALER_EXCHANGE_keys_decref (xkeys);
241 28 : if (NULL == ges->exchange)
242 : {
243 0 : GNUNET_break (0);
244 0 : TALER_TESTING_interpreter_fail (is);
245 0 : return;
246 : }
247 28 : if (! ges->wait_for_keys)
248 0 : TALER_TESTING_interpreter_next (is);
249 : }
250 :
251 :
252 : /**
253 : * Cleanup the state.
254 : *
255 : * @param cls closure.
256 : * @param cmd the command which is being cleaned up.
257 : */
258 : static void
259 28 : get_exchange_cleanup (void *cls,
260 : const struct TALER_TESTING_Command *cmd)
261 : {
262 28 : struct GetExchangeState *ges = cls;
263 :
264 28 : if (NULL != ges->exchange)
265 : {
266 0 : TALER_EXCHANGE_get_keys_cancel (ges->exchange);
267 0 : ges->exchange = NULL;
268 : }
269 28 : TALER_EXCHANGE_keys_decref (ges->keys);
270 28 : ges->keys = NULL;
271 28 : GNUNET_free (ges->master_priv_file);
272 28 : GNUNET_free (ges->exchange_url);
273 28 : GNUNET_free (ges);
274 28 : }
275 :
276 :
277 : /**
278 : * Offer internal data to a "get_exchange" CMD state to other commands.
279 : *
280 : * @param cls closure
281 : * @param[out] ret result (could be anything)
282 : * @param trait name of the trait
283 : * @param index index number of the object to offer.
284 : * @return #GNUNET_OK on success
285 : */
286 : static enum GNUNET_GenericReturnValue
287 1104 : get_exchange_traits (void *cls,
288 : const void **ret,
289 : const char *trait,
290 : unsigned int index)
291 : {
292 1104 : struct GetExchangeState *ges = cls;
293 1104 : unsigned int off = (NULL == ges->master_priv_file) ? 1 : 0;
294 :
295 1104 : if (NULL != ges->keys)
296 : {
297 : struct TALER_TESTING_Trait traits[] = {
298 1104 : TALER_TESTING_make_trait_master_priv (&ges->master_priv),
299 1104 : TALER_TESTING_make_trait_master_pub (&ges->keys->master_pub),
300 1104 : TALER_TESTING_make_trait_keys (ges->keys),
301 1104 : TALER_TESTING_make_trait_exchange_url (ges->exchange_url),
302 1104 : TALER_TESTING_make_trait_timestamp (0,
303 1104 : &ges->my_denom_date),
304 1104 : TALER_TESTING_trait_end ()
305 : };
306 :
307 1104 : return TALER_TESTING_get_trait (&traits[off],
308 : ret,
309 : trait,
310 : index);
311 : }
312 : else
313 : {
314 : struct TALER_TESTING_Trait traits[] = {
315 0 : TALER_TESTING_make_trait_master_priv (&ges->master_priv),
316 0 : TALER_TESTING_make_trait_exchange_url (ges->exchange_url),
317 0 : TALER_TESTING_make_trait_timestamp (0,
318 0 : &ges->my_denom_date),
319 0 : TALER_TESTING_trait_end ()
320 : };
321 :
322 0 : return TALER_TESTING_get_trait (&traits[off],
323 : ret,
324 : trait,
325 : index);
326 : }
327 : }
328 :
329 :
330 : /**
331 : * Get the base URL of the exchange from @a cfg.
332 : *
333 : * @param cfg configuration to evaluate
334 : * @return base URL of the exchange according to @a cfg
335 : */
336 : static char *
337 28 : get_exchange_base_url (
338 : const struct GNUNET_CONFIGURATION_Handle *cfg)
339 : {
340 : char *exchange_url;
341 :
342 28 : if (GNUNET_OK !=
343 28 : GNUNET_CONFIGURATION_get_value_string (cfg,
344 : "exchange",
345 : "BASE_URL",
346 : &exchange_url))
347 : {
348 0 : GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
349 : "exchange",
350 : "BASE_URL");
351 0 : return NULL;
352 : }
353 28 : return exchange_url;
354 : }
355 :
356 :
357 : /**
358 : * Get the file name of the master private key file of the exchange from @a
359 : * cfg.
360 : *
361 : * @param cfg configuration to evaluate
362 : * @return base URL of the exchange according to @a cfg
363 : */
364 : static char *
365 28 : get_exchange_master_priv_file (
366 : const struct GNUNET_CONFIGURATION_Handle *cfg)
367 : {
368 : char *fn;
369 :
370 28 : if (GNUNET_OK !=
371 28 : GNUNET_CONFIGURATION_get_value_filename (cfg,
372 : "exchange-offline",
373 : "MASTER_PRIV_FILE",
374 : &fn))
375 : {
376 0 : GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
377 : "exchange-offline",
378 : "MASTER_PRIV_FILE");
379 0 : return NULL;
380 : }
381 28 : return fn;
382 : }
383 :
384 :
385 : struct TALER_TESTING_Command
386 28 : TALER_TESTING_cmd_get_exchange (
387 : const char *label,
388 : const struct GNUNET_CONFIGURATION_Handle *cfg,
389 : const char *last_keys_ref,
390 : bool wait_for_keys,
391 : bool load_private_key)
392 : {
393 : struct GetExchangeState *ges;
394 :
395 28 : ges = GNUNET_new (struct GetExchangeState);
396 28 : ges->exchange_url = get_exchange_base_url (cfg);
397 28 : ges->last_keys_ref = last_keys_ref;
398 28 : if (load_private_key)
399 28 : ges->master_priv_file = get_exchange_master_priv_file (cfg);
400 28 : ges->wait_for_keys = wait_for_keys;
401 : {
402 28 : struct TALER_TESTING_Command cmd = {
403 : .cls = ges,
404 : .label = label,
405 : .run = &get_exchange_run,
406 : .cleanup = &get_exchange_cleanup,
407 : .traits = &get_exchange_traits,
408 : .name = "exchange"
409 : };
410 :
411 28 : return cmd;
412 : }
413 : }
|