testing_api_cmd_pay_order.c (50508B)
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 (&ps, 265 sizeof (ps)); 266 GNUNET_CRYPTO_random_block (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 (struct PayState *ps, 798 const struct TALER_MERCHANT_PostOrdersPayResponse *pr) 799 { 800 801 ps->oph = NULL; 802 if (ps->http_status != pr->hr.http_status) 803 { 804 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 805 "Unexpected response code %u (%d) to command (%s) %s\n", 806 pr->hr.http_status, 807 (int) pr->hr.ec, 808 pr->hr.hint, 809 TALER_TESTING_interpreter_get_current_label (ps->is)); 810 TALER_TESTING_FAIL (ps->is); 811 } 812 if (MHD_HTTP_OK == pr->hr.http_status) 813 { 814 ps->merchant_sig = pr->details.ok.merchant_sig; 815 if (ps->num_issued_tokens + ps->num_donau_tokens != 816 pr->details.ok.num_tokens) 817 { 818 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 819 "Unexpected number of tokens issued. " 820 "Sent %d envelopes but got %d tokens issued.\n", 821 ps->num_issued_tokens, 822 pr->details.ok.num_tokens); 823 GNUNET_break (0); 824 TALER_TESTING_interpreter_fail (ps->is); 825 return; 826 } 827 for (unsigned int i = 0; i < ps->num_issued_tokens; i++) 828 { 829 struct TALER_MERCHANT_PrivateTokenDetails *details = 830 &ps->issued_tokens[i]; 831 832 /* The issued tokens should be in the 833 same order as the provided envelopes. */ 834 ps->issued_tokens[i].blinded_sig = pr->details.ok.tokens[i].blinded_sig; 835 836 if (GNUNET_OK != 837 TALER_token_issue_sig_unblind (&details->issue_sig, 838 &details->blinded_sig, 839 &details->blinding_secret, 840 &details->h_token_pub, 841 &details->blinding_inputs, 842 &details->issue_pub)) 843 { 844 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 845 "Failed to unblind token signature\n"); 846 GNUNET_break (0); 847 TALER_TESTING_interpreter_fail (ps->is); 848 return; 849 } 850 } 851 if (NULL != ps->pos_key) 852 { 853 char *pc; 854 bool found = false; 855 856 if (NULL == pr->details.ok.pos_confirmation) 857 { 858 GNUNET_break (0); 859 TALER_TESTING_interpreter_fail (ps->is); 860 return; 861 } 862 pc = TALER_build_pos_confirmation (ps->pos_key, 863 ps->pos_alg, 864 &ps->total_amount, 865 GNUNET_TIME_timestamp_get ()); 866 /* Check if *any* of our TOTP codes overlaps 867 with any of the returned TOTP codes. */ 868 for (const char *tok = strtok (pc, "\n"); 869 NULL != tok; 870 tok = strtok (NULL, "\n")) 871 { 872 if (NULL != strstr (pr->details.ok.pos_confirmation, 873 tok)) 874 { 875 found = true; 876 break; 877 } 878 } 879 GNUNET_free (pc); 880 if (! found) 881 { 882 GNUNET_break (0); 883 TALER_TESTING_interpreter_fail (ps->is); 884 return; 885 } 886 } 887 } 888 TALER_TESTING_interpreter_next (ps->is); 889 } 890 891 892 /** 893 * Run a "pay" CMD. 894 * 895 * @param cls closure. 896 * @param cmd current CMD being run. 897 * @param is interpreter state. 898 */ 899 static void 900 pay_run (void *cls, 901 const struct TALER_TESTING_Command *cmd, 902 struct TALER_TESTING_Interpreter *is) 903 { 904 struct PayState *ps = cls; 905 const struct TALER_TESTING_Command *proposal_cmd; 906 const json_t *contract_terms; 907 const char *order_id; 908 struct GNUNET_TIME_Timestamp refund_deadline; 909 struct GNUNET_TIME_Timestamp pay_deadline; 910 struct GNUNET_TIME_Timestamp timestamp; 911 struct TALER_MerchantPublicKeyP merchant_pub; 912 struct TALER_MerchantWireHashP h_wire; 913 const struct TALER_PrivateContractHashP *h_proposal; 914 struct TALER_Amount max_fee; 915 const char *error_name = NULL; 916 unsigned int error_line = 0; 917 struct TALER_MERCHANT_PostOrdersPayCoin *pay_coins; 918 unsigned int npay_coins; 919 struct TALER_MERCHANT_PostOrdersPayUseToken *use_tokens = NULL; 920 unsigned int len_use_tokens = 0; 921 struct TALER_MERCHANT_PostOrdersPayOutputToken *output_tokens = NULL; 922 unsigned int len_output_tokens = 0; 923 const struct TALER_MerchantSignatureP *merchant_sig; 924 const enum TALER_MerchantConfirmationAlgorithm *alg_ptr; 925 926 ps->is = is; 927 proposal_cmd = TALER_TESTING_interpreter_lookup_command ( 928 is, 929 ps->proposal_reference); 930 931 if (NULL == proposal_cmd) 932 TALER_TESTING_FAIL (is); 933 934 if (GNUNET_OK != 935 TALER_TESTING_get_trait_contract_terms (proposal_cmd, 936 &contract_terms)) 937 TALER_TESTING_FAIL (is); 938 if (NULL == contract_terms) 939 TALER_TESTING_FAIL (is); 940 if (GNUNET_OK != 941 TALER_TESTING_get_trait_otp_key (proposal_cmd, 942 &ps->pos_key)) 943 ps->pos_key = NULL; 944 if ( (GNUNET_OK == 945 TALER_TESTING_get_trait_otp_alg (proposal_cmd, 946 &alg_ptr)) && 947 (NULL != alg_ptr) ) 948 ps->pos_alg = *alg_ptr; 949 { 950 /* Get information that needs to be put verbatim in the 951 * deposit permission */ 952 uint64_t version = 0; 953 struct GNUNET_JSON_Specification spec[] = { 954 GNUNET_JSON_spec_mark_optional ( 955 GNUNET_JSON_spec_uint64 ("version", 956 &version), 957 NULL), 958 GNUNET_JSON_spec_string ("order_id", 959 &order_id), 960 GNUNET_JSON_spec_timestamp ("refund_deadline", 961 &refund_deadline), 962 GNUNET_JSON_spec_timestamp ("pay_deadline", 963 &pay_deadline), 964 GNUNET_JSON_spec_timestamp ("timestamp", 965 ×tamp), 966 GNUNET_JSON_spec_fixed_auto ("merchant_pub", 967 &merchant_pub), 968 GNUNET_JSON_spec_fixed_auto ("h_wire", 969 &h_wire), 970 /* FIXME oec: parse minimum age, use data later? */ 971 GNUNET_JSON_spec_end () 972 }; 973 974 if (GNUNET_OK != 975 GNUNET_JSON_parse (contract_terms, 976 spec, 977 &error_name, 978 &error_line)) 979 { 980 char *js; 981 982 js = json_dumps (contract_terms, 983 JSON_INDENT (1)); 984 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 985 "Parser failed on %s:%u for input `%s'\n", 986 error_name, 987 error_line, 988 js); 989 free (js); 990 TALER_TESTING_FAIL (is); 991 } 992 switch (version) 993 { 994 case 0: 995 { 996 struct GNUNET_JSON_Specification v0spec[] = { 997 TALER_JSON_spec_amount_any ("amount", 998 &ps->total_amount), 999 TALER_JSON_spec_amount_any ("max_fee", 1000 &max_fee), 1001 GNUNET_JSON_spec_end () 1002 }; 1003 1004 if (GNUNET_OK != 1005 GNUNET_JSON_parse (contract_terms, 1006 v0spec, 1007 &error_name, 1008 &error_line)) 1009 { 1010 char *js; 1011 1012 js = json_dumps (contract_terms, 1013 JSON_INDENT (1)); 1014 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 1015 "Parser failed on %s:%u for input `%s'\n", 1016 error_name, 1017 error_line, 1018 js); 1019 free (js); 1020 TALER_TESTING_FAIL (is); 1021 } 1022 } 1023 if (0 < ps->choice_index) 1024 TALER_TESTING_FAIL (is); 1025 break; 1026 case 1: 1027 { 1028 const json_t *choices; 1029 const json_t *token_families; 1030 struct GNUNET_JSON_Specification v1spec[] = { 1031 GNUNET_JSON_spec_object_const ("token_families", 1032 &token_families), 1033 GNUNET_JSON_spec_array_const ("choices", 1034 &choices), 1035 GNUNET_JSON_spec_end () 1036 }; 1037 const json_t *outputs; 1038 json_t *output; 1039 unsigned int output_index; 1040 const json_t *choice; 1041 1042 if (GNUNET_OK != 1043 GNUNET_JSON_parse (contract_terms, 1044 v1spec, 1045 &error_name, 1046 &error_line)) 1047 { 1048 char *js; 1049 1050 js = json_dumps (contract_terms, 1051 JSON_INDENT (1)); 1052 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 1053 "Parser failed on %s:%u for input `%s'\n", 1054 error_name, 1055 error_line, 1056 js); 1057 free (js); 1058 TALER_TESTING_FAIL (is); 1059 } 1060 1061 choice = json_array_get (choices, 1062 ps->choice_index); 1063 if (NULL == choice) 1064 { 1065 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 1066 "No choice found at index %d\n", 1067 ps->choice_index); 1068 TALER_TESTING_FAIL (is); 1069 } 1070 1071 { 1072 const char *ierror_name = NULL; 1073 unsigned int ierror_line = 0; 1074 1075 struct GNUNET_JSON_Specification ispec[] = { 1076 TALER_JSON_spec_amount_any ("amount", 1077 &ps->total_amount), 1078 TALER_JSON_spec_amount_any ("max_fee", 1079 &max_fee), 1080 GNUNET_JSON_spec_array_const ("outputs", 1081 &outputs), 1082 GNUNET_JSON_spec_end () 1083 }; 1084 1085 if (GNUNET_OK != 1086 GNUNET_JSON_parse (choice, 1087 ispec, 1088 &ierror_name, 1089 &ierror_line)) 1090 { 1091 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 1092 "Parser failed on %s:%u for input `%s'\n", 1093 ierror_name, 1094 ierror_line, 1095 json_dumps (choice, 1096 JSON_INDENT (2))); 1097 TALER_TESTING_FAIL (is); 1098 } 1099 } 1100 1101 json_array_foreach (outputs, output_index, output) 1102 { 1103 const char *slug; 1104 const char *kind; 1105 uint32_t key_index; 1106 uint32_t count = 1; 1107 const char *ierror_name = NULL; 1108 unsigned int ierror_line = 0; 1109 1110 struct GNUNET_JSON_Specification typespec[] = { 1111 GNUNET_JSON_spec_string ("type", 1112 &kind), 1113 GNUNET_JSON_spec_end () 1114 }; 1115 1116 if (GNUNET_OK != 1117 GNUNET_JSON_parse (output, 1118 typespec, 1119 &ierror_name, 1120 &ierror_line)) 1121 { 1122 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 1123 "Parser failed on %s:%u for input `%s'\n", 1124 ierror_name, 1125 ierror_line, 1126 json_dumps (output, 1127 JSON_INDENT (2))); 1128 TALER_TESTING_FAIL (is); 1129 } 1130 1131 if (0 == strcmp ("tax-receipt", 1132 kind)) 1133 { 1134 const json_t *donau_urls; 1135 1136 // For test, we care only about the presence of it 1137 struct GNUNET_JSON_Specification donauspec[] = { 1138 GNUNET_JSON_spec_array_const ("donau_urls", 1139 &donau_urls), 1140 GNUNET_JSON_spec_end () 1141 }; 1142 1143 if (GNUNET_OK != 1144 GNUNET_JSON_parse (output, 1145 donauspec, 1146 &ierror_name, 1147 &ierror_line)) 1148 { 1149 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 1150 "Parser failed on %s:%u for input `%s'\n", 1151 ierror_name, 1152 ierror_line, 1153 json_dumps (output, 1154 JSON_INDENT (2))); 1155 TALER_TESTING_FAIL (is); 1156 } 1157 1158 { 1159 const char *donau_url_str; 1160 1161 if ( (NULL == donau_urls) || 1162 (0 == json_array_size (donau_urls)) ) 1163 { 1164 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 1165 "No donau_urls found in output\n"); 1166 TALER_TESTING_FAIL (is); 1167 } 1168 1169 donau_url_str = json_string_value (json_array_get (donau_urls, 1170 0)); 1171 if (NULL == donau_url_str) 1172 { 1173 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 1174 "First entry in donau_urls is not a string\n"); 1175 TALER_TESTING_FAIL (is); 1176 } 1177 1178 ps->donau_data.donau_url = GNUNET_strdup (donau_url_str); 1179 1180 if (NULL != ps->donau_data.charity_reference) 1181 { 1182 switch (prepare_donau_data (is, 1183 &ps->donau_data)) 1184 { 1185 case GNUNET_OK: 1186 break; 1187 case GNUNET_NO: 1188 TALER_TESTING_interpreter_next (ps->is); 1189 return; 1190 case GNUNET_SYSERR: 1191 TALER_TESTING_FAIL (is); 1192 return; 1193 } 1194 ps->num_donau_tokens = ps->donau_data.num_bkps; 1195 } 1196 } 1197 } 1198 1199 if (0 == strcmp ("token", 1200 kind)) 1201 { 1202 struct GNUNET_JSON_Specification ispec[] = { 1203 GNUNET_JSON_spec_string ("token_family_slug", 1204 &slug), 1205 GNUNET_JSON_spec_uint32 ("key_index", 1206 &key_index), 1207 GNUNET_JSON_spec_mark_optional ( 1208 GNUNET_JSON_spec_uint32 ("count", 1209 &count), 1210 NULL), 1211 GNUNET_JSON_spec_end () 1212 }; 1213 1214 if (GNUNET_OK != 1215 GNUNET_JSON_parse (output, 1216 ispec, 1217 &ierror_name, 1218 &ierror_line)) 1219 { 1220 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 1221 "Parser failed on %s:%u for input `%s'\n", 1222 ierror_name, 1223 ierror_line, 1224 json_dumps (output, 1225 JSON_INDENT (2))); 1226 TALER_TESTING_FAIL (is); 1227 } 1228 1229 if (0 != strcmp ("token", 1230 kind)) 1231 { 1232 continue; 1233 } 1234 1235 GNUNET_array_grow ( 1236 ps->issued_tokens, 1237 ps->num_issued_tokens, 1238 ps->num_issued_tokens + count + ps->num_donau_tokens); 1239 1240 for (unsigned int k = 0; k < count; k++) 1241 { 1242 struct TALER_MERCHANT_PrivateTokenDetails *details = 1243 &ps->issued_tokens[ps->num_issued_tokens - count + k 1244 + ps->num_donau_tokens]; 1245 1246 if (GNUNET_OK != 1247 find_token_public_key (token_families, 1248 slug, 1249 key_index, 1250 &details->issue_pub)) 1251 { 1252 TALER_TESTING_FAIL (is); 1253 } 1254 1255 /* Only RSA is supported for now. */ 1256 GNUNET_assert (GNUNET_CRYPTO_BSA_RSA == 1257 details->issue_pub.public_key->cipher); 1258 1259 TALER_token_blind_input_copy (&details->blinding_inputs, 1260 TALER_token_blind_input_rsa_singleton () 1261 ); 1262 /* FIXME: Where to get details->blinding_inputs from? */ 1263 TALER_token_use_setup_random (&details->master); 1264 TALER_token_use_setup_priv (&details->master, 1265 &details->blinding_inputs, 1266 &details->token_priv); 1267 TALER_token_use_blinding_secret_create (&details->master, 1268 &details->blinding_inputs, 1269 &details->blinding_secret) 1270 ; 1271 GNUNET_CRYPTO_eddsa_key_get_public ( 1272 &details->token_priv.private_key, 1273 &details->token_pub.public_key); 1274 GNUNET_CRYPTO_hash (&details->token_pub.public_key, 1275 sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey), 1276 &details->h_token_pub.hash); 1277 details->envelope.blinded_pub = 1278 GNUNET_CRYPTO_message_blind_to_sign 1279 ( 1280 details->issue_pub.public_key, 1281 &details->blinding_secret, 1282 NULL, /* FIXME: Add session nonce to support CS tokens */ 1283 &details->h_token_pub.hash, 1284 sizeof (details->h_token_pub.hash), 1285 details->blinding_inputs.blinding_inputs); 1286 1287 if (NULL == details->envelope.blinded_pub) 1288 { 1289 GNUNET_break (0); 1290 TALER_TESTING_FAIL (is); 1291 } 1292 } 1293 } 1294 } 1295 } 1296 1297 break; 1298 default: 1299 TALER_TESTING_FAIL (is); 1300 } 1301 } 1302 1303 { 1304 char *cr; 1305 1306 cr = GNUNET_strdup (ps->coin_reference); 1307 pay_coins = NULL; 1308 npay_coins = 0; 1309 if (GNUNET_OK != 1310 build_coins (&pay_coins, 1311 &npay_coins, 1312 cr, 1313 is, 1314 ps->amount_with_fee, 1315 ps->amount_without_fee)) 1316 { 1317 GNUNET_array_grow (pay_coins, 1318 npay_coins, 1319 0); 1320 GNUNET_free (cr); 1321 TALER_TESTING_FAIL (is); 1322 } 1323 GNUNET_free (cr); 1324 } 1325 if (NULL != ps->token_reference) 1326 { 1327 char *tr; 1328 1329 tr = GNUNET_strdup (ps->token_reference); 1330 if (GNUNET_OK != 1331 build_tokens (&use_tokens, 1332 &len_use_tokens, 1333 tr, 1334 is)) 1335 { 1336 GNUNET_array_grow (use_tokens, 1337 len_use_tokens, 1338 0); 1339 GNUNET_free (tr); 1340 TALER_TESTING_FAIL (is); 1341 } 1342 GNUNET_free (tr); 1343 } 1344 1345 GNUNET_array_grow (output_tokens, 1346 len_output_tokens, 1347 ps->num_issued_tokens); 1348 for (unsigned int i = 0; i<len_output_tokens; i++) 1349 { 1350 output_tokens[i].envelope.blinded_pub 1351 = ps->issued_tokens[i].envelope.blinded_pub; 1352 } 1353 1354 if (GNUNET_OK != 1355 TALER_TESTING_get_trait_merchant_sig (proposal_cmd, 1356 &merchant_sig)) 1357 TALER_TESTING_FAIL (is); 1358 1359 if (GNUNET_OK != 1360 TALER_TESTING_get_trait_h_contract_terms (proposal_cmd, 1361 &h_proposal)) 1362 TALER_TESTING_FAIL (is); 1363 ps->h_contract_terms = *h_proposal; 1364 1365 /* New logic of setting pay params */ 1366 { 1367 struct GNUNET_CURL_Context *ctx = 1368 TALER_TESTING_interpreter_get_context (is); 1369 1370 ps->oph = TALER_MERCHANT_post_orders_pay_create (ctx, 1371 ps->merchant_url, 1372 order_id, 1373 h_proposal, 1374 &ps->total_amount, 1375 &max_fee, 1376 &merchant_pub, 1377 merchant_sig, 1378 timestamp, 1379 refund_deadline, 1380 pay_deadline, 1381 &h_wire, 1382 npay_coins, 1383 pay_coins); 1384 1385 if (NULL == ps->oph) 1386 TALER_TESTING_FAIL (is); 1387 if (0 <= ps->choice_index) 1388 GNUNET_assert ( 1389 GNUNET_OK == 1390 TALER_MERCHANT_post_orders_pay_set_options ( 1391 ps->oph, 1392 TALER_MERCHANT_post_orders_pay_option_choice_index ( 1393 ps->choice_index))); 1394 if (NULL != ps->session_id) 1395 GNUNET_assert ( 1396 GNUNET_OK == 1397 TALER_MERCHANT_post_orders_pay_set_options ( 1398 ps->oph, 1399 TALER_MERCHANT_post_orders_pay_option_session_id ( 1400 ps->session_id))); 1401 1402 if (len_use_tokens > 0) 1403 GNUNET_assert ( 1404 GNUNET_OK == 1405 TALER_MERCHANT_post_orders_pay_set_options ( 1406 ps->oph, 1407 TALER_MERCHANT_post_orders_pay_option_use_tokens ( 1408 len_use_tokens, 1409 use_tokens))); 1410 if (len_output_tokens > 0) 1411 GNUNET_assert ( 1412 GNUNET_OK == 1413 TALER_MERCHANT_post_orders_pay_set_options ( 1414 ps->oph, 1415 TALER_MERCHANT_post_orders_pay_option_output_tokens ( 1416 len_output_tokens, 1417 output_tokens))); 1418 1419 if (ps->donau_data.charity_reference) 1420 { 1421 GNUNET_assert ( 1422 GNUNET_OK == 1423 TALER_MERCHANT_post_orders_pay_set_options ( 1424 ps->oph, 1425 TALER_MERCHANT_post_orders_pay_option_output_donau ( 1426 ps->donau_data.donau_url, 1427 ps->donau_data.year, 1428 ps->donau_data.num_bkps, 1429 ps->donau_data.bkps))); 1430 } 1431 if (TALER_EC_NONE != 1432 TALER_MERCHANT_post_orders_pay_start (ps->oph, 1433 &pay_cb, 1434 ps)) 1435 TALER_TESTING_FAIL (is); 1436 } 1437 1438 GNUNET_array_grow (pay_coins, 1439 npay_coins, 1440 0); 1441 1442 GNUNET_array_grow (use_tokens, 1443 len_use_tokens, 1444 0); 1445 1446 GNUNET_array_grow (output_tokens, 1447 len_output_tokens, 1448 0); 1449 } 1450 1451 1452 /** 1453 * Free a "pay" CMD, and cancel it if need be. 1454 * 1455 * @param cls closure. 1456 * @param cmd command currently being freed. 1457 */ 1458 static void 1459 pay_cleanup (void *cls, 1460 const struct TALER_TESTING_Command *cmd) 1461 { 1462 struct PayState *ps = cls; 1463 1464 if (NULL != ps->oph) 1465 { 1466 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 1467 "Command `%s' did not complete.\n", 1468 TALER_TESTING_interpreter_get_current_label ( 1469 ps->is)); 1470 TALER_MERCHANT_post_orders_pay_cancel (ps->oph); 1471 } 1472 1473 GNUNET_free (ps); 1474 } 1475 1476 1477 /** 1478 * Offer internal data useful to other commands. 1479 * 1480 * @param cls closure 1481 * @param[out] ret result 1482 * @param trait name of the trait 1483 * @param index index number of the object to extract. 1484 * @return #GNUNET_OK on success 1485 */ 1486 static enum GNUNET_GenericReturnValue 1487 pay_traits (void *cls, 1488 const void **ret, 1489 const char *trait, 1490 unsigned int index) 1491 { 1492 1493 struct PayState *ps = cls; 1494 const char *order_id; 1495 const struct TALER_TESTING_Command *proposal_cmd; 1496 const struct TALER_MerchantPublicKeyP *merchant_pub; 1497 1498 if (NULL != ps->token_reference && 1499 index >= ps->num_issued_tokens) 1500 { 1501 GNUNET_break (0); 1502 return GNUNET_NO; 1503 } 1504 1505 if (NULL == 1506 (proposal_cmd = 1507 TALER_TESTING_interpreter_lookup_command (ps->is, 1508 ps->proposal_reference))) 1509 { 1510 GNUNET_break (0); 1511 return GNUNET_SYSERR; 1512 } 1513 1514 if (GNUNET_OK != 1515 TALER_TESTING_get_trait_order_id (proposal_cmd, 1516 &order_id)) 1517 { 1518 GNUNET_break (0); 1519 return GNUNET_SYSERR; 1520 } 1521 1522 if (GNUNET_OK != 1523 TALER_TESTING_get_trait_merchant_pub (proposal_cmd, 1524 &merchant_pub)) 1525 { 1526 GNUNET_break (0); 1527 return GNUNET_SYSERR; 1528 } 1529 { 1530 struct TALER_Amount amount_with_fee; 1531 1532 GNUNET_assert (GNUNET_OK == 1533 TALER_string_to_amount (ps->amount_with_fee, 1534 &amount_with_fee)); 1535 { 1536 struct TALER_TESTING_Trait traits[] = { 1537 TALER_TESTING_make_trait_proposal_reference (ps->proposal_reference), 1538 TALER_TESTING_make_trait_coin_reference (0, 1539 ps->coin_reference), 1540 TALER_TESTING_make_trait_order_id (order_id), 1541 TALER_TESTING_make_trait_merchant_pub (merchant_pub), 1542 TALER_TESTING_make_trait_merchant_sig (&ps->merchant_sig), 1543 TALER_TESTING_make_trait_amount (&amount_with_fee), 1544 TALER_TESTING_make_trait_otp_key (ps->pos_key), 1545 TALER_TESTING_make_trait_otp_alg (&ps->pos_alg), 1546 TALER_TESTING_make_trait_token_priv (index, 1547 &ps->issued_tokens[index]. 1548 token_priv), 1549 TALER_TESTING_make_trait_token_issue_pub (index, 1550 &ps->issued_tokens[index]. 1551 issue_pub), 1552 TALER_TESTING_make_trait_token_issue_sig (index, 1553 &ps->issued_tokens[index]. 1554 issue_sig), 1555 TALER_TESTING_trait_end () 1556 }; 1557 1558 return TALER_TESTING_get_trait (traits, 1559 ret, 1560 trait, 1561 index); 1562 } 1563 } 1564 } 1565 1566 1567 struct TALER_TESTING_Command 1568 TALER_TESTING_cmd_merchant_pay_order_choices ( 1569 const char *label, 1570 const char *merchant_url, 1571 unsigned int http_status, 1572 const char *proposal_reference, 1573 const char *coin_reference, 1574 const char *amount_with_fee, 1575 const char *amount_without_fee, 1576 const char *session_id, 1577 int choice_index, 1578 const char *token_reference) 1579 { 1580 struct PayState *ps; 1581 1582 ps = GNUNET_new (struct PayState); 1583 ps->http_status = http_status; 1584 ps->proposal_reference = proposal_reference; 1585 ps->coin_reference = coin_reference; 1586 ps->merchant_url = merchant_url; 1587 ps->amount_with_fee = amount_with_fee; 1588 ps->amount_without_fee = amount_without_fee; 1589 ps->session_id = session_id; 1590 ps->token_reference = token_reference; 1591 ps->choice_index = choice_index; 1592 { 1593 struct TALER_TESTING_Command cmd = { 1594 .cls = ps, 1595 .label = label, 1596 .run = &pay_run, 1597 .cleanup = &pay_cleanup, 1598 .traits = &pay_traits 1599 }; 1600 1601 return cmd; 1602 } 1603 } 1604 1605 1606 struct TALER_TESTING_Command 1607 TALER_TESTING_cmd_merchant_pay_order_donau ( 1608 const char *label, 1609 const char *merchant_url, 1610 unsigned int http_status, 1611 const char *proposal_reference, 1612 const char *coin_reference, 1613 const char *amount_with_fee, 1614 const char *amount_without_fee, 1615 const char *amount_donation, 1616 const char *session_id, 1617 int choice_index, 1618 const char *charity_reference, 1619 uint64_t year, 1620 const char *donor_tax_id, 1621 const char *salt) 1622 { 1623 struct PayState *ps; 1624 1625 ps = GNUNET_new (struct PayState); 1626 ps->http_status = http_status; 1627 ps->proposal_reference = proposal_reference; 1628 ps->coin_reference = coin_reference; 1629 ps->merchant_url = merchant_url; 1630 ps->amount_with_fee = amount_with_fee; 1631 ps->amount_without_fee = amount_without_fee; 1632 ps->session_id = session_id; 1633 ps->token_reference = NULL; 1634 ps->choice_index = choice_index; 1635 ps->donau_data.year = year; 1636 ps->donau_data.num_bkps = 5; 1637 ps->donau_data.charity_reference = charity_reference; 1638 if (GNUNET_OK != 1639 TALER_string_to_amount (amount_donation, 1640 &ps->donau_data.donation_amount)) 1641 { 1642 GNUNET_assert (0); 1643 } 1644 1645 /* Compute h_donor_tax_id directly into ps->donau_data: */ 1646 if (! DONAU_compute_salted_tax_id_hash (donor_tax_id, 1647 salt, 1648 ps->donau_data.h_donor_tax_id.hash)) 1649 { 1650 GNUNET_assert (0); 1651 } 1652 1653 { 1654 struct TALER_TESTING_Command cmd = { 1655 .cls = ps, 1656 .label = label, 1657 .run = &pay_run, 1658 .cleanup = &pay_cleanup, 1659 .traits = &pay_traits 1660 }; 1661 1662 return cmd; 1663 } 1664 } 1665 1666 1667 struct TALER_TESTING_Command 1668 TALER_TESTING_cmd_merchant_pay_order ( 1669 const char *label, 1670 const char *merchant_url, 1671 unsigned int http_status, 1672 const char *proposal_reference, 1673 const char *coin_reference, 1674 const char *amount_with_fee, 1675 const char *amount_without_fee, 1676 const char *session_id) 1677 { 1678 return TALER_TESTING_cmd_merchant_pay_order_choices ( 1679 label, 1680 merchant_url, 1681 http_status, 1682 proposal_reference, 1683 coin_reference, 1684 amount_with_fee, 1685 amount_without_fee, 1686 session_id, 1687 -1, 1688 NULL); 1689 } 1690 1691 1692 /* end of testing_api_cmd_pay_order.c */