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