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