Line data Source code
1 : /*
2 : This file is part of TALER
3 : Copyright (C) 2014-2024 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_api_cmd_pay_order.c
21 : * @brief command to test the /orders/ID/pay feature.
22 : * @author Marcello Stanisci
23 : * @author Christian Grothoff
24 : */
25 : #include "platform.h"
26 : #include <gnunet/gnunet_common.h>
27 : #include <gnunet/gnunet_json_lib.h>
28 : #include <gnunet/gnunet_time_lib.h>
29 : #include <jansson.h>
30 : #include <stddef.h>
31 : #include <stdint.h>
32 : #include <taler/taler_exchange_service.h>
33 : #include <taler/taler_testing_lib.h>
34 : #include <taler/taler_signatures.h>
35 : #include "taler_merchant_service.h"
36 : #include "taler_merchant_pay_service.h"
37 : #include "taler_merchant_testing_lib.h"
38 :
39 : #ifdef HAVE_DONAU_DONAU_SERVICE_H
40 : #include <donau/donau_service.h>
41 : #include <donau/donau_testing_lib.h>
42 : #include <donau/donau_json_lib.h>
43 : #endif /* HAVE_DONAU_DONAU_SERVICE_H */
44 :
45 : #ifdef HAVE_DONAU_DONAU_SERVICE_H
46 : /**
47 : * Struct for handling the CS approach in signing of the bkps
48 : */
49 : struct CSR_Data
50 : {
51 : /**
52 : * Handle to the "batch issue receipt status" operation.
53 : */
54 : struct DONAU_CsRBatchIssueHandle *csr_handle;
55 :
56 : /**
57 : * CS-Nonce
58 : */
59 : union GNUNET_CRYPTO_BlindSessionNonce nonce;
60 :
61 : /**
62 : * batch issue receipt status state
63 : */
64 : struct StatusState *ss;
65 :
66 : /**
67 : * array position in batch issue receipt request (first position is zero)
68 : */
69 : size_t position;
70 : };
71 :
72 : /**
73 : * Handling all data needed for the /pay DONAU CMD.
74 : */
75 : struct MerchantDonauPayData
76 : {
77 : /**
78 : * Donau URL.
79 : */
80 : const char *donau_url;
81 :
82 : /**
83 : * Donau keys
84 : */
85 : struct DONAU_Keys *keys;
86 :
87 : /**
88 : * Charity reference
89 : */
90 : const char *charity_reference;
91 :
92 : /**
93 : * Charity id
94 : */
95 : uint64_t charity_id;
96 :
97 : /**
98 : * Amount of the donation
99 : */
100 : struct TALER_Amount donation_amount;
101 :
102 : /**
103 : * Number of BUDIs to create or fetch. Example only.
104 : */
105 : uint32_t num_bkps;
106 :
107 : /**
108 : * Year of the donation
109 : */
110 : uint64_t year;
111 :
112 : /**
113 : * Selected donation unit pub keys for this pay order request
114 : */
115 : struct DONAU_DonationUnitPublicKey *selected_pks;
116 :
117 : /**
118 : * BUDI key pairs used in the payment (blinded_udi + pubkey).
119 : */
120 : struct DONAU_BlindedUniqueDonorIdentifierKeyPair *bkps;
121 :
122 : /**
123 : * Blinding secrets, if needed for each BUDI (CS vs. RSA).
124 : */
125 : union GNUNET_CRYPTO_BlindingSecretP *blinding_secrets;
126 :
127 : /**
128 : * Blinding values. Cs-nonces, cipher.
129 : */
130 : const struct DONAU_BatchIssueValues **alg_values;
131 :
132 : /**
133 : * Hash of the salted donor tax id, if relevant.
134 : */
135 : struct DONAU_HashDonorTaxId h_donor_tax_id;
136 :
137 : /**
138 : * Array of donation receipts;
139 : */
140 : struct DONAU_DonationReceipt *receipts;
141 :
142 : /**
143 : * Array of hashed udis.
144 : */
145 : struct DONAU_UniqueDonorIdentifierHashP *h_udis;
146 :
147 : /**
148 : * If using the CS approach, we might track how many
149 : * asynchronous calls are still pending, etc.
150 : */
151 : unsigned int cs_pending;
152 :
153 : /**
154 : * Budis Key Pairs json
155 : */
156 : json_t *budis_json;
157 : };
158 :
159 :
160 : /**
161 : * Prepares the donau data for the /pay CMD.
162 : *
163 : * @param is interpreter state
164 : * @param ss donau data to prepare
165 : */
166 : static enum GNUNET_GenericReturnValue
167 : prepare_donau_data (struct TALER_TESTING_Interpreter *is,
168 : struct MerchantDonauPayData *ss)
169 : {
170 : /* Get charity id and the charity private key from trait */
171 : {
172 : const struct TALER_TESTING_Command *charity_post_cmd;
173 : const uint64_t *charity_id;
174 :
175 : charity_post_cmd = TALER_TESTING_interpreter_lookup_command (
176 : is,
177 : ss->charity_reference);
178 :
179 : if (GNUNET_OK !=
180 : TALER_TESTING_get_trait_charity_id (charity_post_cmd,
181 : &charity_id))
182 : {
183 : GNUNET_break (0);
184 : return GNUNET_SYSERR;
185 : }
186 : ss->charity_id = (uint64_t) *(charity_id);
187 : }
188 :
189 : /* Get donau keys from trait */
190 : {
191 : const struct TALER_TESTING_Command *keys_cmd;
192 : struct DONAU_Keys *keys;
193 :
194 : keys_cmd = TALER_TESTING_interpreter_get_command (is,
195 : "donau");
196 :
197 : if (GNUNET_OK !=
198 : TALER_TESTING_get_trait_donau_keys (keys_cmd,
199 : &keys))
200 : {
201 : GNUNET_break (0);
202 : return GNUNET_SYSERR;
203 : }
204 : ss->keys = keys;
205 : }
206 :
207 : /* Get selected_pks + num_bkps*/
208 : {
209 : enum GNUNET_GenericReturnValue sret;
210 :
211 : sret = DONAU_select_donation_unit_keys_for_amount (
212 : ss->keys,
213 : &ss->donation_amount,
214 : ss->year,
215 : &ss->selected_pks,
216 : &ss->num_bkps);
217 :
218 : if (GNUNET_SYSERR == sret)
219 : {
220 : GNUNET_break (0);
221 : TALER_TESTING_interpreter_fail (is);
222 : return GNUNET_SYSERR;
223 : }
224 : if ((GNUNET_NO == sret) || (0 == ss->num_bkps))
225 : {
226 : GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
227 : "Could not compose exact amount from donation units\n");
228 : TALER_TESTING_interpreter_fail (is);
229 : return GNUNET_NO;
230 : }
231 : }
232 :
233 : /* Get BUDIsKP */
234 : {
235 : ss->bkps
236 : = GNUNET_new_array (ss->num_bkps,
237 : struct DONAU_BlindedUniqueDonorIdentifierKeyPair);
238 : ss->blinding_secrets
239 : = GNUNET_new_array (ss->num_bkps,
240 : union GNUNET_CRYPTO_BlindingSecretP);
241 : ss->receipts
242 : = GNUNET_new_array (ss->num_bkps,
243 : struct DONAU_DonationReceipt);
244 : ss->alg_values
245 : = GNUNET_new_array (ss->num_bkps,
246 : const struct DONAU_BatchIssueValues *);
247 : ss->h_udis
248 : = GNUNET_new_array (ss->num_bkps,
249 : struct DONAU_UniqueDonorIdentifierHashP);
250 :
251 : for (size_t cnt = 0; cnt < ss->num_bkps; cnt++)
252 : {
253 : struct DONAU_UniqueDonorIdentifierNonce *udi_nonce;
254 : struct DONAU_BudiMasterSecretP ps;
255 : const struct DONAU_BatchIssueValues *alg_values;
256 : struct DONAU_BlindedUniqueDonorIdentifier *blinded_udi;
257 : struct DONAU_UniqueDonorIdentifierHashP *udi_hash;
258 :
259 : DONAU_donation_unit_pub_hash (&ss->selected_pks[cnt],
260 : &ss->bkps[cnt].h_donation_unit_pub);
261 :
262 : ss->receipts[cnt].h_donation_unit_pub
263 : = ss->bkps[cnt].h_donation_unit_pub;
264 : udi_nonce
265 : = &ss->receipts[cnt].nonce;
266 : blinded_udi
267 : = &ss->bkps[cnt].blinded_udi;
268 : udi_hash = &ss->h_udis[cnt];
269 :
270 : GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_STRONG,
271 : &ps,
272 : sizeof (ps));
273 : GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
274 : udi_nonce,
275 : sizeof (*udi_nonce));
276 : switch (ss->selected_pks[cnt].bsign_pub_key->cipher)
277 : {
278 : case GNUNET_CRYPTO_BSA_RSA:
279 : alg_values = DONAU_donation_unit_ewv_rsa_singleton ();
280 : DONAU_budi_secret_create (&ps,
281 : alg_values,
282 : &ss->blinding_secrets[cnt]);
283 : GNUNET_assert (GNUNET_OK ==
284 : DONAU_donation_unit_blind (
285 : &ss->selected_pks[cnt],
286 : &ss->blinding_secrets[cnt],
287 : NULL, /* no cs-nonce needed for rsa */
288 : udi_nonce,
289 : &ss->h_donor_tax_id,
290 : alg_values,
291 : udi_hash,
292 : blinded_udi));
293 : ss->alg_values[cnt] = alg_values;
294 : break;
295 : case GNUNET_CRYPTO_BSA_CS:
296 : GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
297 : "CS donation-unit key not yet supported – skip");
298 : return GNUNET_NO;
299 : /* FIXME: BUG-#### Cs support missing/broken for donau
300 : struct CSR_Data *csr_data = GNUNET_new (struct CSR_Data);
301 : TALER_cs_withdraw_nonce_derive ( // FIXME: write new method
302 : (struct TALER_PlanchetMasterSecretP *) &ps,
303 : &csr_data->nonce.cs_nonce);
304 : csr_data->ss = is;
305 : csr_data->position = cnt;
306 :
307 : csr_data->csr_handle = DONAU_csr_issue (
308 : TALER_TESTING_interpreter_get_context (is),
309 : TALER_TESTING_get_donau_url (is),
310 : &ss->selected_pks[cnt],
311 : &csr_data->nonce.cs_nonce,
312 : &cs_stage_two_callback,
313 : csr_data);
314 : if (NULL == csr_data->csr_handle)
315 : {
316 : GNUNET_break (0);
317 : }
318 : ss->cs_pending++; */
319 : break;
320 : default:
321 : GNUNET_break (0);
322 : }
323 : }
324 :
325 : {
326 : json_t *budikeypairs = json_array ();
327 :
328 : GNUNET_assert (NULL != budikeypairs);
329 : for (size_t i = 0; i < ss->num_bkps; i++)
330 : {
331 : json_t *budikeypair = GNUNET_JSON_PACK (
332 : GNUNET_JSON_pack_data_auto ("h_donation_unit_pub",
333 : &ss->bkps[i].h_donation_unit_pub),
334 : DONAU_JSON_pack_blinded_donation_identifier ("blinded_udi",
335 : &ss->bkps[i].blinded_udi)
336 : );
337 :
338 : /* steal the reference into the array */
339 : GNUNET_assert (0 == json_array_append_new (budikeypairs,
340 : budikeypair));
341 : }
342 : ss->budis_json = budikeypairs;
343 : }
344 : }
345 : return GNUNET_OK;
346 : };
347 : #endif /* HAVE_DONAU_DONAU_SERVICE_H */
348 :
349 : /**
350 : * State for a /pay CMD.
351 : */
352 : struct PayState
353 : {
354 : /**
355 : * Contract terms hash code.
356 : */
357 : struct TALER_PrivateContractHashP h_contract_terms;
358 :
359 : /**
360 : * The interpreter state.
361 : */
362 : struct TALER_TESTING_Interpreter *is;
363 :
364 : /**
365 : * Expected HTTP response status code.
366 : */
367 : unsigned int http_status;
368 :
369 : /**
370 : * Reference to a command that can provide a order id,
371 : * typically a /proposal test command.
372 : */
373 : const char *proposal_reference;
374 :
375 : /**
376 : * Reference to a command that can provide a coin, so
377 : * we can pay here.
378 : */
379 : const char *coin_reference;
380 :
381 : /**
382 : * Reference to a command that can provide one or
383 : * multiple tokens used as inputs for the payment.
384 : * In the form "LABEL0[/INDEX];LABEL1[/INDEX];..."
385 : */
386 : const char *token_reference;
387 :
388 : /**
389 : * The merchant base URL.
390 : */
391 : const char *merchant_url;
392 :
393 : /**
394 : * Total amount to be paid.
395 : */
396 : struct TALER_Amount total_amount;
397 :
398 : /**
399 : * Amount to be paid, plus the deposit fee.
400 : */
401 : const char *amount_with_fee;
402 :
403 : /**
404 : * Amount to be paid, including NO fees.
405 : */
406 : const char *amount_without_fee;
407 :
408 : /**
409 : * Handle to the pay operation.
410 : */
411 : struct TALER_MERCHANT_OrderPayHandle *oph;
412 :
413 : /**
414 : * Signature from the merchant, set on success.
415 : */
416 : struct TALER_MerchantSignatureP merchant_sig;
417 :
418 : /**
419 : * Array of issued tokens, set on success.
420 : */
421 : struct TALER_MERCHANT_PrivateTokenDetails *issued_tokens;
422 :
423 : /**
424 : * Number of tokens in @e issued_tokens.
425 : */
426 : unsigned int num_issued_tokens;
427 :
428 : /**
429 : * Number of donau_tokens in @e issued_tokens.
430 : */
431 : unsigned int num_donau_tokens;
432 :
433 : /**
434 : * The session for which the payment is made.
435 : */
436 : const char *session_id;
437 :
438 : /**
439 : * base64-encoded key
440 : */
441 : const char *pos_key;
442 :
443 : /**
444 : * Option that add amount of the order
445 : */
446 : enum TALER_MerchantConfirmationAlgorithm pos_alg;
447 :
448 : /**
449 : * Index of the choice to be used in the payment. -1 for orders without choices.
450 : */
451 : int choice_index;
452 :
453 : #ifdef HAVE_DONAU_DONAU_SERVICE_H
454 : /**
455 : * Donau data, if required.
456 : */
457 : struct MerchantDonauPayData donau_data;
458 : #endif /* HAVE_DONAU_DONAU_SERVICE_H */
459 : };
460 :
461 :
462 : /**
463 : * Find the token issue public key for a given token family @a slug and
464 : * @a valid_after timestamp.
465 : *
466 : * @param token_families json object of token families where the key is the slug
467 : * @param slug the slug of the token family
468 : * @param key_index index of the key within the token family
469 : * @param[out] pub the token issue public key of the token family
470 : * @return #GNUNET_OK on success and #GNUNET_SYSERR if not found
471 : */
472 : static enum GNUNET_GenericReturnValue
473 6 : find_token_public_key (const json_t *token_families,
474 : const char *slug,
475 : unsigned int key_index,
476 : struct TALER_TokenIssuePublicKey *pub)
477 :
478 : {
479 6 : const json_t *tf = json_object_get (token_families, slug);
480 : const json_t *keys;
481 : struct GNUNET_JSON_Specification spec[] = {
482 6 : GNUNET_JSON_spec_array_const ("keys",
483 : &keys),
484 6 : GNUNET_JSON_spec_end ()
485 : };
486 : const json_t *key;
487 : const char *error_name;
488 : unsigned int error_line;
489 : struct GNUNET_JSON_Specification ispec[] = {
490 6 : TALER_JSON_spec_token_pub (NULL,
491 : pub),
492 6 : GNUNET_JSON_spec_end ()
493 : };
494 :
495 6 : if (NULL == tf)
496 : {
497 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
498 : "Token family `%s' not found\n",
499 : slug);
500 0 : return GNUNET_SYSERR;
501 : }
502 6 : if (GNUNET_OK !=
503 6 : GNUNET_JSON_parse (tf,
504 : spec,
505 : NULL,
506 : NULL))
507 : {
508 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
509 : "Failed to parse token family `%s'\n",
510 : slug);
511 0 : return GNUNET_SYSERR;
512 : }
513 :
514 6 : key = json_array_get (keys,
515 : key_index);
516 6 : if (NULL == key)
517 : {
518 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
519 : "Key with index %u for token family '%s' not found\n",
520 : key_index,
521 : slug);
522 0 : return GNUNET_SYSERR;
523 : }
524 6 : if (GNUNET_OK !=
525 6 : GNUNET_JSON_parse (key,
526 : ispec,
527 : &error_name,
528 : &error_line))
529 : {
530 0 : GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
531 : "Failed to parse %s at %u: %s\n",
532 : ispec[error_line].field,
533 : error_line,
534 : error_name);
535 0 : return GNUNET_SYSERR;
536 : }
537 6 : return GNUNET_OK;
538 : }
539 :
540 :
541 : /**
542 : * Parse the @a coins specification and grow the @a pc
543 : * array with the coins found, updating @a npc.
544 : *
545 : * @param[in,out] pc pointer to array of coins found
546 : * @param[in,out] npc length of array at @a pc
547 : * @param[in] coins string specifying coins to add to @a pc,
548 : * clobbered in the process
549 : * @param is interpreter state
550 : * @param amount_with_fee total amount to be paid for a contract.
551 : * @param amount_without_fee to be removed, there is no
552 : * per-contract fee, only per-coin exists.
553 : * @return #GNUNET_OK on success
554 : */
555 : static enum GNUNET_GenericReturnValue
556 35 : build_coins (struct TALER_MERCHANT_PayCoin **pc,
557 : unsigned int *npc,
558 : char *coins,
559 : struct TALER_TESTING_Interpreter *is,
560 : const char *amount_with_fee,
561 : const char *amount_without_fee)
562 : {
563 : char *token;
564 : struct TALER_EXCHANGE_Keys *keys;
565 :
566 35 : keys = TALER_TESTING_get_keys (is);
567 35 : if (NULL == keys)
568 : {
569 0 : GNUNET_break (0);
570 0 : return GNUNET_SYSERR;
571 : }
572 :
573 35 : for (token = strtok (coins, ";");
574 76 : NULL != token;
575 41 : token = strtok (NULL, ";"))
576 : {
577 : const struct TALER_TESTING_Command *coin_cmd;
578 : char *ctok;
579 : unsigned int ci;
580 : struct TALER_MERCHANT_PayCoin *icoin;
581 : const struct TALER_EXCHANGE_DenomPublicKey *dpk;
582 : const char *exchange_url;
583 :
584 : /* Token syntax is "LABEL[/NUMBER]" */
585 41 : ctok = strchr (token, '/');
586 : /* FIXME: Check why ci variable is parsed but not used? */
587 41 : ci = 0;
588 41 : if (NULL != ctok)
589 : {
590 0 : *ctok = '\0';
591 0 : ctok++;
592 0 : if (1 != sscanf (ctok,
593 : "%u",
594 : &ci))
595 : {
596 0 : GNUNET_break (0);
597 0 : return GNUNET_SYSERR;
598 : }
599 : }
600 :
601 41 : coin_cmd = TALER_TESTING_interpreter_lookup_command
602 : (is, token);
603 :
604 41 : if (NULL == coin_cmd)
605 : {
606 0 : GNUNET_break (0);
607 0 : return GNUNET_SYSERR;
608 : }
609 :
610 41 : GNUNET_array_grow (*pc,
611 : *npc,
612 : (*npc) + 1);
613 :
614 41 : icoin = &((*pc)[(*npc) - 1]);
615 :
616 : {
617 : const struct TALER_CoinSpendPrivateKeyP *coin_priv;
618 : const struct TALER_DenominationSignature *denom_sig;
619 : const struct TALER_Amount *denom_value;
620 : const struct TALER_EXCHANGE_DenomPublicKey *denom_pub;
621 : const struct TALER_AgeCommitmentHashP *h_age_commitment;
622 :
623 41 : GNUNET_assert (GNUNET_OK ==
624 : TALER_TESTING_get_trait_coin_priv (coin_cmd,
625 : 0,
626 : &coin_priv));
627 41 : GNUNET_assert (GNUNET_OK ==
628 : TALER_TESTING_get_trait_denom_pub (coin_cmd,
629 : 0,
630 : &denom_pub));
631 41 : GNUNET_assert (GNUNET_OK ==
632 : TALER_TESTING_get_trait_denom_sig (coin_cmd,
633 : 0,
634 : &denom_sig));
635 41 : GNUNET_assert (GNUNET_OK ==
636 : TALER_TESTING_get_trait_amount (coin_cmd,
637 : &denom_value));
638 41 : GNUNET_assert (GNUNET_OK ==
639 : TALER_TESTING_get_trait_h_age_commitment (coin_cmd,
640 : 0,
641 : &h_age_commitment
642 : ));
643 41 : icoin->coin_priv = *coin_priv;
644 41 : icoin->denom_pub = denom_pub->key;
645 41 : icoin->denom_sig = *denom_sig;
646 41 : icoin->denom_value = *denom_value;
647 41 : icoin->amount_with_fee = *denom_value;
648 41 : icoin->h_age_commitment = h_age_commitment;
649 : }
650 41 : GNUNET_assert (NULL != (dpk =
651 : TALER_TESTING_find_pk (keys,
652 : &icoin->denom_value,
653 : false)));
654 :
655 41 : GNUNET_assert (0 <=
656 : TALER_amount_subtract (&icoin->amount_without_fee,
657 : &icoin->denom_value,
658 : &dpk->fees.deposit));
659 41 : GNUNET_assert (GNUNET_OK ==
660 : TALER_TESTING_get_trait_exchange_url (coin_cmd,
661 : &exchange_url));
662 41 : icoin->exchange_url = exchange_url;
663 : }
664 :
665 35 : return GNUNET_OK;
666 : }
667 :
668 :
669 : /**
670 : * Parse the @a pay_references specification and grow the @a tokens
671 : * array with the tokens found, updating @a tokens_num.
672 : *
673 : * @param[in,out] tokens array of tokens found
674 : * @param[in,out] tokens_num length of @a tokens array
675 : * @param[in] pay_references string of ; separated references to pay commands
676 : that issued the tokens.
677 : * @param is interpreter state
678 : * @return #GNUNET_OK on success
679 : */
680 : static enum GNUNET_GenericReturnValue
681 4 : build_tokens (struct TALER_MERCHANT_UseToken **tokens,
682 : unsigned int *tokens_num,
683 : char *pay_references,
684 : struct TALER_TESTING_Interpreter *is)
685 : {
686 : char *ref;
687 :
688 4 : for (ref = strtok (pay_references, ";");
689 8 : NULL != ref;
690 4 : ref = strtok (NULL, ";"))
691 : {
692 : const struct TALER_TESTING_Command *pay_cmd;
693 : char *slash;
694 : unsigned int index;
695 : struct TALER_MERCHANT_UseToken *token;
696 :
697 : /* Reference syntax is "LABEL[/NUMBER]" */
698 4 : slash = strchr (ref, '/');
699 4 : index = 0;
700 4 : if (NULL != slash)
701 : {
702 0 : *slash = '\0';
703 0 : slash++;
704 0 : if (1 != sscanf (slash,
705 : "%u",
706 : &index))
707 : {
708 0 : GNUNET_break (0);
709 0 : return GNUNET_SYSERR;
710 : }
711 : }
712 :
713 4 : pay_cmd = TALER_TESTING_interpreter_lookup_command (is, ref);
714 :
715 4 : if (NULL == pay_cmd)
716 : {
717 0 : GNUNET_break (0);
718 0 : return GNUNET_SYSERR;
719 : }
720 :
721 4 : GNUNET_array_grow (*tokens,
722 : *tokens_num,
723 : (*tokens_num) + 1);
724 :
725 4 : token = &((*tokens)[(*tokens_num) - 1]);
726 :
727 : {
728 : const struct TALER_TokenUsePrivateKeyP *token_priv;
729 : const struct TALER_TokenIssueSignature *issue_sig;
730 : const struct TALER_TokenIssuePublicKey *issue_pub;
731 :
732 4 : GNUNET_assert (GNUNET_OK ==
733 : TALER_TESTING_get_trait_token_priv (pay_cmd,
734 : index,
735 : &token_priv));
736 :
737 4 : GNUNET_assert (GNUNET_OK ==
738 : TALER_TESTING_get_trait_token_issue_sig (pay_cmd,
739 : index,
740 : &issue_sig));
741 :
742 4 : GNUNET_assert (GNUNET_OK ==
743 : TALER_TESTING_get_trait_token_issue_pub (pay_cmd,
744 : index,
745 : &issue_pub));
746 :
747 4 : token->token_priv = *token_priv;
748 4 : token->ub_sig = *issue_sig;
749 4 : token->issue_pub = *issue_pub;
750 : }
751 : }
752 :
753 4 : return GNUNET_OK;
754 : }
755 :
756 :
757 : /**
758 : * Function called with the result of a /pay operation.
759 : * Checks whether the merchant signature is valid and the
760 : * HTTP response code matches our expectation.
761 : *
762 : * @param cls closure with the interpreter state
763 : * @param pr HTTP response
764 : */
765 : static void
766 35 : pay_cb (void *cls,
767 : const struct TALER_MERCHANT_PayResponse *pr)
768 : {
769 35 : struct PayState *ps = cls;
770 :
771 35 : ps->oph = NULL;
772 35 : if (ps->http_status != pr->hr.http_status)
773 : {
774 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
775 : "Unexpected response code %u (%d) to command (%s) %s\n",
776 : pr->hr.http_status,
777 : (int) pr->hr.ec,
778 : pr->hr.hint,
779 : TALER_TESTING_interpreter_get_current_label (ps->is));
780 0 : TALER_TESTING_FAIL (ps->is);
781 : }
782 35 : if (MHD_HTTP_OK == pr->hr.http_status)
783 : {
784 23 : ps->merchant_sig = pr->details.ok.merchant_sig;
785 23 : if (ps->num_issued_tokens + ps->num_donau_tokens !=
786 23 : pr->details.ok.num_tokens)
787 : {
788 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
789 : "Unexpected number of tokens issued. "
790 : "Sent %d envelopes but got %d tokens issued.\n",
791 : ps->num_issued_tokens,
792 : pr->details.ok.num_tokens);
793 0 : GNUNET_break (0);
794 0 : TALER_TESTING_interpreter_fail (ps->is);
795 0 : return;
796 : }
797 27 : for (unsigned int i = 0; i < ps->num_issued_tokens; i++)
798 : {
799 4 : struct TALER_MERCHANT_PrivateTokenDetails *details =
800 4 : &ps->issued_tokens[i];
801 :
802 : /* The issued tokens should be in the
803 : same order as the provided envelopes. */
804 4 : ps->issued_tokens[i].blinded_sig = pr->details.ok.tokens[i].blinded_sig;
805 :
806 4 : if (GNUNET_OK !=
807 4 : TALER_token_issue_sig_unblind (&details->issue_sig,
808 4 : &details->blinded_sig,
809 4 : &details->blinding_secret,
810 4 : &details->h_token_pub,
811 4 : &details->blinding_inputs,
812 4 : &details->issue_pub))
813 : {
814 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
815 : "Failed to unblind token signature\n");
816 0 : GNUNET_break (0);
817 0 : TALER_TESTING_interpreter_fail (ps->is);
818 0 : return;
819 : }
820 : }
821 23 : if (NULL != ps->pos_key)
822 : {
823 : char *pc;
824 2 : bool found = false;
825 :
826 2 : if (NULL == pr->details.ok.pos_confirmation)
827 : {
828 0 : GNUNET_break (0);
829 0 : TALER_TESTING_interpreter_fail (ps->is);
830 0 : return;
831 : }
832 2 : pc = TALER_build_pos_confirmation (ps->pos_key,
833 : ps->pos_alg,
834 2 : &ps->total_amount,
835 : GNUNET_TIME_timestamp_get ());
836 : /* Check if *any* of our TOTP codes overlaps
837 : with any of the returned TOTP codes. */
838 2 : for (const char *tok = strtok (pc, "\n");
839 2 : NULL != tok;
840 0 : tok = strtok (NULL, "\n"))
841 : {
842 2 : if (NULL != strstr (pr->details.ok.pos_confirmation,
843 : tok))
844 : {
845 2 : found = true;
846 2 : break;
847 : }
848 : }
849 2 : GNUNET_free (pc);
850 2 : if (! found)
851 : {
852 0 : GNUNET_break (0);
853 0 : TALER_TESTING_interpreter_fail (ps->is);
854 0 : return;
855 : }
856 : }
857 : }
858 35 : TALER_TESTING_interpreter_next (ps->is);
859 : }
860 :
861 :
862 : /**
863 : * Run a "pay" CMD.
864 : *
865 : * @param cls closure.
866 : * @param cmd current CMD being run.
867 : * @param is interpreter state.
868 : */
869 : static void
870 35 : pay_run (void *cls,
871 : const struct TALER_TESTING_Command *cmd,
872 : struct TALER_TESTING_Interpreter *is)
873 : {
874 35 : struct PayState *ps = cls;
875 : const struct TALER_TESTING_Command *proposal_cmd;
876 : const json_t *contract_terms;
877 : const char *order_id;
878 : struct GNUNET_TIME_Timestamp refund_deadline;
879 : struct GNUNET_TIME_Timestamp pay_deadline;
880 : struct GNUNET_TIME_Timestamp timestamp;
881 : struct TALER_MerchantPublicKeyP merchant_pub;
882 : struct TALER_MerchantWireHashP h_wire;
883 : const struct TALER_PrivateContractHashP *h_proposal;
884 : struct TALER_Amount max_fee;
885 35 : const char *error_name = NULL;
886 35 : unsigned int error_line = 0;
887 : struct TALER_MERCHANT_PayCoin *pay_coins;
888 : unsigned int npay_coins;
889 35 : struct TALER_MERCHANT_UseToken *use_tokens = NULL;
890 35 : unsigned int len_use_tokens = 0;
891 35 : struct TALER_MERCHANT_OutputToken *output_tokens = NULL;
892 35 : unsigned int len_output_tokens = 0;
893 : const struct TALER_MerchantSignatureP *merchant_sig;
894 : const enum TALER_MerchantConfirmationAlgorithm *alg_ptr;
895 :
896 35 : ps->is = is;
897 35 : proposal_cmd = TALER_TESTING_interpreter_lookup_command (
898 : is,
899 : ps->proposal_reference);
900 :
901 35 : if (NULL == proposal_cmd)
902 0 : TALER_TESTING_FAIL (is);
903 :
904 35 : if (GNUNET_OK !=
905 35 : TALER_TESTING_get_trait_contract_terms (proposal_cmd,
906 : &contract_terms))
907 0 : TALER_TESTING_FAIL (is);
908 35 : if (NULL == contract_terms)
909 0 : TALER_TESTING_FAIL (is);
910 35 : if (GNUNET_OK !=
911 35 : TALER_TESTING_get_trait_otp_key (proposal_cmd,
912 : &ps->pos_key))
913 31 : ps->pos_key = NULL;
914 35 : if ( (GNUNET_OK ==
915 35 : TALER_TESTING_get_trait_otp_alg (proposal_cmd,
916 4 : &alg_ptr)) &&
917 4 : (NULL != alg_ptr) )
918 2 : ps->pos_alg = *alg_ptr;
919 : {
920 : /* Get information that needs to be put verbatim in the
921 : * deposit permission */
922 35 : uint64_t version = 0;
923 : struct GNUNET_JSON_Specification spec[] = {
924 35 : GNUNET_JSON_spec_mark_optional (
925 : GNUNET_JSON_spec_uint64 ("version",
926 : &version),
927 : NULL),
928 35 : GNUNET_JSON_spec_string ("order_id",
929 : &order_id),
930 35 : GNUNET_JSON_spec_timestamp ("refund_deadline",
931 : &refund_deadline),
932 35 : GNUNET_JSON_spec_timestamp ("pay_deadline",
933 : &pay_deadline),
934 35 : GNUNET_JSON_spec_timestamp ("timestamp",
935 : ×tamp),
936 35 : GNUNET_JSON_spec_fixed_auto ("merchant_pub",
937 : &merchant_pub),
938 35 : GNUNET_JSON_spec_fixed_auto ("h_wire",
939 : &h_wire),
940 : /* FIXME oec: parse minimum age, use data later? */
941 35 : GNUNET_JSON_spec_end ()
942 : };
943 :
944 35 : if (GNUNET_OK !=
945 35 : GNUNET_JSON_parse (contract_terms,
946 : spec,
947 : &error_name,
948 : &error_line))
949 : {
950 : char *js;
951 :
952 0 : js = json_dumps (contract_terms,
953 : JSON_INDENT (1));
954 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
955 : "Parser failed on %s:%u for input `%s'\n",
956 : error_name,
957 : error_line,
958 : js);
959 0 : free (js);
960 0 : TALER_TESTING_FAIL (is);
961 : }
962 35 : switch (version)
963 : {
964 29 : case 0:
965 : {
966 : struct GNUNET_JSON_Specification v0spec[] = {
967 29 : TALER_JSON_spec_amount_any ("amount",
968 : &ps->total_amount),
969 29 : TALER_JSON_spec_amount_any ("max_fee",
970 : &max_fee),
971 29 : GNUNET_JSON_spec_end ()
972 : };
973 :
974 29 : if (GNUNET_OK !=
975 29 : GNUNET_JSON_parse (contract_terms,
976 : v0spec,
977 : &error_name,
978 : &error_line))
979 : {
980 : char *js;
981 :
982 0 : js = json_dumps (contract_terms,
983 : JSON_INDENT (1));
984 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
985 : "Parser failed on %s:%u for input `%s'\n",
986 : error_name,
987 : error_line,
988 : js);
989 0 : free (js);
990 0 : TALER_TESTING_FAIL (is);
991 : }
992 : }
993 29 : if (0 < ps->choice_index)
994 0 : TALER_TESTING_FAIL (is);
995 29 : break;
996 6 : case 1:
997 : {
998 : const json_t *choices;
999 : const json_t *token_families;
1000 : struct GNUNET_JSON_Specification v1spec[] = {
1001 6 : GNUNET_JSON_spec_object_const ("token_families",
1002 : &token_families),
1003 6 : GNUNET_JSON_spec_array_const ("choices",
1004 : &choices),
1005 6 : GNUNET_JSON_spec_end ()
1006 : };
1007 : const json_t *outputs;
1008 : json_t *output;
1009 : unsigned int output_index;
1010 : const json_t *choice;
1011 :
1012 6 : if (GNUNET_OK !=
1013 6 : GNUNET_JSON_parse (contract_terms,
1014 : v1spec,
1015 : &error_name,
1016 : &error_line))
1017 : {
1018 : char *js;
1019 :
1020 0 : js = json_dumps (contract_terms,
1021 : JSON_INDENT (1));
1022 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1023 : "Parser failed on %s:%u for input `%s'\n",
1024 : error_name,
1025 : error_line,
1026 : js);
1027 0 : free (js);
1028 0 : TALER_TESTING_FAIL (is);
1029 : }
1030 :
1031 6 : choice = json_array_get (choices,
1032 6 : ps->choice_index);
1033 6 : if (NULL == choice)
1034 : {
1035 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1036 : "No choice found at index %d\n",
1037 : ps->choice_index);
1038 0 : TALER_TESTING_FAIL (is);
1039 : }
1040 :
1041 : {
1042 6 : const char *ierror_name = NULL;
1043 6 : unsigned int ierror_line = 0;
1044 :
1045 : struct GNUNET_JSON_Specification ispec[] = {
1046 6 : TALER_JSON_spec_amount_any ("amount",
1047 : &ps->total_amount),
1048 6 : TALER_JSON_spec_amount_any ("max_fee",
1049 : &max_fee),
1050 6 : GNUNET_JSON_spec_array_const ("outputs",
1051 : &outputs),
1052 6 : GNUNET_JSON_spec_end ()
1053 : };
1054 :
1055 6 : if (GNUNET_OK !=
1056 6 : GNUNET_JSON_parse (choice,
1057 : ispec,
1058 : &ierror_name,
1059 : &ierror_line))
1060 : {
1061 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1062 : "Parser failed on %s:%u for input `%s'\n",
1063 : ierror_name,
1064 : ierror_line,
1065 : json_dumps (choice,
1066 : JSON_INDENT (2)));
1067 0 : TALER_TESTING_FAIL (is);
1068 : }
1069 : }
1070 :
1071 12 : json_array_foreach (outputs, output_index, output)
1072 : {
1073 : const char *slug;
1074 : const char *kind;
1075 : uint32_t key_index;
1076 6 : uint32_t count = 1;
1077 6 : const char *ierror_name = NULL;
1078 6 : unsigned int ierror_line = 0;
1079 :
1080 : struct GNUNET_JSON_Specification typespec[] = {
1081 6 : GNUNET_JSON_spec_string ("type",
1082 : &kind),
1083 6 : GNUNET_JSON_spec_end ()
1084 : };
1085 :
1086 6 : if (GNUNET_OK !=
1087 6 : GNUNET_JSON_parse (output,
1088 : typespec,
1089 : &ierror_name,
1090 : &ierror_line))
1091 : {
1092 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1093 : "Parser failed on %s:%u for input `%s'\n",
1094 : ierror_name,
1095 : ierror_line,
1096 : json_dumps (output,
1097 : JSON_INDENT (2)));
1098 0 : TALER_TESTING_FAIL (is);
1099 : }
1100 :
1101 6 : if (0 == strcmp ("tax-receipt",
1102 : kind))
1103 : {
1104 : const json_t *donau_urls;
1105 :
1106 : // For test, we care only about the presence of it
1107 : struct GNUNET_JSON_Specification donauspec[] = {
1108 0 : GNUNET_JSON_spec_array_const ("donau_urls",
1109 : &donau_urls),
1110 0 : GNUNET_JSON_spec_end ()
1111 : };
1112 :
1113 0 : if (GNUNET_OK !=
1114 0 : GNUNET_JSON_parse (output,
1115 : donauspec,
1116 : &ierror_name,
1117 : &ierror_line))
1118 : {
1119 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1120 : "Parser failed on %s:%u for input `%s'\n",
1121 : ierror_name,
1122 : ierror_line,
1123 : json_dumps (output,
1124 : JSON_INDENT (2)));
1125 0 : TALER_TESTING_FAIL (is);
1126 : }
1127 :
1128 : #ifdef HAVE_DONAU_DONAU_SERVICE_H
1129 : {
1130 : const char *donau_url_str;
1131 :
1132 : if ( (NULL == donau_urls) ||
1133 : (0 == json_array_size (donau_urls)) )
1134 : {
1135 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1136 : "No donau_urls found in output\n");
1137 : TALER_TESTING_FAIL (is);
1138 : }
1139 :
1140 : donau_url_str = json_string_value (json_array_get (donau_urls,
1141 : 0));
1142 : if (NULL == donau_url_str)
1143 : {
1144 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1145 : "First entry in donau_urls is not a string\n");
1146 : TALER_TESTING_FAIL (is);
1147 : }
1148 :
1149 : ps->donau_data.donau_url = GNUNET_strdup (donau_url_str);
1150 :
1151 : if (NULL != ps->donau_data.charity_reference)
1152 : {
1153 : switch (prepare_donau_data (is,
1154 : &ps->donau_data))
1155 : {
1156 : case GNUNET_OK:
1157 : break;
1158 : case GNUNET_NO:
1159 : TALER_TESTING_interpreter_next (ps->is);
1160 : return;
1161 : case GNUNET_SYSERR:
1162 : TALER_TESTING_FAIL (is);
1163 : return;
1164 : }
1165 : ps->num_donau_tokens = ps->donau_data.num_bkps;
1166 : }
1167 : }
1168 : #else /* HAVE_DONAU_DONAU_SERVICE_H */
1169 : /* SIMPLY NOTHING */
1170 : #endif /* HAVE_DONAU_DONAU_SERVICE_H */
1171 : }
1172 :
1173 6 : if (0 == strcmp ("token",
1174 : kind))
1175 : {
1176 : struct GNUNET_JSON_Specification ispec[] = {
1177 6 : GNUNET_JSON_spec_string ("token_family_slug",
1178 : &slug),
1179 6 : GNUNET_JSON_spec_uint32 ("key_index",
1180 : &key_index),
1181 6 : GNUNET_JSON_spec_mark_optional (
1182 : GNUNET_JSON_spec_uint32 ("count",
1183 : &count),
1184 : NULL),
1185 6 : GNUNET_JSON_spec_end ()
1186 : };
1187 :
1188 6 : if (GNUNET_OK !=
1189 6 : GNUNET_JSON_parse (output,
1190 : ispec,
1191 : &ierror_name,
1192 : &ierror_line))
1193 : {
1194 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1195 : "Parser failed on %s:%u for input `%s'\n",
1196 : ierror_name,
1197 : ierror_line,
1198 : json_dumps (output,
1199 : JSON_INDENT (2)));
1200 0 : TALER_TESTING_FAIL (is);
1201 : }
1202 :
1203 6 : if (0 != strcmp ("token",
1204 : kind))
1205 : {
1206 0 : continue;
1207 : }
1208 :
1209 6 : GNUNET_array_grow (
1210 : ps->issued_tokens,
1211 : ps->num_issued_tokens,
1212 : ps->num_issued_tokens + count + ps->num_donau_tokens);
1213 :
1214 12 : for (unsigned int k = 0; k < count; k++)
1215 : {
1216 6 : struct TALER_MERCHANT_PrivateTokenDetails *details =
1217 6 : &ps->issued_tokens[ps->num_issued_tokens - count + k
1218 6 : + ps->num_donau_tokens];
1219 :
1220 6 : if (GNUNET_OK !=
1221 6 : find_token_public_key (token_families,
1222 : slug,
1223 : key_index,
1224 : &details->issue_pub))
1225 : {
1226 0 : TALER_TESTING_FAIL (is);
1227 : }
1228 :
1229 : /* Only RSA is supported for now. */
1230 6 : GNUNET_assert (GNUNET_CRYPTO_BSA_RSA ==
1231 : details->issue_pub.public_key->cipher);
1232 :
1233 6 : TALER_token_blind_input_copy (&details->blinding_inputs,
1234 : TALER_token_blind_input_rsa_singleton ()
1235 : );
1236 : /* FIXME: Where to get details->blinding_inputs from? */
1237 6 : TALER_token_use_setup_random (&details->master);
1238 6 : TALER_token_use_setup_priv (&details->master,
1239 6 : &details->blinding_inputs,
1240 : &details->token_priv);
1241 6 : TALER_token_use_blinding_secret_create (&details->master,
1242 6 : &details->blinding_inputs,
1243 : &details->blinding_secret)
1244 : ;
1245 6 : GNUNET_CRYPTO_eddsa_key_get_public (
1246 6 : &details->token_priv.private_key,
1247 : &details->token_pub.public_key);
1248 6 : GNUNET_CRYPTO_hash (&details->token_pub.public_key,
1249 : sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey),
1250 : &details->h_token_pub.hash);
1251 6 : details->envelope.blinded_pub =
1252 6 : GNUNET_CRYPTO_message_blind_to_sign
1253 : (
1254 6 : details->issue_pub.public_key,
1255 6 : &details->blinding_secret,
1256 : NULL, /* FIXME: Add session nonce to support CS tokens */
1257 6 : &details->h_token_pub.hash,
1258 : sizeof (details->h_token_pub.hash),
1259 6 : details->blinding_inputs.blinding_inputs);
1260 :
1261 6 : if (NULL == details->envelope.blinded_pub)
1262 : {
1263 0 : GNUNET_break (0);
1264 0 : TALER_TESTING_FAIL (is);
1265 : }
1266 : }
1267 : }
1268 : }
1269 : }
1270 :
1271 6 : break;
1272 0 : default:
1273 0 : TALER_TESTING_FAIL (is);
1274 : }
1275 : }
1276 :
1277 : {
1278 : char *cr;
1279 :
1280 35 : cr = GNUNET_strdup (ps->coin_reference);
1281 35 : pay_coins = NULL;
1282 35 : npay_coins = 0;
1283 35 : if (GNUNET_OK !=
1284 35 : build_coins (&pay_coins,
1285 : &npay_coins,
1286 : cr,
1287 : is,
1288 : ps->amount_with_fee,
1289 : ps->amount_without_fee))
1290 : {
1291 0 : GNUNET_array_grow (pay_coins,
1292 : npay_coins,
1293 : 0);
1294 0 : GNUNET_free (cr);
1295 0 : TALER_TESTING_FAIL (is);
1296 : }
1297 35 : GNUNET_free (cr);
1298 : }
1299 35 : if (NULL != ps->token_reference)
1300 : {
1301 : char *tr;
1302 :
1303 4 : tr = GNUNET_strdup (ps->token_reference);
1304 4 : if (GNUNET_OK !=
1305 4 : build_tokens (&use_tokens,
1306 : &len_use_tokens,
1307 : tr,
1308 : is))
1309 : {
1310 0 : GNUNET_array_grow (use_tokens,
1311 : len_use_tokens,
1312 : 0);
1313 0 : GNUNET_free (tr);
1314 0 : TALER_TESTING_FAIL (is);
1315 : }
1316 4 : GNUNET_free (tr);
1317 : }
1318 :
1319 35 : GNUNET_array_grow (output_tokens,
1320 : len_output_tokens,
1321 : ps->num_issued_tokens);
1322 41 : for (unsigned int i = 0; i<len_output_tokens; i++)
1323 : {
1324 6 : output_tokens[i].envelope.blinded_pub
1325 6 : = ps->issued_tokens[i].envelope.blinded_pub;
1326 : }
1327 :
1328 35 : if (GNUNET_OK !=
1329 35 : TALER_TESTING_get_trait_merchant_sig (proposal_cmd,
1330 : &merchant_sig))
1331 0 : TALER_TESTING_FAIL (is);
1332 :
1333 35 : if (GNUNET_OK !=
1334 35 : TALER_TESTING_get_trait_h_contract_terms (proposal_cmd,
1335 : &h_proposal))
1336 0 : TALER_TESTING_FAIL (is);
1337 35 : ps->h_contract_terms = *h_proposal;
1338 :
1339 : /* New logic of setting pay params */
1340 : {
1341 : struct GNUNET_CURL_Context *ctx =
1342 35 : TALER_TESTING_interpreter_get_context (is);
1343 : struct TALER_MERCHANT_OrderPayOption opts[32];
1344 35 : size_t oi = 0;
1345 :
1346 35 : ps->oph = TALER_MERCHANT_order_pay_create (ctx,
1347 : &pay_cb,
1348 : ps);
1349 :
1350 35 : if (NULL == ps->oph)
1351 0 : TALER_TESTING_FAIL (is);
1352 :
1353 : #define ADD(_opt) opts[oi++] = (_opt)
1354 35 : ADD (TALER_MERCHANT_ORDER_PAY_OPTION_MERCHANT_URL (ps->merchant_url));
1355 35 : ADD (TALER_MERCHANT_ORDER_PAY_OPTION_ORDER_ID (order_id));
1356 35 : if (NULL != ps->session_id)
1357 9 : ADD (TALER_MERCHANT_ORDER_PAY_OPTION_SESSION_ID (ps->session_id));
1358 35 : ADD (TALER_MERCHANT_ORDER_PAY_OPTION_H_CONTRACT (h_proposal));
1359 35 : if (ps->choice_index >= 0)
1360 6 : ADD (TALER_MERCHANT_ORDER_PAY_OPTION_CHOICE_INDEX (ps->choice_index));
1361 35 : ADD (TALER_MERCHANT_ORDER_PAY_OPTION_AMOUNT (&ps->total_amount));
1362 35 : ADD (TALER_MERCHANT_ORDER_PAY_OPTION_MAX_FEE (&max_fee));
1363 35 : ADD (TALER_MERCHANT_ORDER_PAY_OPTION_MERCHANT_PUB (&merchant_pub));
1364 35 : ADD (TALER_MERCHANT_ORDER_PAY_OPTION_TIMESTAMP (timestamp));
1365 35 : ADD (TALER_MERCHANT_ORDER_PAY_OPTION_REFUND_DEADLINE (refund_deadline));
1366 35 : ADD (TALER_MERCHANT_ORDER_PAY_OPTION_PAY_DEADLINE (pay_deadline));
1367 35 : ADD (TALER_MERCHANT_ORDER_PAY_OPTION_H_WIRE (&h_wire));
1368 35 : ADD (TALER_MERCHANT_ORDER_PAY_OPTION_COINS (npay_coins,
1369 : pay_coins));
1370 35 : if (len_use_tokens > 0)
1371 4 : ADD (TALER_MERCHANT_ORDER_PAY_OPTION_INPUT_TOKENS (len_use_tokens,
1372 : use_tokens));
1373 35 : if (len_output_tokens > 0)
1374 6 : ADD (TALER_MERCHANT_ORDER_PAY_OPTION_OUTPUT_TOKENS (len_output_tokens,
1375 : output_tokens));
1376 :
1377 : #ifdef HAVE_DONAU_DONAU_SERVICE_H
1378 : if (ps->donau_data.charity_reference)
1379 : {
1380 : ADD (
1381 : TALER_MERCHANT_ORDER_PAY_OPTION_DONAU_URL (ps->donau_data.donau_url));
1382 : ADD (TALER_MERCHANT_ORDER_PAY_OPTION_DONAU_YEAR (ps->donau_data.year));
1383 : ADD (TALER_MERCHANT_ORDER_PAY_OPTION_DONAU_BUDIS (
1384 : ps->donau_data.budis_json));
1385 : }
1386 : #endif
1387 35 : ADD (TALER_MERCHANT_ORDER_PAY_OPTION_TERMINATE ());
1388 : #undef ADD
1389 :
1390 35 : if (TALER_MERCHANT_OPOEC_OK !=
1391 35 : TALER_MERCHANT_order_pay_set_options (ps->oph,
1392 : opts,
1393 : oi))
1394 0 : TALER_TESTING_FAIL (is);
1395 :
1396 35 : if (TALER_MERCHANT_OPOEC_OK !=
1397 35 : TALER_MERCHANT_order_pay_start (ps->oph))
1398 0 : TALER_TESTING_FAIL (is);
1399 : }
1400 :
1401 35 : GNUNET_array_grow (pay_coins,
1402 : npay_coins,
1403 : 0);
1404 :
1405 35 : GNUNET_array_grow (use_tokens,
1406 : len_use_tokens,
1407 : 0);
1408 :
1409 35 : GNUNET_array_grow (output_tokens,
1410 : len_output_tokens,
1411 : 0);
1412 : }
1413 :
1414 :
1415 : /**
1416 : * Free a "pay" CMD, and cancel it if need be.
1417 : *
1418 : * @param cls closure.
1419 : * @param cmd command currently being freed.
1420 : */
1421 : static void
1422 35 : pay_cleanup (void *cls,
1423 : const struct TALER_TESTING_Command *cmd)
1424 : {
1425 35 : struct PayState *ps = cls;
1426 :
1427 35 : if (NULL != ps->oph)
1428 : {
1429 0 : GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1430 : "Command `%s' did not complete.\n",
1431 : TALER_TESTING_interpreter_get_current_label (
1432 : ps->is));
1433 0 : TALER_MERCHANT_order_pay_cancel1 (ps->oph);
1434 : }
1435 :
1436 35 : GNUNET_free (ps);
1437 35 : }
1438 :
1439 :
1440 : /**
1441 : * Offer internal data useful to other commands.
1442 : *
1443 : * @param cls closure
1444 : * @param[out] ret result
1445 : * @param trait name of the trait
1446 : * @param index index number of the object to extract.
1447 : * @return #GNUNET_OK on success
1448 : */
1449 : static enum GNUNET_GenericReturnValue
1450 24 : pay_traits (void *cls,
1451 : const void **ret,
1452 : const char *trait,
1453 : unsigned int index)
1454 : {
1455 :
1456 24 : struct PayState *ps = cls;
1457 : const char *order_id;
1458 : const struct TALER_TESTING_Command *proposal_cmd;
1459 : const struct TALER_MerchantPublicKeyP *merchant_pub;
1460 :
1461 24 : if (NULL != ps->token_reference &&
1462 0 : index >= ps->num_issued_tokens)
1463 : {
1464 0 : GNUNET_break (0);
1465 0 : return GNUNET_NO;
1466 : }
1467 :
1468 24 : if (NULL ==
1469 : (proposal_cmd =
1470 24 : TALER_TESTING_interpreter_lookup_command (ps->is,
1471 : ps->proposal_reference)))
1472 : {
1473 0 : GNUNET_break (0);
1474 0 : return GNUNET_SYSERR;
1475 : }
1476 :
1477 24 : if (GNUNET_OK !=
1478 24 : TALER_TESTING_get_trait_order_id (proposal_cmd,
1479 : &order_id))
1480 : {
1481 0 : GNUNET_break (0);
1482 0 : return GNUNET_SYSERR;
1483 : }
1484 :
1485 24 : if (GNUNET_OK !=
1486 24 : TALER_TESTING_get_trait_merchant_pub (proposal_cmd,
1487 : &merchant_pub))
1488 : {
1489 0 : GNUNET_break (0);
1490 0 : return GNUNET_SYSERR;
1491 : }
1492 : {
1493 : struct TALER_Amount amount_with_fee;
1494 :
1495 24 : GNUNET_assert (GNUNET_OK ==
1496 : TALER_string_to_amount (ps->amount_with_fee,
1497 : &amount_with_fee));
1498 : {
1499 : struct TALER_TESTING_Trait traits[] = {
1500 24 : TALER_TESTING_make_trait_proposal_reference (ps->proposal_reference),
1501 24 : TALER_TESTING_make_trait_coin_reference (0,
1502 : ps->coin_reference),
1503 24 : TALER_TESTING_make_trait_order_id (order_id),
1504 24 : TALER_TESTING_make_trait_merchant_pub (merchant_pub),
1505 24 : TALER_TESTING_make_trait_merchant_sig (&ps->merchant_sig),
1506 24 : TALER_TESTING_make_trait_amount (&amount_with_fee),
1507 24 : TALER_TESTING_make_trait_otp_key (ps->pos_key),
1508 24 : TALER_TESTING_make_trait_otp_alg (&ps->pos_alg),
1509 24 : TALER_TESTING_make_trait_token_priv (index,
1510 24 : &ps->issued_tokens[index].
1511 : token_priv),
1512 24 : TALER_TESTING_make_trait_token_issue_pub (index,
1513 24 : &ps->issued_tokens[index].
1514 : issue_pub),
1515 24 : TALER_TESTING_make_trait_token_issue_sig (index,
1516 24 : &ps->issued_tokens[index].
1517 : issue_sig),
1518 24 : TALER_TESTING_trait_end ()
1519 : };
1520 :
1521 24 : return TALER_TESTING_get_trait (traits,
1522 : ret,
1523 : trait,
1524 : index);
1525 : }
1526 : }
1527 : }
1528 :
1529 :
1530 : struct TALER_TESTING_Command
1531 35 : TALER_TESTING_cmd_merchant_pay_order_choices (
1532 : const char *label,
1533 : const char *merchant_url,
1534 : unsigned int http_status,
1535 : const char *proposal_reference,
1536 : const char *coin_reference,
1537 : const char *amount_with_fee,
1538 : const char *amount_without_fee,
1539 : const char *session_id,
1540 : int choice_index,
1541 : const char *token_reference)
1542 : {
1543 : struct PayState *ps;
1544 :
1545 35 : ps = GNUNET_new (struct PayState);
1546 35 : ps->http_status = http_status;
1547 35 : ps->proposal_reference = proposal_reference;
1548 35 : ps->coin_reference = coin_reference;
1549 35 : ps->merchant_url = merchant_url;
1550 35 : ps->amount_with_fee = amount_with_fee;
1551 35 : ps->amount_without_fee = amount_without_fee;
1552 35 : ps->session_id = session_id;
1553 35 : ps->token_reference = token_reference;
1554 35 : ps->choice_index = choice_index;
1555 : {
1556 35 : struct TALER_TESTING_Command cmd = {
1557 : .cls = ps,
1558 : .label = label,
1559 : .run = &pay_run,
1560 : .cleanup = &pay_cleanup,
1561 : .traits = &pay_traits
1562 : };
1563 :
1564 35 : return cmd;
1565 : }
1566 : }
1567 :
1568 :
1569 : #ifdef HAVE_DONAU_DONAU_SERVICE_H
1570 :
1571 : struct TALER_TESTING_Command
1572 : TALER_TESTING_cmd_merchant_pay_order_donau (
1573 : const char *label,
1574 : const char *merchant_url,
1575 : unsigned int http_status,
1576 : const char *proposal_reference,
1577 : const char *coin_reference,
1578 : const char *amount_with_fee,
1579 : const char *amount_without_fee,
1580 : const char *amount_donation,
1581 : const char *session_id,
1582 : int choice_index,
1583 : const char *charity_reference,
1584 : uint64_t year,
1585 : const char *donor_tax_id,
1586 : const char *salt)
1587 : {
1588 : struct PayState *ps;
1589 :
1590 : ps = GNUNET_new (struct PayState);
1591 : ps->http_status = http_status;
1592 : ps->proposal_reference = proposal_reference;
1593 : ps->coin_reference = coin_reference;
1594 : ps->merchant_url = merchant_url;
1595 : ps->amount_with_fee = amount_with_fee;
1596 : ps->amount_without_fee = amount_without_fee;
1597 : ps->session_id = session_id;
1598 : ps->token_reference = NULL;
1599 : ps->choice_index = choice_index;
1600 : ps->donau_data.year = year;
1601 : ps->donau_data.num_bkps = 5;
1602 : ps->donau_data.charity_reference = charity_reference;
1603 : if (GNUNET_OK !=
1604 : TALER_string_to_amount (amount_donation,
1605 : &ps->donau_data.donation_amount))
1606 : {
1607 : GNUNET_assert (0);
1608 : }
1609 :
1610 : /* Compute h_donor_tax_id directly into ps->donau_data: */
1611 : if (! DONAU_compute_salted_tax_id_hash (donor_tax_id,
1612 : salt,
1613 : ps->donau_data.h_donor_tax_id.hash))
1614 : {
1615 : GNUNET_assert (0);
1616 : }
1617 :
1618 : {
1619 : struct TALER_TESTING_Command cmd = {
1620 : .cls = ps,
1621 : .label = label,
1622 : .run = &pay_run,
1623 : .cleanup = &pay_cleanup,
1624 : .traits = &pay_traits
1625 : };
1626 :
1627 : return cmd;
1628 : }
1629 : }
1630 :
1631 :
1632 : #endif /* HAVE_DONAU_DONAU_SERVICE_H */
1633 :
1634 :
1635 : struct TALER_TESTING_Command
1636 29 : TALER_TESTING_cmd_merchant_pay_order (
1637 : const char *label,
1638 : const char *merchant_url,
1639 : unsigned int http_status,
1640 : const char *proposal_reference,
1641 : const char *coin_reference,
1642 : const char *amount_with_fee,
1643 : const char *amount_without_fee,
1644 : const char *session_id)
1645 : {
1646 29 : return TALER_TESTING_cmd_merchant_pay_order_choices (
1647 : label,
1648 : merchant_url,
1649 : http_status,
1650 : proposal_reference,
1651 : coin_reference,
1652 : amount_with_fee,
1653 : amount_without_fee,
1654 : session_id,
1655 : -1,
1656 : NULL);
1657 : }
1658 :
1659 :
1660 : /* end of testing_api_cmd_pay_order.c */
|