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