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