Line data Source code
1 : /*
2 : This file is part of TALER
3 : Copyright (C) 2014-2022 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_recoup_refresh.c
21 : * @brief Implement the /recoup-refresh test command.
22 : * @author Marcello Stanisci
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 "pay back" CMD.
32 : */
33 : struct RecoupRefreshState
34 : {
35 : /**
36 : * Expected HTTP status code.
37 : */
38 : unsigned int expected_response_code;
39 :
40 : /**
41 : * Command that offers a reserve private key,
42 : * plus a coin to be paid back.
43 : */
44 : const char *coin_reference;
45 :
46 : /**
47 : * Entry in the old coin's history generated by this operation.
48 : */
49 : struct TALER_EXCHANGE_CoinHistoryEntry che_old;
50 :
51 : /**
52 : * Entry in the recouped coin's history generated by this operation.
53 : */
54 : struct TALER_EXCHANGE_CoinHistoryEntry che_new;
55 :
56 : /**
57 : * Public key of the refunded coin.
58 : */
59 : struct TALER_CoinSpendPublicKeyP coin_pub_old;
60 :
61 : /**
62 : * Public key of the refunded coin.
63 : */
64 : struct TALER_CoinSpendPublicKeyP coin_pub_new;
65 :
66 : /**
67 : * Amount to be recouped.
68 : */
69 : struct TALER_Amount amount;
70 :
71 : /**
72 : * The interpreter state.
73 : */
74 : struct TALER_TESTING_Interpreter *is;
75 :
76 : /**
77 : * Handle to the ongoing operation.
78 : */
79 : struct TALER_EXCHANGE_RecoupRefreshHandle *ph;
80 :
81 : /**
82 : * NULL if coin was not refreshed, otherwise reference
83 : * to the melt operation underlying @a coin_reference.
84 : */
85 : const char *melt_reference;
86 :
87 : };
88 :
89 :
90 : /**
91 : * Check the result of the recoup_refresh request: checks whether
92 : * the HTTP response code is good, and that the coin that
93 : * was paid back belonged to the right old coin.
94 : *
95 : * @param cls closure
96 : * @param rrr response details
97 : */
98 : static void
99 0 : recoup_refresh_cb (void *cls,
100 : const struct TALER_EXCHANGE_RecoupRefreshResponse *rrr)
101 : {
102 0 : struct RecoupRefreshState *rrs = cls;
103 0 : const struct TALER_EXCHANGE_HttpResponse *hr = &rrr->hr;
104 0 : struct TALER_TESTING_Interpreter *is = rrs->is;
105 : char *cref;
106 : unsigned int idx;
107 :
108 0 : rrs->ph = NULL;
109 0 : if (rrs->expected_response_code != hr->http_status)
110 : {
111 0 : TALER_TESTING_unexpected_status (is,
112 : hr->http_status,
113 : rrs->expected_response_code);
114 0 : return;
115 : }
116 :
117 0 : if (GNUNET_OK !=
118 0 : TALER_TESTING_parse_coin_reference (
119 : rrs->coin_reference,
120 : &cref,
121 : &idx))
122 : {
123 0 : TALER_TESTING_interpreter_fail (is);
124 0 : return;
125 : }
126 : (void) idx; /* do NOT use! We ignore 'idx', must be 0 for melt! */
127 :
128 0 : GNUNET_free (cref);
129 0 : switch (hr->http_status)
130 : {
131 0 : case MHD_HTTP_OK:
132 : /* check old_coin_pub */
133 : {
134 : const struct TALER_TESTING_Command *melt_cmd;
135 : const struct TALER_CoinSpendPrivateKeyP *dirty_priv;
136 : struct TALER_CoinSpendPublicKeyP oc;
137 :
138 0 : melt_cmd = TALER_TESTING_interpreter_lookup_command (is,
139 : rrs->melt_reference);
140 0 : if (NULL == melt_cmd)
141 : {
142 0 : GNUNET_break (0);
143 0 : TALER_TESTING_interpreter_fail (is);
144 0 : return;
145 : }
146 0 : if (GNUNET_OK !=
147 0 : TALER_TESTING_get_trait_coin_priv (melt_cmd,
148 : 0,
149 : &dirty_priv))
150 : {
151 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
152 : "Coin %u not found in command %s\n",
153 : 0,
154 : rrs->melt_reference);
155 0 : GNUNET_break (0);
156 0 : TALER_TESTING_interpreter_fail (is);
157 0 : return;
158 : }
159 0 : GNUNET_CRYPTO_eddsa_key_get_public (&dirty_priv->eddsa_priv,
160 : &oc.eddsa_pub);
161 0 : if (0 != GNUNET_memcmp (&oc,
162 : &rrr->details.ok.old_coin_pub))
163 : {
164 0 : GNUNET_break (0);
165 0 : TALER_TESTING_interpreter_fail (is);
166 0 : return;
167 : }
168 : }
169 0 : break;
170 0 : case MHD_HTTP_NOT_FOUND:
171 0 : break;
172 0 : case MHD_HTTP_CONFLICT:
173 0 : break;
174 0 : default:
175 0 : GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
176 : "Unmanaged HTTP status code %u/%d.\n",
177 : hr->http_status,
178 : (int) hr->ec);
179 0 : break;
180 : }
181 0 : TALER_TESTING_interpreter_next (is);
182 : }
183 :
184 :
185 : /**
186 : * Run the command.
187 : *
188 : * @param cls closure.
189 : * @param cmd the command to execute.
190 : * @param is the interpreter state.
191 : */
192 : static void
193 0 : recoup_refresh_run (void *cls,
194 : const struct TALER_TESTING_Command *cmd,
195 : struct TALER_TESTING_Interpreter *is)
196 : {
197 0 : struct RecoupRefreshState *rrs = cls;
198 : const struct TALER_TESTING_Command *coin_cmd;
199 : const struct TALER_TESTING_Command *melt_cmd;
200 : const struct TALER_CoinSpendPrivateKeyP *coin_priv;
201 : const struct TALER_CoinSpendPrivateKeyP *coin_priv_old;
202 : const struct TALER_EXCHANGE_DenomPublicKey *denom_pub;
203 : const struct TALER_DenominationSignature *coin_sig;
204 : const struct TALER_RefreshMasterSecretP *rplanchet;
205 : const struct TALER_PlanchetMasterSecretP *planchet;
206 : const struct TALER_ExchangeBlindingValues *ewv;
207 : char *cref;
208 : unsigned int idx;
209 : struct TALER_DenominationHashP h_denom_pub;
210 :
211 0 : rrs->is = is;
212 0 : if (GNUNET_OK !=
213 0 : TALER_TESTING_parse_coin_reference (
214 : rrs->coin_reference,
215 : &cref,
216 : &idx))
217 : {
218 0 : TALER_TESTING_interpreter_fail (is);
219 0 : return;
220 : }
221 :
222 0 : coin_cmd = TALER_TESTING_interpreter_lookup_command (is,
223 : cref);
224 0 : GNUNET_free (cref);
225 0 : if (NULL == coin_cmd)
226 : {
227 0 : GNUNET_break (0);
228 0 : TALER_TESTING_interpreter_fail (is);
229 0 : return;
230 : }
231 0 : melt_cmd = TALER_TESTING_interpreter_lookup_command (is,
232 : rrs->melt_reference);
233 0 : if (NULL == melt_cmd)
234 : {
235 0 : GNUNET_break (0);
236 0 : TALER_TESTING_interpreter_fail (is);
237 0 : return;
238 : }
239 0 : if (GNUNET_OK !=
240 0 : TALER_TESTING_get_trait_coin_priv (coin_cmd,
241 : idx,
242 : &coin_priv))
243 : {
244 0 : GNUNET_break (0);
245 0 : TALER_TESTING_interpreter_fail (is);
246 0 : return;
247 : }
248 0 : if (GNUNET_OK !=
249 0 : TALER_TESTING_get_trait_coin_priv (melt_cmd,
250 : 0,
251 : &coin_priv_old))
252 : {
253 0 : GNUNET_break (0);
254 0 : TALER_TESTING_interpreter_fail (is);
255 0 : return;
256 : }
257 0 : GNUNET_CRYPTO_eddsa_key_get_public (
258 0 : &coin_priv->eddsa_priv,
259 : &rrs->coin_pub_new.eddsa_pub);
260 0 : GNUNET_CRYPTO_eddsa_key_get_public (
261 0 : &coin_priv_old->eddsa_priv,
262 : &rrs->coin_pub_old.eddsa_pub);
263 :
264 0 : if (GNUNET_OK !=
265 0 : TALER_TESTING_get_trait_exchange_blinding_values (melt_cmd,
266 : idx,
267 : &ewv))
268 : {
269 0 : GNUNET_break (0);
270 0 : TALER_TESTING_interpreter_fail (is);
271 0 : return;
272 : }
273 0 : if (GNUNET_OK !=
274 0 : TALER_TESTING_get_trait_planchet_secrets (coin_cmd,
275 : idx,
276 : &planchet))
277 : {
278 0 : GNUNET_break (0);
279 0 : TALER_TESTING_interpreter_fail (is);
280 0 : return;
281 : }
282 0 : if (GNUNET_OK !=
283 0 : TALER_TESTING_get_trait_refresh_secret (melt_cmd,
284 : &rplanchet))
285 : {
286 0 : GNUNET_break (0);
287 0 : TALER_TESTING_interpreter_fail (is);
288 0 : return;
289 : }
290 0 : if (GNUNET_OK !=
291 0 : TALER_TESTING_get_trait_denom_pub (coin_cmd,
292 : idx,
293 : &denom_pub))
294 : {
295 0 : GNUNET_break (0);
296 0 : TALER_TESTING_interpreter_fail (is);
297 0 : return;
298 : }
299 0 : if (GNUNET_OK !=
300 0 : TALER_TESTING_get_trait_denom_sig (coin_cmd,
301 : idx,
302 : &coin_sig))
303 : {
304 0 : GNUNET_break (0);
305 0 : TALER_TESTING_interpreter_fail (is);
306 0 : return;
307 : }
308 0 : GNUNET_log (GNUNET_ERROR_TYPE_INFO,
309 : "Trying to recoup_refresh denomination '%s'\n",
310 : TALER_B2S (&denom_pub->h_key));
311 : rrs->che_old.type
312 0 : = TALER_EXCHANGE_CTT_OLD_COIN_RECOUP;
313 : rrs->che_old.amount
314 0 : = rrs->amount;
315 : rrs->che_old.details.old_coin_recoup.new_coin_pub
316 0 : = rrs->coin_pub_new;
317 : rrs->che_new.type
318 0 : = TALER_EXCHANGE_CTT_RECOUP_REFRESH;
319 : rrs->che_new.amount
320 0 : = rrs->amount;
321 : rrs->che_new.details.recoup_refresh.old_coin_pub
322 0 : = rrs->coin_pub_old;
323 0 : TALER_planchet_blinding_secret_create (
324 : planchet,
325 : ewv,
326 : &rrs->che_new.details.recoup_refresh.coin_bks);
327 0 : TALER_denom_pub_hash (&denom_pub->key,
328 : &h_denom_pub);
329 0 : TALER_wallet_recoup_refresh_sign (
330 : &h_denom_pub,
331 0 : &rrs->che_new.details.recoup_refresh.coin_bks,
332 : coin_priv,
333 : &rrs->che_new.details.recoup_refresh.coin_sig);
334 0 : rrs->ph = TALER_EXCHANGE_recoup_refresh (
335 : TALER_TESTING_interpreter_get_context (is),
336 : TALER_TESTING_get_exchange_url (is),
337 : TALER_TESTING_get_keys (is),
338 : denom_pub,
339 : coin_sig,
340 : ewv,
341 : rplanchet,
342 : planchet,
343 : idx,
344 : &recoup_refresh_cb,
345 : rrs);
346 0 : GNUNET_assert (NULL != rrs->ph);
347 : }
348 :
349 :
350 : /**
351 : * Cleanup the "recoup_refresh" CMD state, and possibly cancel
352 : * a pending operation thereof.
353 : *
354 : * @param cls closure.
355 : * @param cmd the command which is being cleaned up.
356 : */
357 : static void
358 0 : recoup_refresh_cleanup (void *cls,
359 : const struct TALER_TESTING_Command *cmd)
360 : {
361 0 : struct RecoupRefreshState *rrs = cls;
362 0 : if (NULL != rrs->ph)
363 : {
364 0 : TALER_EXCHANGE_recoup_refresh_cancel (rrs->ph);
365 0 : rrs->ph = NULL;
366 : }
367 0 : GNUNET_free (rrs);
368 0 : }
369 :
370 :
371 : /**
372 : * Offer internal data from a "recoup-refresh" CMD state to other
373 : * commands.
374 : *
375 : * @param cls closure
376 : * @param[out] ret result (could be anything)
377 : * @param trait name of the trait
378 : * @param index index number of the object to offer.
379 : * @return #GNUNET_OK on success
380 : */
381 : static enum GNUNET_GenericReturnValue
382 0 : recoup_refresh_traits (void *cls,
383 : const void **ret,
384 : const char *trait,
385 : unsigned int index)
386 : {
387 0 : struct RecoupRefreshState *rrs = cls;
388 : struct TALER_TESTING_Trait traits[] = {
389 0 : TALER_TESTING_make_trait_coin_history (0,
390 0 : &rrs->che_old),
391 0 : TALER_TESTING_make_trait_coin_pub (0,
392 0 : &rrs->coin_pub_old),
393 0 : TALER_TESTING_make_trait_coin_history (1,
394 0 : &rrs->che_new),
395 0 : TALER_TESTING_make_trait_coin_pub (1,
396 0 : &rrs->coin_pub_new),
397 0 : TALER_TESTING_trait_end ()
398 : };
399 :
400 0 : return TALER_TESTING_get_trait (traits,
401 : ret,
402 : trait,
403 : index);
404 : }
405 :
406 :
407 : struct TALER_TESTING_Command
408 0 : TALER_TESTING_cmd_recoup_refresh (const char *label,
409 : unsigned int expected_response_code,
410 : const char *coin_reference,
411 : const char *melt_reference,
412 : const char *amount)
413 : {
414 : struct RecoupRefreshState *rrs;
415 :
416 0 : rrs = GNUNET_new (struct RecoupRefreshState);
417 0 : rrs->expected_response_code = expected_response_code;
418 0 : rrs->coin_reference = coin_reference;
419 0 : rrs->melt_reference = melt_reference;
420 0 : if (GNUNET_OK !=
421 0 : TALER_string_to_amount (amount,
422 : &rrs->amount))
423 : {
424 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
425 : "Failed to parse amount `%s' at %s\n",
426 : amount,
427 : label);
428 0 : GNUNET_assert (0);
429 : }
430 : {
431 0 : struct TALER_TESTING_Command cmd = {
432 : .cls = rrs,
433 : .label = label,
434 : .run = &recoup_refresh_run,
435 : .cleanup = &recoup_refresh_cleanup,
436 : .traits = &recoup_refresh_traits
437 : };
438 :
439 0 : return cmd;
440 : }
441 : }
|