taler-merchant-httpd_post-orders-ORDER_ID-pay.c (172737B)
1 /* 2 This file is part of TALER 3 (C) 2014-2026 Taler Systems SA 4 5 TALER is free software; you can redistribute it and/or modify 6 it under the terms of the GNU Affero General Public License as 7 published by the Free Software Foundation; either version 3, 8 or (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, 17 see <http://www.gnu.org/licenses/> 18 */ 19 20 /** 21 * @file src/backend/taler-merchant-httpd_post-orders-ORDER_ID-pay.c 22 * @brief handling of POST /orders/$ID/pay requests 23 * @author Marcello Stanisci 24 * @author Christian Grothoff 25 * @author Florian Dold 26 */ 27 #include "platform.h" 28 struct ExchangeGroup; 29 #define TALER_EXCHANGE_POST_BATCH_DEPOSIT_RESULT_CLOSURE struct ExchangeGroup 30 #include <gnunet/gnunet_common.h> 31 #include <gnunet/gnunet_db_lib.h> 32 #include <gnunet/gnunet_json_lib.h> 33 #include <gnunet/gnunet_time_lib.h> 34 #include <jansson.h> 35 #include <microhttpd.h> 36 #include <stddef.h> 37 #include <stdint.h> 38 #include <string.h> 39 #include <taler/taler_dbevents.h> 40 #include <taler/taler_error_codes.h> 41 #include <taler/taler_signatures.h> 42 #include <taler/taler_json_lib.h> 43 #include <taler/taler_exchange_service.h> 44 #include "taler-merchant-httpd.h" 45 #include "taler-merchant-httpd_exchanges.h" 46 #include "taler-merchant-httpd_get-exchanges.h" 47 #include "taler-merchant-httpd_helper.h" 48 #include "taler-merchant-httpd_post-orders-ORDER_ID-pay.h" 49 #include "taler-merchant-httpd_get-private-orders.h" 50 #include "taler/taler_merchant_util.h" 51 #include "merchantdb_lib.h" 52 #include <donau/donau_service.h> 53 #include <donau/donau_util.h> 54 #include <donau/donau_json_lib.h> 55 #include "merchant-database/update_money_pot_totals.h" 56 #include "merchant-database/insert_deposit.h" 57 #include "merchant-database/insert_deposit_confirmation.h" 58 #include "merchant-database/insert_issued_token.h" 59 #include "merchant-database/insert_order_token_blinded_sig.h" 60 #include "merchant-database/insert_used_token.h" 61 #include "merchant-database/get_contract_terms_pos.h" 62 #include "merchant-database/iterate_deposits.h" 63 #include "merchant-database/iterate_deposits_by_order.h" 64 #include "merchant-database/get_donau_instance_by_url.h" 65 #include "merchant-database/iterate_refunds.h" 66 #include "merchant-database/set_instance.h" 67 #include "merchant-database/iterate_used_tokens_by_order.h" 68 #include "merchant-database/get_token_family_key.h" 69 #include "merchant-database/update_to_contract_terms_paid.h" 70 #include "merchant-database/iterate_order_token_blinded_sigs.h" 71 #include "merchant-database/start.h" 72 #include "merchant-database/preflight.h" 73 #include "merchant-database/event_notify.h" 74 #include "merchant-database/update_donau_instance_receipts_amount.h" 75 76 /** 77 * How often do we retry the (complex!) database transaction? 78 */ 79 #define MAX_RETRIES 5 80 81 /** 82 * Maximum number of coins that we allow per transaction. 83 * Note that the limit for each batch deposit request to 84 * the exchange is lower, so we may break a very large 85 * number of coins up into multiple smaller requests to 86 * the exchange. 87 */ 88 #define MAX_COIN_ALLOWED_COINS 1024 89 90 /** 91 * Maximum number of tokens that we allow as inputs per transaction 92 */ 93 #define MAX_TOKEN_ALLOWED_INPUTS 64 94 95 /** 96 * Maximum number of tokens that we allow as outputs per transaction 97 */ 98 #define MAX_TOKEN_ALLOWED_OUTPUTS 64 99 100 /** 101 * How often do we ask the exchange again about our 102 * KYC status? Very rarely, as if the user actively 103 * changes it, we should usually notice anyway. 104 */ 105 #define KYC_RETRY_FREQUENCY GNUNET_TIME_UNIT_WEEKS 106 107 /** 108 * Information we keep for an individual call to the pay handler. 109 */ 110 struct PayContext; 111 112 113 /** 114 * Different phases of processing the /pay request. 115 */ 116 enum PayPhase 117 { 118 /** 119 * Initial phase where the request is parsed. 120 */ 121 PP_PARSE_PAY = 0, 122 123 /** 124 * Parse wallet data object from the pay request. 125 */ 126 PP_PARSE_WALLET_DATA, 127 128 /** 129 * Check database state for the given order. 130 */ 131 PP_CHECK_CONTRACT, 132 133 /** 134 * Validate provided tokens and token envelopes. 135 */ 136 PP_VALIDATE_TOKENS, 137 138 /** 139 * Check if contract has been paid. 140 */ 141 PP_CONTRACT_PAID, 142 143 /** 144 * Compute money pot changes. 145 */ 146 PP_COMPUTE_MONEY_POTS, 147 148 /** 149 * Execute payment transaction. 150 */ 151 PP_PAY_TRANSACTION, 152 153 /** 154 * Communicate with DONAU to generate a donation receipt from the donor BUDIs. 155 */ 156 PP_REQUEST_DONATION_RECEIPT, 157 158 /** 159 * Process the donation receipt response from DONAU (save the donau_sigs to the db). 160 */ 161 PP_FINAL_OUTPUT_TOKEN_PROCESSING, 162 163 /** 164 * Notify other processes about successful payment. 165 */ 166 PP_PAYMENT_NOTIFICATION, 167 168 /** 169 * Create final success response. 170 */ 171 PP_SUCCESS_RESPONSE, 172 173 /** 174 * Perform batch deposits with exchange(s). 175 */ 176 PP_BATCH_DEPOSITS, 177 178 /** 179 * Return response in payment context. 180 */ 181 PP_RETURN_RESPONSE, 182 183 /** 184 * An exchange denied a deposit, fail for 185 * legal reasons. 186 */ 187 PP_FAIL_LEGAL_REASONS, 188 189 /** 190 * Return #MHD_YES to end processing. 191 */ 192 PP_END_YES, 193 194 /** 195 * Return #MHD_NO to end processing. 196 */ 197 PP_END_NO 198 }; 199 200 201 /** 202 * Information kept during a pay request for each coin. 203 */ 204 struct DepositConfirmation 205 { 206 207 /** 208 * Reference to the main PayContext 209 */ 210 struct PayContext *pc; 211 212 /** 213 * URL of the exchange that issued this coin. 214 */ 215 char *exchange_url; 216 217 /** 218 * Details about the coin being deposited. 219 */ 220 struct TALER_EXCHANGE_CoinDepositDetail cdd; 221 222 /** 223 * Fee charged by the exchange for the deposit operation of this coin. 224 */ 225 struct TALER_Amount deposit_fee; 226 227 /** 228 * Fee charged by the exchange for the refund operation of this coin. 229 */ 230 struct TALER_Amount refund_fee; 231 232 /** 233 * Fee charged by the exchange for the wire transfer. 234 */ 235 struct TALER_Amount wire_fee; 236 237 /** 238 * If a minimum age was required (i. e. pc->minimum_age is large enough), 239 * this is the signature of the minimum age (as a single uint8_t), using the 240 * private key to the corresponding age group. Might be all zeroes for no 241 * age attestation. 242 */ 243 struct TALER_AgeAttestationP minimum_age_sig; 244 245 /** 246 * If a minimum age was required (i. e. pc->minimum_age is large enough), 247 * this is the age commitment (i. e. age mask and vector of EdDSA public 248 * keys, one per age group) that went into the mining of the coin. The 249 * SHA256 hash of the mask and the vector of public keys was bound to the 250 * key. 251 */ 252 struct TALER_AgeCommitment age_commitment; 253 254 /** 255 * Age mask in the denomination that defines the age groups. Only 256 * applicable, if minimum age was required. 257 */ 258 struct TALER_AgeMask age_mask; 259 260 /** 261 * Offset of this coin into the `dc` array of all coins in the 262 * @e pc. 263 */ 264 unsigned int index; 265 266 /** 267 * true, if no field "age_commitment" was found in the JSON blob 268 */ 269 bool no_age_commitment; 270 271 /** 272 * True, if no field "minimum_age_sig" was found in the JSON blob 273 */ 274 bool no_minimum_age_sig; 275 276 /** 277 * true, if no field "h_age_commitment" was found in the JSON blob 278 */ 279 bool no_h_age_commitment; 280 281 /** 282 * true if we found this coin in the database. 283 */ 284 bool found_in_db; 285 286 /** 287 * true if we #deposit_paid_check() matched this coin in the database. 288 */ 289 bool matched_in_db; 290 291 /** 292 * True if this coin is in the current batch. 293 */ 294 bool in_batch; 295 296 }; 297 298 struct TokenUseConfirmation 299 { 300 301 /** 302 * Signature on the deposit request made using the token use private key. 303 */ 304 struct TALER_TokenUseSignatureP sig; 305 306 /** 307 * Token use public key. This key was blindly signed by the merchant during 308 * the token issuance process. 309 */ 310 struct TALER_TokenUsePublicKeyP pub; 311 312 /** 313 * Unblinded signature on the token use public key done by the merchant. 314 */ 315 struct TALER_TokenIssueSignature unblinded_sig; 316 317 /** 318 * Hash of the token issue public key associated with this token. 319 * Note this is set in the validate_tokens phase. 320 */ 321 struct TALER_TokenIssuePublicKeyHashP h_issue; 322 323 /** 324 * true if we found this token in the database. 325 */ 326 bool found_in_db; 327 328 }; 329 330 331 /** 332 * Information about a token envelope. 333 */ 334 struct TokenEnvelope 335 { 336 337 /** 338 * Blinded token use public keys waiting to be signed. 339 */ 340 struct TALER_TokenEnvelope blinded_token; 341 342 }; 343 344 345 /** 346 * (Blindly) signed token to be returned to the wallet. 347 */ 348 struct SignedOutputToken 349 { 350 351 /** 352 * Index of the output token that produced this blindly signed token. 353 */ 354 unsigned int output_index; 355 356 /** 357 * Blinded token use public keys waiting to be signed. 358 */ 359 struct TALER_BlindedTokenIssueSignature sig; 360 361 /** 362 * Hash of token issue public key. 363 */ 364 struct TALER_TokenIssuePublicKeyHashP h_issue; 365 366 }; 367 368 369 /** 370 * Information kept during a pay request for each exchange. 371 */ 372 struct ExchangeGroup 373 { 374 375 /** 376 * Payment context this group is part of. 377 */ 378 struct PayContext *pc; 379 380 /** 381 * Handle to the batch deposit operation currently in flight for this 382 * exchange, NULL when no operation is pending. 383 */ 384 struct TALER_EXCHANGE_PostBatchDepositHandle *bdh; 385 386 /** 387 * Handle for operation to lookup /keys (and auditors) from 388 * the exchange used for this transaction; NULL if no operation is 389 * pending. 390 */ 391 struct TMH_EXCHANGES_KeysOperation *fo; 392 393 /** 394 * URL of the exchange that issued this coin. Aliases 395 * the exchange URL of one of the coins, do not free! 396 */ 397 const char *exchange_url; 398 399 /** 400 * The keys of the exchange. 401 */ 402 struct TALER_EXCHANGE_Keys *keys; 403 404 /** 405 * Total deposit amount in this exchange group. 406 */ 407 struct TALER_Amount total; 408 409 /** 410 * Wire fee that applies to this exchange for the 411 * given payment context's wire method. 412 */ 413 struct TALER_Amount wire_fee; 414 415 /** 416 * true if we already tried a forced /keys download. 417 */ 418 bool tried_force_keys; 419 420 /** 421 * Did this exchange deny the transaction for legal reasons? 422 */ 423 bool got_451; 424 }; 425 426 427 /** 428 * Information about donau, that can be fetched even 429 * if the merhchant doesn't support donau 430 */ 431 struct DonauData 432 { 433 /** 434 * The user-selected Donau URL. 435 */ 436 char *donau_url; 437 438 /** 439 * The donation year, as parsed from "year". 440 */ 441 uint64_t donation_year; 442 443 /** 444 * The original BUDI key-pairs array from the donor 445 * to be used for the receipt creation. 446 */ 447 const json_t *budikeypairs; 448 }; 449 450 /** 451 * Information we keep for an individual call to the /pay handler. 452 */ 453 struct PayContext 454 { 455 456 /** 457 * Stored in a DLL. 458 */ 459 struct PayContext *next; 460 461 /** 462 * Stored in a DLL. 463 */ 464 struct PayContext *prev; 465 466 /** 467 * MHD connection to return to 468 */ 469 struct MHD_Connection *connection; 470 471 /** 472 * Details about the client's request. 473 */ 474 struct TMH_HandlerContext *hc; 475 476 /** 477 * Transaction ID given in @e root. 478 */ 479 const char *order_id; 480 481 /** 482 * Response to return, NULL if we don't have one yet. 483 */ 484 struct MHD_Response *response; 485 486 /** 487 * Array with @e output_tokens_len signed tokens returned in 488 * the response to the wallet. This array combines both the 489 * token family-signed outputs and the donation authority 490 * outputs. Each output has a field ``output_index`` 491 * which matches the index into the choice's outputs array. 492 * The Donau outputs are those where the `output_index` matches 493 * the @e validate_tokens.donau_output_index. 494 */ 495 struct SignedOutputToken *output_tokens; 496 497 /** 498 * Number of output tokens to return in the response. 499 * Length of the @e output_tokens array. 500 */ 501 unsigned int output_tokens_len; 502 503 /** 504 * Counter used to generate the output index in append_output_token_sig(). 505 */ 506 unsigned int output_index_gen; 507 508 /** 509 * Counter used to generate the output index in append_output_token_sig(). 510 * 511 * Counts the generated tokens _within_ the current output_index_gen. 512 */ 513 unsigned int output_token_cnt; 514 515 /** 516 * HTTP status code to use for the reply, i.e 200 for "OK". 517 * Special value UINT_MAX is used to indicate hard errors 518 * (no reply, return #MHD_NO). 519 */ 520 unsigned int response_code; 521 522 /** 523 * Payment processing phase we are in. 524 */ 525 enum PayPhase phase; 526 527 /** 528 * #GNUNET_NO if the @e connection was not suspended, 529 * #GNUNET_YES if the @e connection was suspended, 530 * #GNUNET_SYSERR if @e connection was resumed to as 531 * part of #MH_force_pc_resume during shutdown. 532 */ 533 enum GNUNET_GenericReturnValue suspended; 534 535 /** 536 * Results from the phase_parse_pay() 537 */ 538 struct 539 { 540 541 /** 542 * Array with @e num_exchanges exchanges we are depositing 543 * coins into. 544 */ 545 struct ExchangeGroup **egs; 546 547 /** 548 * Array with @e coins_cnt coins we are despositing. 549 */ 550 struct DepositConfirmation *dc; 551 552 /** 553 * Array with @e tokens_cnt input tokens passed to this request. 554 */ 555 struct TokenUseConfirmation *tokens; 556 557 /** 558 * Optional session id given in @e root. 559 * NULL if not given. 560 */ 561 char *session_id; 562 563 /** 564 * Wallet data json object from the request. Containing additional 565 * wallet data such as the selected choice_index. 566 */ 567 const json_t *wallet_data; 568 569 /** 570 * Number of coins this payment is made of. Length 571 * of the @e dc array. 572 */ 573 size_t coins_cnt; 574 575 /** 576 * Number of input tokens passed to this request. Length 577 * of the @e tokens array. 578 */ 579 size_t tokens_cnt; 580 581 /** 582 * Number of exchanges involved in the payment. Length 583 * of the @e eg array. 584 */ 585 unsigned int num_exchanges; 586 587 } parse_pay; 588 589 /** 590 * Results from the phase_wallet_data() 591 */ 592 struct 593 { 594 595 /** 596 * Array with @e token_envelopes_cnt (blinded) token envelopes. 597 */ 598 struct TokenEnvelope *token_envelopes; 599 600 /** 601 * Index of selected choice in the @e contract_terms choices array. 602 */ 603 int16_t choice_index; 604 605 /** 606 * Number of token envelopes passed to this request. 607 * Length of the @e token_envelopes array. 608 */ 609 size_t token_envelopes_cnt; 610 611 /** 612 * Hash of the canonicalized wallet data json object. 613 */ 614 struct GNUNET_HashCode h_wallet_data; 615 616 /** 617 * Donau related information 618 */ 619 struct DonauData donau; 620 621 /** 622 * Serial from the DB of the donau instance that we are using 623 */ 624 uint64_t donau_instance_serial; 625 626 /** 627 * Number of the blinded key pairs @e bkps 628 */ 629 unsigned int num_bkps; 630 631 /** 632 * Blinded key pairs received from the wallet 633 */ 634 struct DONAU_BlindedUniqueDonorIdentifierKeyPair *bkps; 635 636 /** 637 * The id of the charity as saved on the donau. 638 */ 639 uint64_t charity_id; 640 641 /** 642 * Private key of the charity(related to the private key of the merchant). 643 */ 644 struct DONAU_CharityPrivateKeyP charity_priv; 645 646 /** 647 * Maximum amount of donations that the charity can receive per year. 648 */ 649 struct TALER_Amount charity_max_per_year; 650 651 /** 652 * Amount of donations that the charity has received so far this year. 653 */ 654 struct TALER_Amount charity_receipts_to_date; 655 656 /** 657 * Donau keys, that we are using to get the information about the bkps. 658 */ 659 struct DONAU_Keys *donau_keys; 660 661 /** 662 * Amount from BKPS 663 */ 664 struct TALER_Amount donation_amount; 665 666 } parse_wallet_data; 667 668 /** 669 * Results from the phase_check_contract() 670 */ 671 struct 672 { 673 674 /** 675 * Hashed @e contract_terms. 676 */ 677 struct TALER_PrivateContractHashP h_contract_terms; 678 679 /** 680 * Our contract (or NULL if not available). 681 */ 682 json_t *contract_terms_json; 683 684 /** 685 * Parsed contract terms, NULL when parsing failed. 686 */ 687 struct TALER_MERCHANT_Contract *contract_terms; 688 689 /** 690 * What wire method (of the @e mi) was selected by the wallet? 691 * Set in #phase_parse_pay(). 692 */ 693 struct TMH_WireMethod *wm; 694 695 /** 696 * Set to the POS key, if applicable for this order. 697 */ 698 char *pos_key; 699 700 /** 701 * Serial number of this order in the database (set once we did the lookup). 702 */ 703 uint64_t order_serial; 704 705 /** 706 * Algorithm chosen for generating the confirmation code. 707 */ 708 enum TALER_MerchantConfirmationAlgorithm pos_alg; 709 710 } check_contract; 711 712 /** 713 * Results from the phase_validate_tokens() 714 */ 715 struct 716 { 717 718 /** 719 * Maximum fee the merchant is willing to pay, from @e root. 720 * Note that IF the total fee of the exchange is higher, that is 721 * acceptable to the merchant if the customer is willing to 722 * pay the difference 723 * (i.e. amount - max_fee <= actual_amount - actual_fee). 724 */ 725 struct TALER_Amount max_fee; 726 727 /** 728 * Amount from @e root. This is the amount the merchant expects 729 * to make, minus @e max_fee. 730 */ 731 struct TALER_Amount brutto; 732 733 /** 734 * Index of the donau output in the list of tokens. 735 * Set to -1 if no donau output exists. 736 */ 737 int donau_output_index; 738 739 } validate_tokens; 740 741 742 struct 743 { 744 /** 745 * Length of the @a pots and @a increments arrays. 746 */ 747 unsigned int num_pots; 748 749 /** 750 * Serial IDs of money pots to increment. 751 */ 752 uint64_t *pots; 753 754 /** 755 * Increment for the respective money pot. 756 */ 757 struct TALER_Amount *increments; 758 759 /** 760 * True if the money pots have already been computed. 761 */ 762 bool pots_computed; 763 764 } compute_money_pots; 765 766 /** 767 * Results from the phase_execute_pay_transaction() 768 */ 769 struct 770 { 771 772 /** 773 * Considering all the coins with the "found_in_db" flag 774 * set, what is the total amount we were so far paid on 775 * this contract? 776 */ 777 struct TALER_Amount total_paid; 778 779 /** 780 * Considering all the coins with the "found_in_db" flag 781 * set, what is the total amount we had to pay in deposit 782 * fees so far on this contract? 783 */ 784 struct TALER_Amount total_fees_paid; 785 786 /** 787 * Considering all the coins with the "found_in_db" flag 788 * set, what is the total amount we already refunded? 789 */ 790 struct TALER_Amount total_refunded; 791 792 /** 793 * Number of coin deposits pending. 794 */ 795 unsigned int pending; 796 797 /** 798 * How often have we retried the 'main' transaction? 799 */ 800 unsigned int retry_counter; 801 802 /** 803 * Set to true if the deposit currency of a coin 804 * does not match the contract currency. 805 */ 806 bool deposit_currency_mismatch; 807 808 /** 809 * Set to true if the database contains a (bogus) 810 * refund for a different currency. 811 */ 812 bool refund_currency_mismatch; 813 814 } pay_transaction; 815 816 /** 817 * Results from the phase_batch_deposits() 818 */ 819 struct 820 { 821 822 /** 823 * Task called when the (suspended) processing for 824 * the /pay request times out. 825 * Happens when we don't get a response from the exchange. 826 */ 827 struct GNUNET_SCHEDULER_Task *timeout_task; 828 829 /** 830 * Number of batch transactions pending. 831 */ 832 unsigned int pending_at_eg; 833 834 /** 835 * Did any exchange deny a deposit for legal reasons? 836 */ 837 bool got_451; 838 839 } batch_deposits; 840 841 /** 842 * Struct for #phase_request_donation_receipt() 843 */ 844 struct 845 { 846 /** 847 * Handler of the donau request 848 */ 849 struct DONAU_BatchIssueReceiptHandle *birh; 850 851 } donau_receipt; 852 }; 853 854 855 /** 856 * Head of active pay context DLL. 857 */ 858 static struct PayContext *pc_head; 859 860 /** 861 * Tail of active pay context DLL. 862 */ 863 static struct PayContext *pc_tail; 864 865 866 void 867 TMH_force_pc_resume () 868 { 869 for (struct PayContext *pc = pc_head; 870 NULL != pc; 871 pc = pc->next) 872 { 873 if (NULL != pc->batch_deposits.timeout_task) 874 { 875 GNUNET_SCHEDULER_cancel (pc->batch_deposits.timeout_task); 876 pc->batch_deposits.timeout_task = NULL; 877 } 878 if (GNUNET_YES == pc->suspended) 879 { 880 pc->suspended = GNUNET_SYSERR; 881 MHD_resume_connection (pc->connection); 882 } 883 } 884 } 885 886 887 /** 888 * Resume payment processing. 889 * 890 * @param[in,out] pc payment process to resume 891 */ 892 static void 893 pay_resume (struct PayContext *pc) 894 { 895 GNUNET_assert (GNUNET_YES == pc->suspended); 896 /* We only ever suspend while we interact with an exchange or the 897 Donau; thus, once we resume, the timeout for that interaction is 898 no longer relevant and MUST be cancelled: otherwise it could fire 899 after we already resumed (and possibly even after we queued the 900 response) and then hit the "GNUNET_YES == pc->suspended" assertion 901 in handle_pay_timeout(). */ 902 if (NULL != pc->batch_deposits.timeout_task) 903 { 904 GNUNET_SCHEDULER_cancel (pc->batch_deposits.timeout_task); 905 pc->batch_deposits.timeout_task = NULL; 906 } 907 pc->suspended = GNUNET_NO; 908 MHD_resume_connection (pc->connection); 909 TALER_MHD_daemon_trigger (); /* we resumed, kick MHD */ 910 } 911 912 913 /** 914 * Resume the given pay context and send the given response. 915 * Stores the response in the @a pc and signals MHD to resume 916 * the connection. Also ensures MHD runs immediately. 917 * 918 * @param pc payment context 919 * @param response_code response code to use 920 * @param response response data to send back 921 */ 922 static void 923 resume_pay_with_response (struct PayContext *pc, 924 unsigned int response_code, 925 struct MHD_Response *response) 926 { 927 pc->response_code = response_code; 928 pc->response = response; 929 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 930 "Resuming /pay handling. HTTP status for our reply is %u.\n", 931 response_code); 932 for (unsigned int i = 0; i<pc->parse_pay.num_exchanges; i++) 933 { 934 struct ExchangeGroup *eg = pc->parse_pay.egs[i]; 935 936 if (NULL != eg->fo) 937 { 938 TMH_EXCHANGES_keys4exchange_cancel (eg->fo); 939 eg->fo = NULL; 940 pc->batch_deposits.pending_at_eg--; 941 } 942 if (NULL != eg->bdh) 943 { 944 TALER_EXCHANGE_post_batch_deposit_cancel (eg->bdh); 945 eg->bdh = NULL; 946 pc->batch_deposits.pending_at_eg--; 947 } 948 } 949 GNUNET_assert (0 == pc->batch_deposits.pending_at_eg); 950 if (NULL != pc->batch_deposits.timeout_task) 951 { 952 GNUNET_SCHEDULER_cancel (pc->batch_deposits.timeout_task); 953 pc->batch_deposits.timeout_task = NULL; 954 } 955 pc->phase = PP_RETURN_RESPONSE; 956 pay_resume (pc); 957 } 958 959 960 /** 961 * Resume payment processing with an error. 962 * 963 * @param pc operation to resume 964 * @param ec taler error code to return 965 * @param msg human readable error message 966 */ 967 static void 968 resume_pay_with_error (struct PayContext *pc, 969 enum TALER_ErrorCode ec, 970 const char *msg) 971 { 972 resume_pay_with_response ( 973 pc, 974 TALER_ErrorCode_get_http_status_safe (ec), 975 TALER_MHD_make_error (ec, 976 msg)); 977 } 978 979 980 /** 981 * Conclude payment processing for @a pc with the 982 * given @a res MHD status code. 983 * 984 * @param[in,out] pc payment context for final state transition 985 * @param res MHD return code to end with 986 */ 987 static void 988 pay_end (struct PayContext *pc, 989 enum MHD_Result res) 990 { 991 pc->phase = (MHD_YES == res) 992 ? PP_END_YES 993 : PP_END_NO; 994 } 995 996 997 /** 998 * Return response stored in @a pc. 999 * 1000 * @param[in,out] pc payment context we are processing 1001 */ 1002 static void 1003 phase_return_response (struct PayContext *pc) 1004 { 1005 GNUNET_assert (0 != pc->response_code); 1006 /* We are *done* processing the request, just queue the response (!) */ 1007 if (UINT_MAX == pc->response_code) 1008 { 1009 GNUNET_break (0); 1010 pay_end (pc, 1011 MHD_NO); /* hard error */ 1012 return; 1013 } 1014 pay_end (pc, 1015 MHD_queue_response (pc->connection, 1016 pc->response_code, 1017 pc->response)); 1018 } 1019 1020 1021 /** 1022 * Return a response indicating failure for legal reasons. 1023 * 1024 * @param[in,out] pc payment context we are processing 1025 */ 1026 static void 1027 phase_fail_for_legal_reasons (struct PayContext *pc) 1028 { 1029 json_t *exchanges; 1030 1031 GNUNET_assert (0 == pc->pay_transaction.pending); 1032 GNUNET_assert (pc->batch_deposits.got_451); 1033 exchanges = json_array (); 1034 GNUNET_assert (NULL != exchanges); 1035 for (unsigned int i = 0; i<pc->parse_pay.num_exchanges; i++) 1036 { 1037 struct ExchangeGroup *eg = pc->parse_pay.egs[i]; 1038 1039 GNUNET_assert (NULL == eg->fo); 1040 GNUNET_assert (NULL == eg->bdh); 1041 if (! eg->got_451) 1042 continue; 1043 GNUNET_assert ( 1044 0 == 1045 json_array_append_new ( 1046 exchanges, 1047 json_string (eg->exchange_url))); 1048 } 1049 pay_end (pc, 1050 TALER_MHD_REPLY_JSON_PACK ( 1051 pc->connection, 1052 MHD_HTTP_UNAVAILABLE_FOR_LEGAL_REASONS, 1053 TALER_JSON_pack_ec ( 1054 TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_EXCHANGE_LEGALLY_REFUSED), 1055 GNUNET_JSON_pack_array_steal ("exchange_base_urls", 1056 exchanges))); 1057 } 1058 1059 1060 /** 1061 * Do database transaction for a completed batch deposit. 1062 * 1063 * @param eg group that completed 1064 * @param dr response from the server 1065 * @return transaction status 1066 */ 1067 static enum GNUNET_DB_QueryStatus 1068 batch_deposit_transaction ( 1069 const struct ExchangeGroup *eg, 1070 const struct TALER_EXCHANGE_PostBatchDepositResponse *dr) 1071 { 1072 const struct PayContext *pc = eg->pc; 1073 enum GNUNET_DB_QueryStatus qs; 1074 enum TALER_MERCHANTDB_DepositConfirmationStatus dcs; 1075 uint64_t b_dep_serial; 1076 uint32_t off = 0; 1077 1078 qs = TALER_MERCHANTDB_set_instance ( 1079 TMH_db, 1080 pc->hc->instance->settings.id); 1081 if (qs <= 0) 1082 return qs; /* failure, we're done */ 1083 dcs = TALER_MERCHANTDB_insert_deposit_confirmation ( 1084 TMH_db, 1085 pc->hc->instance->settings.id, 1086 dr->details.ok.deposit_timestamp, 1087 &pc->check_contract.h_contract_terms, 1088 eg->exchange_url, 1089 pc->check_contract.contract_terms->pc->wire_deadline, 1090 &dr->details.ok.accumulated_total_without_fee, 1091 &eg->wire_fee, 1092 &pc->check_contract.wm->h_wire, 1093 dr->details.ok.exchange_sig, 1094 dr->details.ok.exchange_pub, 1095 &b_dep_serial); 1096 switch (dcs) 1097 { 1098 case TALER_MERCHANTDB_DCS_SUCCESS: 1099 break; 1100 case TALER_MERCHANTDB_DCS_SOFT_ERROR: 1101 qs = GNUNET_DB_STATUS_SOFT_ERROR; 1102 goto cleanup; 1103 case TALER_MERCHANTDB_DCS_CONFLICT: 1104 case TALER_MERCHANTDB_DCS_NO_SIGNKEY: 1105 case TALER_MERCHANTDB_DCS_NO_ACCOUNT: 1106 case TALER_MERCHANTDB_DCS_NO_ORDER: 1107 case TALER_MERCHANTDB_DCS_HARD_ERROR: 1108 case TALER_MERCHANTDB_DCS_NO_RESULTS: 1109 /* We must NOT commit here: the coins were deposited at the 1110 exchange, but we failed to persist the deposit confirmation. 1111 Committing would leave us with a paid order and no deposit 1112 records at all, which breaks our accounting. Note that this 1113 is still a VERY bad case: the customer lost their payment, 1114 and the exchange will pay *somebody*. It really should not 1115 happen as we should not have accepted an unknown order or 1116 an account we do not know, etc.; still, best outcome is for 1117 the wallet to be forced to replay and then hopefully next 1118 time we succeed... */ 1119 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 1120 "Failed to store deposit confirmation for order `%s' (status %d), failing payment\n", 1121 pc->hc->infix, 1122 (int) dcs); 1123 qs = GNUNET_DB_STATUS_HARD_ERROR; 1124 goto cleanup; 1125 } 1126 1127 for (size_t i = 0; i<pc->parse_pay.coins_cnt; i++) 1128 { 1129 struct DepositConfirmation *dc = &pc->parse_pay.dc[i]; 1130 1131 /* might want to group deposits by batch more explicitly ... */ 1132 if (0 != strcmp (eg->exchange_url, 1133 dc->exchange_url)) 1134 continue; 1135 if (dc->found_in_db) 1136 continue; 1137 if (! dc->in_batch) 1138 continue; 1139 dc->wire_fee = eg->wire_fee; 1140 /* FIXME-#9457: We might want to check if the order was fully paid concurrently 1141 by some other wallet here, and if so, issue an auto-refund. Right now, 1142 it is possible to over-pay if two wallets literally make a concurrent 1143 payment, as the earlier check for 'paid' is not in the same transaction 1144 scope as this 'insert' operation. */ 1145 qs = TALER_MERCHANTDB_insert_deposit ( 1146 TMH_db, 1147 off++, /* might want to group deposits by batch more explicitly ... */ 1148 b_dep_serial, 1149 &dc->cdd.coin_pub, 1150 &dc->cdd.coin_sig, 1151 &dc->cdd.amount, 1152 &dc->deposit_fee, 1153 &dc->refund_fee, 1154 GNUNET_TIME_absolute_add ( 1155 pc->check_contract.contract_terms->pc->wire_deadline.abs_time, 1156 GNUNET_TIME_randomize (GNUNET_TIME_UNIT_MINUTES))); 1157 if (qs < 0) 1158 goto cleanup; 1159 GNUNET_break (qs > 0); 1160 } 1161 cleanup: 1162 GNUNET_break (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT == 1163 TALER_MERCHANTDB_set_instance ( 1164 TMH_db, 1165 NULL)); 1166 return qs; 1167 } 1168 1169 1170 /** 1171 * Handle case where the batch deposit completed 1172 * with a status of #MHD_HTTP_OK. 1173 * 1174 * @param eg group that completed 1175 * @param dr response from the server 1176 */ 1177 static void 1178 handle_batch_deposit_ok ( 1179 struct ExchangeGroup *eg, 1180 const struct TALER_EXCHANGE_PostBatchDepositResponse *dr) 1181 { 1182 struct PayContext *pc = eg->pc; 1183 enum GNUNET_DB_QueryStatus qs 1184 = GNUNET_DB_STATUS_SUCCESS_NO_RESULTS; 1185 1186 /* store result to DB */ 1187 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 1188 "Storing successful payment %s (%s) at instance `%s'\n", 1189 pc->hc->infix, 1190 GNUNET_h2s (&pc->check_contract.h_contract_terms.hash), 1191 pc->hc->instance->settings.id); 1192 for (unsigned int r = 0; r<MAX_RETRIES; r++) 1193 { 1194 TALER_MERCHANTDB_preflight (TMH_db); 1195 if (GNUNET_OK != 1196 TALER_MERCHANTDB_start (TMH_db, 1197 "batch-deposit-insert-confirmation")) 1198 { 1199 resume_pay_with_response ( 1200 pc, 1201 MHD_HTTP_INTERNAL_SERVER_ERROR, 1202 TALER_MHD_MAKE_JSON_PACK ( 1203 TALER_JSON_pack_ec ( 1204 TALER_EC_GENERIC_DB_START_FAILED), 1205 TMH_pack_exchange_reply (&dr->hr))); 1206 return; 1207 } 1208 qs = batch_deposit_transaction (eg, 1209 dr); 1210 if (GNUNET_DB_STATUS_SOFT_ERROR == qs) 1211 { 1212 TALER_MERCHANTDB_rollback (TMH_db); 1213 continue; 1214 } 1215 if (GNUNET_DB_STATUS_HARD_ERROR == qs) 1216 { 1217 GNUNET_break (0); 1218 resume_pay_with_error (pc, 1219 TALER_EC_GENERIC_DB_COMMIT_FAILED, 1220 "batch_deposit_transaction"); 1221 TALER_MERCHANTDB_rollback (TMH_db); 1222 return; 1223 } 1224 qs = TALER_MERCHANTDB_commit (TMH_db); 1225 if (GNUNET_DB_STATUS_SOFT_ERROR == qs) 1226 { 1227 TALER_MERCHANTDB_rollback (TMH_db); 1228 continue; 1229 } 1230 if (GNUNET_DB_STATUS_HARD_ERROR == qs) 1231 { 1232 GNUNET_break (0); 1233 resume_pay_with_error (pc, 1234 TALER_EC_GENERIC_DB_COMMIT_FAILED, 1235 "insert_deposit"); 1236 } 1237 break; /* DB transaction succeeded */ 1238 } 1239 if (GNUNET_DB_STATUS_SOFT_ERROR == qs) 1240 { 1241 resume_pay_with_error (pc, 1242 TALER_EC_GENERIC_DB_SOFT_FAILURE, 1243 "insert_deposit"); 1244 return; 1245 } 1246 1247 /* Transaction is done, mark affected coins as complete as well. */ 1248 for (size_t i = 0; i<pc->parse_pay.coins_cnt; i++) 1249 { 1250 struct DepositConfirmation *dc = &pc->parse_pay.dc[i]; 1251 1252 if (0 != strcmp (eg->exchange_url, 1253 dc->exchange_url)) 1254 continue; 1255 if (dc->found_in_db) 1256 continue; 1257 if (! dc->in_batch) 1258 continue; 1259 dc->found_in_db = true; /* well, at least NOW it'd be true ;-) */ 1260 dc->in_batch = false; 1261 pc->pay_transaction.pending--; 1262 } 1263 } 1264 1265 1266 /** 1267 * Notify taler-merchant-kyccheck that we got a KYC 1268 * rule violation notification and should start to 1269 * check our KYC status. 1270 * 1271 * @param eg exchange group we were notified for 1272 */ 1273 static void 1274 notify_kyc_required (const struct ExchangeGroup *eg) 1275 { 1276 struct GNUNET_DB_EventHeaderP es = { 1277 .size = htons (sizeof (es)), 1278 .type = htons (TALER_DBEVENT_MERCHANT_EXCHANGE_KYC_RULE_TRIGGERED) 1279 }; 1280 char *hws; 1281 char *extra; 1282 1283 hws = GNUNET_STRINGS_data_to_string_alloc ( 1284 &eg->pc->check_contract.contract_terms->pc->h_wire, 1285 sizeof (eg->pc->check_contract.contract_terms->pc->h_wire)); 1286 GNUNET_asprintf (&extra, 1287 "%s %s", 1288 hws, 1289 eg->exchange_url); 1290 GNUNET_free (hws); 1291 TALER_MERCHANTDB_event_notify (TMH_db, 1292 &es, 1293 extra, 1294 strlen (extra) + 1); 1295 GNUNET_free (extra); 1296 } 1297 1298 1299 /** 1300 * Run batch deposits for @a eg. 1301 * 1302 * @param[in,out] eg group to do batch deposits for 1303 */ 1304 static void 1305 do_batch_deposits (struct ExchangeGroup *eg); 1306 1307 1308 /** 1309 * Callback to handle a batch deposit permission's response. 1310 * 1311 * @param cls a `struct ExchangeGroup` 1312 * @param dr HTTP response code details 1313 */ 1314 static void 1315 batch_deposit_cb ( 1316 struct ExchangeGroup *eg, 1317 const struct TALER_EXCHANGE_PostBatchDepositResponse *dr) 1318 { 1319 struct PayContext *pc = eg->pc; 1320 1321 eg->bdh = NULL; 1322 pc->batch_deposits.pending_at_eg--; 1323 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 1324 "Batch deposit completed with status %u\n", 1325 dr->hr.http_status); 1326 GNUNET_assert (GNUNET_YES == pc->suspended); 1327 switch (dr->hr.http_status) 1328 { 1329 case MHD_HTTP_OK: 1330 handle_batch_deposit_ok (eg, 1331 dr); 1332 if (GNUNET_YES != pc->suspended) 1333 return; /* handle_batch_deposit_ok already resumed with an error */ 1334 do_batch_deposits (eg); 1335 return; 1336 case MHD_HTTP_UNAVAILABLE_FOR_LEGAL_REASONS: 1337 for (size_t i = 0; i<pc->parse_pay.coins_cnt; i++) 1338 { 1339 struct DepositConfirmation *dc = &pc->parse_pay.dc[i]; 1340 1341 if (0 != strcmp (eg->exchange_url, 1342 dc->exchange_url)) 1343 continue; 1344 dc->in_batch = false; 1345 } 1346 notify_kyc_required (eg); 1347 eg->got_451 = true; 1348 pc->batch_deposits.got_451 = true; 1349 /* update pc->pay_transaction.pending */ 1350 for (size_t i = 0; i<pc->parse_pay.coins_cnt; i++) 1351 { 1352 struct DepositConfirmation *dc = &pc->parse_pay.dc[i]; 1353 1354 if (0 != strcmp (eg->exchange_url, 1355 pc->parse_pay.dc[i].exchange_url)) 1356 continue; 1357 if (dc->found_in_db) 1358 continue; 1359 pc->pay_transaction.pending--; 1360 } 1361 if (0 == pc->batch_deposits.pending_at_eg) 1362 { 1363 pc->phase = PP_COMPUTE_MONEY_POTS; 1364 pay_resume (pc); 1365 } 1366 return; 1367 default: 1368 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 1369 "Deposit operation failed with HTTP code %u/%d\n", 1370 dr->hr.http_status, 1371 (int) dr->hr.ec); 1372 for (size_t i = 0; i<pc->parse_pay.coins_cnt; i++) 1373 { 1374 struct DepositConfirmation *dc = &pc->parse_pay.dc[i]; 1375 1376 if (0 != strcmp (eg->exchange_url, 1377 dc->exchange_url)) 1378 continue; 1379 dc->in_batch = false; 1380 } 1381 /* Transaction failed */ 1382 if (5 == dr->hr.http_status / 100) 1383 { 1384 /* internal server error at exchange */ 1385 resume_pay_with_response (pc, 1386 MHD_HTTP_BAD_GATEWAY, 1387 TALER_MHD_MAKE_JSON_PACK ( 1388 TALER_JSON_pack_ec ( 1389 TALER_EC_MERCHANT_GENERIC_EXCHANGE_UNEXPECTED_STATUS), 1390 TMH_pack_exchange_reply (&dr->hr))); 1391 return; 1392 } 1393 if (NULL == dr->hr.reply) 1394 { 1395 /* We can't do anything meaningful here, the exchange did something wrong */ 1396 resume_pay_with_response ( 1397 pc, 1398 MHD_HTTP_BAD_GATEWAY, 1399 TALER_MHD_MAKE_JSON_PACK ( 1400 TALER_JSON_pack_ec ( 1401 TALER_EC_MERCHANT_GENERIC_EXCHANGE_REPLY_MALFORMED), 1402 TMH_pack_exchange_reply (&dr->hr))); 1403 return; 1404 } 1405 1406 /* Forward error, adding the "exchange_url" for which the 1407 error was being generated */ 1408 if (TALER_EC_EXCHANGE_GENERIC_INSUFFICIENT_FUNDS == dr->hr.ec) 1409 { 1410 resume_pay_with_response ( 1411 pc, 1412 MHD_HTTP_CONFLICT, 1413 TALER_MHD_MAKE_JSON_PACK ( 1414 TALER_JSON_pack_ec ( 1415 TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_INSUFFICIENT_FUNDS), 1416 TMH_pack_exchange_reply (&dr->hr), 1417 GNUNET_JSON_pack_string ("exchange_url", 1418 eg->exchange_url))); 1419 return; 1420 } 1421 resume_pay_with_response ( 1422 pc, 1423 MHD_HTTP_BAD_GATEWAY, 1424 TALER_MHD_MAKE_JSON_PACK ( 1425 TALER_JSON_pack_ec ( 1426 TALER_EC_MERCHANT_GENERIC_EXCHANGE_UNEXPECTED_STATUS), 1427 TMH_pack_exchange_reply (&dr->hr), 1428 GNUNET_JSON_pack_string ("exchange_url", 1429 eg->exchange_url))); 1430 return; 1431 } /* end switch */ 1432 } 1433 1434 1435 static void 1436 do_batch_deposits (struct ExchangeGroup *eg) 1437 { 1438 struct PayContext *pc = eg->pc; 1439 struct TMH_HandlerContext *hc = pc->hc; 1440 unsigned int group_size = 0; 1441 /* Initiate /batch-deposit operation for all coins of 1442 the current exchange (!) */ 1443 1444 GNUNET_assert (NULL != eg->keys); 1445 for (size_t i = 0; i<pc->parse_pay.coins_cnt; i++) 1446 { 1447 struct DepositConfirmation *dc = &pc->parse_pay.dc[i]; 1448 1449 if (0 != strcmp (eg->exchange_url, 1450 pc->parse_pay.dc[i].exchange_url)) 1451 continue; 1452 if (dc->found_in_db) 1453 continue; 1454 group_size++; 1455 if (group_size >= TALER_MAX_COINS) 1456 break; 1457 } 1458 if (0 == group_size) 1459 { 1460 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 1461 "Group size zero, %u batch transactions remain pending\n", 1462 pc->batch_deposits.pending_at_eg); 1463 if (0 == pc->batch_deposits.pending_at_eg) 1464 { 1465 pc->phase = PP_COMPUTE_MONEY_POTS; 1466 pay_resume (pc); 1467 return; 1468 } 1469 return; 1470 } 1471 /* Dispatch the next batch of up to TALER_MAX_COINS coins. 1472 On success, batch_deposit_cb() will re-invoke 1473 do_batch_deposits() to send further batches until 1474 all coins are done. */ 1475 { 1476 struct TALER_EXCHANGE_DepositContractDetail dcd = { 1477 .wire_deadline 1478 = pc->check_contract.contract_terms->pc->wire_deadline, 1479 .merchant_payto_uri 1480 = pc->check_contract.wm->payto_uri, 1481 .extra_wire_subject_metadata 1482 = pc->check_contract.wm->extra_wire_subject_metadata, 1483 .wire_salt 1484 = pc->check_contract.wm->wire_salt, 1485 .h_contract_terms 1486 = pc->check_contract.h_contract_terms, 1487 .wallet_data_hash 1488 = pc->parse_wallet_data.h_wallet_data, 1489 .wallet_timestamp 1490 = pc->check_contract.contract_terms->pc->timestamp, 1491 .merchant_pub 1492 = hc->instance->merchant_pub, 1493 .refund_deadline 1494 = pc->check_contract.contract_terms->pc->refund_deadline 1495 }; 1496 /* Collect up to TALER_MAX_COINS eligible coins for this batch */ 1497 struct TALER_EXCHANGE_CoinDepositDetail cdds[group_size]; 1498 unsigned int batch_size = 0; 1499 enum TALER_ErrorCode ec; 1500 1501 /* FIXME-optimization: move signing outside of this 'loop' 1502 and into the code that runs long before we look at a 1503 specific exchange, otherwise we sign repeatedly! */ 1504 TALER_merchant_contract_sign (&pc->check_contract.h_contract_terms, 1505 &pc->hc->instance->merchant_priv, 1506 &dcd.merchant_sig); 1507 for (size_t i = 0; i<pc->parse_pay.coins_cnt; i++) 1508 { 1509 struct DepositConfirmation *dc = &pc->parse_pay.dc[i]; 1510 1511 if (dc->found_in_db) 1512 continue; 1513 if (0 != strcmp (dc->exchange_url, 1514 eg->exchange_url)) 1515 continue; 1516 dc->in_batch = true; 1517 cdds[batch_size++] = dc->cdd; 1518 if (batch_size == group_size) 1519 break; 1520 } 1521 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 1522 "Initiating batch deposit with %u coins\n", 1523 batch_size); 1524 /* Note: the coin signatures over the wallet_data_hash are 1525 checked inside of this call */ 1526 eg->bdh = TALER_EXCHANGE_post_batch_deposit_create ( 1527 TMH_curl_ctx, 1528 eg->exchange_url, 1529 eg->keys, 1530 &dcd, 1531 batch_size, 1532 cdds, 1533 &ec); 1534 if (NULL == eg->bdh) 1535 { 1536 /* Signature was invalid or some other constraint was not satisfied. If 1537 the exchange was unavailable, we'd get that information in the 1538 callback. */ 1539 GNUNET_break_op (0); 1540 resume_pay_with_response ( 1541 pc, 1542 TALER_ErrorCode_get_http_status_safe (ec), 1543 TALER_MHD_MAKE_JSON_PACK ( 1544 TALER_JSON_pack_ec (ec), 1545 GNUNET_JSON_pack_string ("exchange_url", 1546 eg->exchange_url))); 1547 return; 1548 } 1549 pc->batch_deposits.pending_at_eg++; 1550 if (TMH_force_audit) 1551 { 1552 GNUNET_assert ( 1553 GNUNET_OK == 1554 TALER_EXCHANGE_post_batch_deposit_set_options ( 1555 eg->bdh, 1556 TALER_EXCHANGE_post_batch_deposit_option_force_dc ())); 1557 } 1558 TALER_EXCHANGE_post_batch_deposit_start (eg->bdh, 1559 &batch_deposit_cb, 1560 eg); 1561 } 1562 } 1563 1564 1565 /** 1566 * Force re-downloading keys for @a eg. 1567 * 1568 * @param[in,out] eg group to re-download keys for 1569 */ 1570 static void 1571 force_keys (struct ExchangeGroup *eg); 1572 1573 1574 /** 1575 * Function called with the result of our exchange keys lookup. 1576 * 1577 * @param cls the `struct ExchangeGroup` 1578 * @param keys the keys of the exchange 1579 * @param exchange representation of the exchange 1580 */ 1581 static void 1582 process_pay_with_keys ( 1583 void *cls, 1584 struct TALER_EXCHANGE_Keys *keys, 1585 struct TMH_Exchange *exchange) 1586 { 1587 struct ExchangeGroup *eg = cls; 1588 struct PayContext *pc = eg->pc; 1589 struct TMH_HandlerContext *hc = pc->hc; 1590 struct TALER_Amount max_amount; 1591 enum TMH_ExchangeStatus es; 1592 1593 eg->fo = NULL; 1594 pc->batch_deposits.pending_at_eg--; 1595 GNUNET_SCHEDULER_begin_async_scope (&hc->async_scope_id); 1596 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 1597 "Processing payment with keys from exchange %s\n", 1598 eg->exchange_url); 1599 GNUNET_assert (GNUNET_YES == pc->suspended); 1600 if (NULL == keys) 1601 { 1602 GNUNET_break_op (0); 1603 resume_pay_with_error ( 1604 pc, 1605 TALER_EC_MERCHANT_GENERIC_EXCHANGE_TIMEOUT, 1606 NULL); 1607 return; 1608 } 1609 if (NULL != eg->keys) 1610 TALER_EXCHANGE_keys_decref (eg->keys); 1611 eg->keys = TALER_EXCHANGE_keys_incref (keys); 1612 if (! TMH_EXCHANGES_is_below_limit (keys, 1613 TALER_KYCLOGIC_KYC_TRIGGER_TRANSACTION, 1614 &eg->total)) 1615 { 1616 GNUNET_break_op (0); 1617 resume_pay_with_error ( 1618 pc, 1619 TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_EXCHANGE_TRANSACTION_LIMIT_VIOLATION, 1620 eg->exchange_url); 1621 return; 1622 } 1623 1624 max_amount = eg->total; 1625 es = TMH_exchange_check_debit ( 1626 pc->hc->instance->settings.id, 1627 exchange, 1628 pc->check_contract.wm, 1629 &max_amount); 1630 if ( (TMH_ES_OK != es) && 1631 (TMH_ES_RETRY_OK != es) ) 1632 { 1633 if (eg->tried_force_keys || 1634 (0 == (TMH_ES_RETRY_OK & es)) ) 1635 { 1636 GNUNET_break_op (0); 1637 resume_pay_with_error ( 1638 pc, 1639 TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_WIRE_METHOD_UNSUPPORTED, 1640 NULL); 1641 return; 1642 } 1643 force_keys (eg); 1644 return; 1645 } 1646 if (-1 == 1647 TALER_amount_cmp (&max_amount, 1648 &eg->total)) 1649 { 1650 /* max_amount < eg->total */ 1651 GNUNET_break_op (0); 1652 resume_pay_with_error ( 1653 pc, 1654 TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_EXCHANGE_TRANSACTION_LIMIT_VIOLATION, 1655 eg->exchange_url); 1656 return; 1657 } 1658 1659 if (GNUNET_OK != 1660 TMH_EXCHANGES_lookup_wire_fee (exchange, 1661 pc->check_contract.wm->wire_method, 1662 &eg->wire_fee)) 1663 { 1664 if (eg->tried_force_keys) 1665 { 1666 GNUNET_break_op (0); 1667 resume_pay_with_error ( 1668 pc, 1669 TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_WIRE_METHOD_UNSUPPORTED, 1670 pc->check_contract.wm->wire_method); 1671 return; 1672 } 1673 force_keys (eg); 1674 return; 1675 } 1676 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 1677 "Got wire data for %s\n", 1678 eg->exchange_url); 1679 1680 /* Check all coins satisfy constraints like deposit deadlines 1681 and age restrictions */ 1682 for (size_t i = 0; i<pc->parse_pay.coins_cnt; i++) 1683 { 1684 struct DepositConfirmation *dc = &pc->parse_pay.dc[i]; 1685 const struct TALER_EXCHANGE_DenomPublicKey *denom_details; 1686 bool is_age_restricted_denom = false; 1687 1688 if (0 != strcmp (eg->exchange_url, 1689 pc->parse_pay.dc[i].exchange_url)) 1690 continue; 1691 if (dc->found_in_db) 1692 continue; 1693 1694 denom_details 1695 = TALER_EXCHANGE_get_denomination_key_by_hash (keys, 1696 &dc->cdd.h_denom_pub); 1697 if (NULL == denom_details) 1698 { 1699 if (eg->tried_force_keys) 1700 { 1701 GNUNET_break_op (0); 1702 resume_pay_with_response ( 1703 pc, 1704 MHD_HTTP_BAD_REQUEST, 1705 TALER_MHD_MAKE_JSON_PACK ( 1706 TALER_JSON_pack_ec ( 1707 TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_DENOMINATION_KEY_NOT_FOUND), 1708 GNUNET_JSON_pack_data_auto ("h_denom_pub", 1709 &dc->cdd.h_denom_pub), 1710 GNUNET_JSON_pack_allow_null ( 1711 GNUNET_JSON_pack_object_steal ( 1712 "exchange_keys", 1713 TALER_EXCHANGE_keys_to_json (keys))))); 1714 return; 1715 } 1716 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 1717 "Missing denomination %s from exchange %s, updating keys\n", 1718 GNUNET_h2s (&dc->cdd.h_denom_pub.hash), 1719 eg->exchange_url); 1720 force_keys (eg); 1721 return; 1722 } 1723 dc->deposit_fee = denom_details->fees.deposit; 1724 dc->refund_fee = denom_details->fees.refund; 1725 1726 if (GNUNET_TIME_absolute_is_past ( 1727 denom_details->expire_deposit.abs_time)) 1728 { 1729 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 1730 "Denomination key offered by client has expired for deposits\n"); 1731 resume_pay_with_response ( 1732 pc, 1733 MHD_HTTP_GONE, 1734 TALER_MHD_MAKE_JSON_PACK ( 1735 TALER_JSON_pack_ec ( 1736 TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_DENOMINATION_DEPOSIT_EXPIRED), 1737 GNUNET_JSON_pack_data_auto ("h_denom_pub", 1738 &denom_details->h_key))); 1739 return; 1740 } 1741 1742 /* Now that we have the details about the denomination, we can verify age 1743 * restriction requirements, if applicable. Note that denominations with an 1744 * age_mask equal to zero always pass the age verification. */ 1745 is_age_restricted_denom = (0 != denom_details->key.age_mask.bits); 1746 1747 if (is_age_restricted_denom && 1748 (0 < pc->check_contract.contract_terms->pc->base->minimum_age)) 1749 { 1750 /* Minimum age given and restricted coin provided: We need to verify the 1751 * minimum age */ 1752 unsigned int code = 0; 1753 1754 if (dc->no_age_commitment) 1755 { 1756 GNUNET_break_op (0); 1757 code = TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_AGE_COMMITMENT_MISSING; 1758 goto AGE_FAIL; 1759 } 1760 dc->age_commitment.mask = denom_details->key.age_mask; 1761 if (((int) (dc->age_commitment.num + 1)) != 1762 __builtin_popcount (dc->age_commitment.mask.bits)) 1763 { 1764 GNUNET_break_op (0); 1765 code = 1766 TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_AGE_COMMITMENT_SIZE_MISMATCH; 1767 goto AGE_FAIL; 1768 } 1769 if (GNUNET_OK != 1770 TALER_age_commitment_verify ( 1771 &dc->age_commitment, 1772 pc->check_contract.contract_terms->pc->base->minimum_age, 1773 &dc->minimum_age_sig)) 1774 code = TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_AGE_VERIFICATION_FAILED; 1775 AGE_FAIL: 1776 if (0 < code) 1777 { 1778 GNUNET_break_op (0); 1779 TALER_age_commitment_free (&dc->age_commitment); 1780 resume_pay_with_response ( 1781 pc, 1782 MHD_HTTP_BAD_REQUEST, 1783 TALER_MHD_MAKE_JSON_PACK ( 1784 TALER_JSON_pack_ec (code), 1785 GNUNET_JSON_pack_data_auto ("h_denom_pub", 1786 &denom_details->h_key))); 1787 return; 1788 } 1789 1790 /* Age restriction successfully verified! 1791 * Calculate the hash of the age commitment. */ 1792 TALER_age_commitment_hash (&dc->age_commitment, 1793 &dc->cdd.h_age_commitment); 1794 TALER_age_commitment_free (&dc->age_commitment); 1795 } 1796 else if (is_age_restricted_denom && 1797 dc->no_h_age_commitment) 1798 { 1799 /* The contract did not ask for a minimum_age but the client paid 1800 * with a coin that has age restriction enabled. We lack the hash 1801 * of the age commitment in this case in order to verify the coin 1802 * and to deposit it with the exchange. */ 1803 GNUNET_break_op (0); 1804 resume_pay_with_response ( 1805 pc, 1806 MHD_HTTP_BAD_REQUEST, 1807 TALER_MHD_MAKE_JSON_PACK ( 1808 TALER_JSON_pack_ec ( 1809 TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_AGE_COMMITMENT_HASH_MISSING), 1810 GNUNET_JSON_pack_data_auto ("h_denom_pub", 1811 &denom_details->h_key))); 1812 return; 1813 } 1814 } 1815 1816 do_batch_deposits (eg); 1817 } 1818 1819 1820 static void 1821 force_keys (struct ExchangeGroup *eg) 1822 { 1823 struct PayContext *pc = eg->pc; 1824 1825 eg->tried_force_keys = true; 1826 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 1827 "Forcing /keys download (once)\n"); 1828 eg->fo = TMH_EXCHANGES_keys4exchange ( 1829 eg->exchange_url, 1830 true, 1831 &process_pay_with_keys, 1832 eg); 1833 if (NULL == eg->fo) 1834 { 1835 GNUNET_break_op (0); 1836 resume_pay_with_error (pc, 1837 TALER_EC_MERCHANT_GENERIC_EXCHANGE_UNTRUSTED, 1838 eg->exchange_url); 1839 return; 1840 } 1841 pc->batch_deposits.pending_at_eg++; 1842 } 1843 1844 1845 /** 1846 * Handle a timeout for the processing of the pay request. 1847 * 1848 * @param cls our `struct PayContext` 1849 */ 1850 static void 1851 handle_pay_timeout (void *cls) 1852 { 1853 struct PayContext *pc = cls; 1854 1855 pc->batch_deposits.timeout_task = NULL; 1856 GNUNET_assert (GNUNET_YES == pc->suspended); 1857 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 1858 "Resuming pay with error after timeout\n"); 1859 resume_pay_with_error (pc, 1860 TALER_EC_MERCHANT_GENERIC_EXCHANGE_TIMEOUT, 1861 NULL); 1862 } 1863 1864 1865 /** 1866 * Compute the timeout for a /pay request based on the number of coins 1867 * involved. 1868 * 1869 * @param num_coins number of coins 1870 * @returns timeout for the /pay request 1871 */ 1872 static struct GNUNET_TIME_Relative 1873 get_pay_timeout (unsigned int num_coins) 1874 { 1875 struct GNUNET_TIME_Relative t; 1876 1877 /* FIXME-Performance-Optimization: Do some benchmarking to come up with a 1878 * better timeout. We've increased this value so the wallet integration 1879 * test passes again on my (Florian) machine. 1880 */ 1881 t = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 1882 15 * (1 + (num_coins / 5))); 1883 1884 return t; 1885 } 1886 1887 1888 /** 1889 * Start batch deposits for all exchanges involved 1890 * in this payment. 1891 * 1892 * @param[in,out] pc payment context we are processing 1893 */ 1894 static void 1895 phase_batch_deposits (struct PayContext *pc) 1896 { 1897 for (unsigned int i = 0; i<pc->parse_pay.num_exchanges; i++) 1898 { 1899 struct ExchangeGroup *eg = pc->parse_pay.egs[i]; 1900 bool have_coins = false; 1901 1902 for (size_t j = 0; j<pc->parse_pay.coins_cnt; j++) 1903 { 1904 struct DepositConfirmation *dc = &pc->parse_pay.dc[j]; 1905 1906 if (0 != strcmp (eg->exchange_url, 1907 dc->exchange_url)) 1908 continue; 1909 if (dc->found_in_db) 1910 continue; 1911 have_coins = true; 1912 break; 1913 } 1914 if (! have_coins) 1915 continue; /* no coins left to deposit at this exchange */ 1916 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 1917 "Getting /keys for %s\n", 1918 eg->exchange_url); 1919 eg->fo = TMH_EXCHANGES_keys4exchange ( 1920 eg->exchange_url, 1921 false, 1922 &process_pay_with_keys, 1923 eg); 1924 if (NULL == eg->fo) 1925 { 1926 GNUNET_break_op (0); 1927 pay_end (pc, 1928 TALER_MHD_reply_with_error ( 1929 pc->connection, 1930 MHD_HTTP_BAD_REQUEST, 1931 TALER_EC_MERCHANT_GENERIC_EXCHANGE_UNTRUSTED, 1932 eg->exchange_url)); 1933 return; 1934 } 1935 pc->batch_deposits.pending_at_eg++; 1936 } 1937 if (0 == pc->batch_deposits.pending_at_eg) 1938 { 1939 pc->phase = PP_COMPUTE_MONEY_POTS; 1940 pay_resume (pc); 1941 return; 1942 } 1943 /* Suspend while we interact with the exchange */ 1944 MHD_suspend_connection (pc->connection); 1945 pc->suspended = GNUNET_YES; 1946 GNUNET_assert (NULL == pc->batch_deposits.timeout_task); 1947 pc->batch_deposits.timeout_task 1948 = GNUNET_SCHEDULER_add_delayed (get_pay_timeout (pc->parse_pay.coins_cnt), 1949 &handle_pay_timeout, 1950 pc); 1951 } 1952 1953 1954 /** 1955 * Build JSON array of blindly signed token envelopes, 1956 * to be used in the response to the wallet. 1957 * 1958 * @param[in,out] pc payment context to use 1959 */ 1960 static json_t * 1961 build_token_sigs (struct PayContext *pc) 1962 { 1963 json_t *token_sigs; 1964 1965 if (0 == pc->output_tokens_len) 1966 return NULL; 1967 token_sigs = json_array (); 1968 GNUNET_assert (NULL != token_sigs); 1969 for (unsigned int i = 0; i < pc->output_tokens_len; i++) 1970 { 1971 if (NULL == pc->output_tokens[i].sig.signature) 1972 continue; /* must be optional TF and wallet did not provide it */ 1973 GNUNET_assert (0 == 1974 json_array_append_new ( 1975 token_sigs, 1976 GNUNET_JSON_PACK ( 1977 GNUNET_JSON_pack_blinded_sig ( 1978 "blind_sig", 1979 pc->output_tokens[i].sig.signature) 1980 ))); 1981 } 1982 return token_sigs; 1983 } 1984 1985 1986 /** 1987 * Generate response (payment successful) 1988 * 1989 * @param[in,out] pc payment context where the payment was successful 1990 */ 1991 static void 1992 phase_success_response (struct PayContext *pc) 1993 { 1994 struct TALER_MerchantSignatureP sig; 1995 char *pos_confirmation; 1996 1997 /* Sign on our end (as the payment did go through, even if it may 1998 have been refunded already) */ 1999 TALER_merchant_pay_sign (&pc->check_contract.h_contract_terms, 2000 &pc->hc->instance->merchant_priv, 2001 &sig); 2002 /* Build the response */ 2003 pos_confirmation = (NULL == pc->check_contract.pos_key) 2004 ? NULL 2005 : TALER_build_pos_confirmation ( 2006 pc->check_contract.pos_key, 2007 pc->check_contract.pos_alg, 2008 &pc->validate_tokens.brutto, 2009 pc->check_contract.contract_terms->pc->timestamp); 2010 pay_end (pc, 2011 TALER_MHD_REPLY_JSON_PACK ( 2012 pc->connection, 2013 MHD_HTTP_OK, 2014 GNUNET_JSON_pack_allow_null ( 2015 GNUNET_JSON_pack_string ("pos_confirmation", 2016 pos_confirmation)), 2017 GNUNET_JSON_pack_allow_null ( 2018 GNUNET_JSON_pack_array_steal ("token_sigs", 2019 build_token_sigs (pc))), 2020 GNUNET_JSON_pack_data_auto ("sig", 2021 &sig))); 2022 GNUNET_free (pos_confirmation); 2023 } 2024 2025 2026 /** 2027 * Use database to notify other clients about the 2028 * payment being completed. 2029 * 2030 * @param[in,out] pc context to trigger notification for 2031 */ 2032 static void 2033 phase_payment_notification (struct PayContext *pc) 2034 { 2035 { 2036 struct TMH_OrderPayEventP pay_eh = { 2037 .header.size = htons (sizeof (pay_eh)), 2038 .header.type = htons (TALER_DBEVENT_MERCHANT_ORDER_PAID), 2039 .merchant_pub = pc->hc->instance->merchant_pub 2040 }; 2041 2042 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 2043 "Notifying clients about payment of order %s\n", 2044 pc->order_id); 2045 GNUNET_CRYPTO_hash (pc->order_id, 2046 strlen (pc->order_id), 2047 &pay_eh.h_order_id); 2048 TALER_MERCHANTDB_event_notify (TMH_db, 2049 &pay_eh.header, 2050 NULL, 2051 0); 2052 } 2053 { 2054 struct TMH_OrderPayEventP pay_eh = { 2055 .header.size = htons (sizeof (pay_eh)), 2056 .header.type = htons (TALER_DBEVENT_MERCHANT_ORDER_STATUS_CHANGED), 2057 .merchant_pub = pc->hc->instance->merchant_pub 2058 }; 2059 2060 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 2061 "Notifying clients about status change of order %s\n", 2062 pc->order_id); 2063 GNUNET_CRYPTO_hash (pc->order_id, 2064 strlen (pc->order_id), 2065 &pay_eh.h_order_id); 2066 TALER_MERCHANTDB_event_notify (TMH_db, 2067 &pay_eh.header, 2068 NULL, 2069 0); 2070 } 2071 if ( (NULL != pc->parse_pay.session_id) && 2072 (NULL != pc->check_contract.contract_terms->pc->base->fulfillment_url) ) 2073 { 2074 struct TMH_SessionEventP session_eh = { 2075 .header.size = htons (sizeof (session_eh)), 2076 .header.type = htons (TALER_DBEVENT_MERCHANT_SESSION_CAPTURED), 2077 .merchant_pub = pc->hc->instance->merchant_pub 2078 }; 2079 2080 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 2081 "Notifying clients about session change to %s for %s\n", 2082 pc->parse_pay.session_id, 2083 pc->check_contract.contract_terms->pc->base->fulfillment_url); 2084 GNUNET_CRYPTO_hash (pc->parse_pay.session_id, 2085 strlen (pc->parse_pay.session_id), 2086 &session_eh.h_session_id); 2087 GNUNET_CRYPTO_hash ( 2088 pc->check_contract.contract_terms->pc->base->fulfillment_url, 2089 strlen (pc->check_contract.contract_terms->pc->base->fulfillment_url), 2090 &session_eh.h_fulfillment_url); 2091 TALER_MERCHANTDB_event_notify (TMH_db, 2092 &session_eh.header, 2093 NULL, 2094 0); 2095 } 2096 pc->phase = PP_SUCCESS_RESPONSE; 2097 } 2098 2099 2100 /** 2101 * Phase to write all outputs to our database so we do 2102 * not re-request them in case the client re-plays the 2103 * request. 2104 * 2105 * @param[in,out] pc payment context 2106 */ 2107 static void 2108 phase_final_output_token_processing (struct PayContext *pc) 2109 { 2110 if (0 == pc->output_tokens_len) 2111 { 2112 pc->phase++; 2113 return; 2114 } 2115 for (unsigned int retry = 0; retry < MAX_RETRIES; retry++) 2116 { 2117 enum GNUNET_DB_QueryStatus qs; 2118 2119 TALER_MERCHANTDB_preflight (TMH_db); 2120 if (GNUNET_OK != 2121 TALER_MERCHANTDB_start (TMH_db, 2122 "insert_order_token_blinded_sig")) 2123 { 2124 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 2125 "start insert_order_blinded_sigs_failed"); 2126 pc->phase++; 2127 return; 2128 } 2129 if (pc->parse_wallet_data.num_bkps > 0) 2130 { 2131 qs = TALER_MERCHANTDB_update_donau_instance_receipts_amount ( 2132 TMH_db, 2133 &pc->parse_wallet_data.donau_instance_serial, 2134 &pc->parse_wallet_data.charity_receipts_to_date); 2135 switch (qs) 2136 { 2137 case GNUNET_DB_STATUS_HARD_ERROR: 2138 TALER_MERCHANTDB_rollback (TMH_db); 2139 GNUNET_break (0); 2140 pc->phase++; 2141 return; 2142 case GNUNET_DB_STATUS_SOFT_ERROR: 2143 TALER_MERCHANTDB_rollback (TMH_db); 2144 continue; 2145 case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS: 2146 /* weird for an update */ 2147 GNUNET_break (0); 2148 break; 2149 case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT: 2150 break; 2151 } 2152 } 2153 for (unsigned int i = 0; 2154 i < pc->output_tokens_len; 2155 i++) 2156 { 2157 if (NULL == pc->output_tokens[i].sig.signature) 2158 continue; /* must have been optional and not provided by wallet */ 2159 qs = TALER_MERCHANTDB_insert_order_token_blinded_sig ( 2160 TMH_db, 2161 pc->order_id, 2162 i, 2163 &pc->output_tokens[i].h_issue.hash, 2164 pc->output_tokens[i].sig.signature); 2165 2166 switch (qs) 2167 { 2168 case GNUNET_DB_STATUS_HARD_ERROR: 2169 TALER_MERCHANTDB_rollback (TMH_db); 2170 pc->phase++; 2171 return; 2172 case GNUNET_DB_STATUS_SOFT_ERROR: 2173 TALER_MERCHANTDB_rollback (TMH_db); 2174 goto OUTER; 2175 case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS: 2176 /* weird for an update */ 2177 GNUNET_break (0); 2178 break; 2179 case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT: 2180 break; 2181 } 2182 } /* for i */ 2183 qs = TALER_MERCHANTDB_commit (TMH_db); 2184 switch (qs) 2185 { 2186 case GNUNET_DB_STATUS_HARD_ERROR: 2187 TALER_MERCHANTDB_rollback (TMH_db); 2188 pc->phase++; 2189 return; 2190 case GNUNET_DB_STATUS_SOFT_ERROR: 2191 TALER_MERCHANTDB_rollback (TMH_db); 2192 continue; 2193 case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS: 2194 pc->phase++; 2195 return; /* success */ 2196 case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT: 2197 pc->phase++; 2198 return; /* success */ 2199 } 2200 GNUNET_break (0); 2201 pc->phase++; 2202 return; /* strange */ 2203 OUTER: 2204 } /* for retry */ 2205 TALER_MERCHANTDB_rollback (TMH_db); 2206 pc->phase++; 2207 /* We continue anyway, as there is not much we can 2208 do here: the Donau *did* issue us the receipts; 2209 also, we'll eventually ask the Donau for the 2210 balance and get the correct one. Plus, we were 2211 paid by the client, so it's technically all still 2212 OK. If the request fails anyway, the wallet will 2213 most likely replay the request and then hopefully 2214 we will succeed the next time */ 2215 } 2216 2217 2218 /** 2219 * Add donation receipt outputs to the output_tokens. 2220 * 2221 * Note that under the current (odd, bad) libdonau 2222 * API *we* are responsible for freeing blinded_sigs, 2223 * so we truly own that array! 2224 * 2225 * @param[in,out] pc payment context 2226 * @param num_blinded_sigs number of signatures received 2227 * @param blinded_sigs blinded signatures from Donau 2228 * @return #GNUNET_OK on success, 2229 * #GNUNET_SYSERR on failure (state machine was 2230 * in that case already advanced) 2231 */ 2232 static enum GNUNET_GenericReturnValue 2233 add_donation_receipt_outputs ( 2234 struct PayContext *pc, 2235 size_t num_blinded_sigs, 2236 struct DONAU_BlindedDonationUnitSignature *blinded_sigs) 2237 { 2238 unsigned int i; 2239 int donau_output_index = pc->validate_tokens.donau_output_index; 2240 2241 GNUNET_assert (pc->parse_wallet_data.num_bkps == 2242 num_blinded_sigs); 2243 GNUNET_assert (donau_output_index >= 0); 2244 2245 /* Find position where donau tokens start in output_tokens */ 2246 for (i = 0; i<pc->output_tokens_len; i++) 2247 { 2248 const struct SignedOutputToken *sot 2249 = &pc->output_tokens[i]; 2250 2251 /* Only look at actual donau tokens. */ 2252 if (sot->output_index == donau_output_index) 2253 break; 2254 } 2255 2256 /* copy donau signatures into output array */ 2257 for (unsigned int j=0; j<pc->parse_wallet_data.num_bkps; j++) 2258 { 2259 struct SignedOutputToken *sot; 2260 2261 GNUNET_assert (i + j < pc->output_tokens_len); 2262 sot = &pc->output_tokens[i + j]; 2263 GNUNET_assert (sot->output_index == donau_output_index); 2264 sot->sig.signature = GNUNET_CRYPTO_blind_sig_incref ( 2265 blinded_sigs[j].blinded_sig); 2266 sot->h_issue.hash 2267 = pc->parse_wallet_data.bkps[j].h_donation_unit_pub.hash; 2268 } 2269 return GNUNET_OK; 2270 } 2271 2272 2273 /** 2274 * Callback to handle the result of a batch issue request. 2275 * 2276 * @param cls our `struct PayContext` 2277 * @param resp the response from Donau 2278 */ 2279 static void 2280 merchant_donau_issue_receipt_cb ( 2281 void *cls, 2282 const struct DONAU_BatchIssueResponse *resp) 2283 { 2284 struct PayContext *pc = cls; 2285 2286 /* Donau replies asynchronously, so we expect the PayContext 2287 * to be suspended. */ 2288 GNUNET_assert (GNUNET_YES == pc->suspended); 2289 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 2290 "Donau responded with status=%u, ec=%u", 2291 resp->hr.http_status, 2292 resp->hr.ec); 2293 switch (resp->hr.http_status) 2294 { 2295 case 0: 2296 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 2297 "Donau batch issue request from merchant-httpd failed (http_status==0)"); 2298 resume_pay_with_error (pc, 2299 TALER_EC_MERCHANT_GENERIC_DONAU_INVALID_RESPONSE, 2300 resp->hr.hint); 2301 return; 2302 case MHD_HTTP_OK: 2303 if (pc->parse_wallet_data.num_bkps != 2304 resp->details.ok.num_blinded_sigs) 2305 { 2306 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 2307 "Invalid number of signatures in batch issue response"); 2308 resume_pay_with_error (pc, 2309 TALER_EC_MERCHANT_GENERIC_DONAU_INVALID_RESPONSE, 2310 "invalid number of signatures"); 2311 return; 2312 } 2313 if (TALER_EC_NONE != resp->hr.ec) 2314 { 2315 /* Most probably, it is just some small flaw from 2316 * donau so no point in failing, yet we have to display it */ 2317 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 2318 "Donau signalled error %u despite HTTP %u", 2319 resp->hr.ec, 2320 resp->hr.http_status); 2321 } 2322 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 2323 "Donau accepted donation receipts with total_issued=%s", 2324 TALER_amount2s (&resp->details.ok.issued_amount)); 2325 if (GNUNET_OK != 2326 add_donation_receipt_outputs (pc, 2327 resp->details.ok.num_blinded_sigs, 2328 resp->details.ok.blinded_sigs)) 2329 return; /* state machine was already advanced */ 2330 pc->phase = PP_FINAL_OUTPUT_TOKEN_PROCESSING; 2331 pay_resume (pc); 2332 return; 2333 2334 case MHD_HTTP_BAD_REQUEST: 2335 case MHD_HTTP_FORBIDDEN: 2336 case MHD_HTTP_NOT_FOUND: 2337 case MHD_HTTP_INTERNAL_SERVER_ERROR: 2338 default: /* make sure that everything except 200/201 will end up here*/ 2339 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 2340 "Donau replied with HTTP %u (ec=%u)", 2341 resp->hr.http_status, 2342 resp->hr.ec); 2343 resume_pay_with_error (pc, 2344 TALER_EC_MERCHANT_GENERIC_DONAU_INVALID_RESPONSE, 2345 resp->hr.hint); 2346 return; 2347 } 2348 } 2349 2350 2351 /** 2352 * Parse a bkp encoded in JSON. 2353 * 2354 * @param[out] bkp where to return the result 2355 * @param bkp_key_obj json to parse 2356 * @return #GNUNET_OK if all is fine, #GNUNET_SYSERR if @a bkp_key_obj 2357 * is malformed. 2358 */ 2359 static enum GNUNET_GenericReturnValue 2360 merchant_parse_json_bkp (struct DONAU_BlindedUniqueDonorIdentifierKeyPair *bkp, 2361 const json_t *bkp_key_obj) 2362 { 2363 struct GNUNET_JSON_Specification spec[] = { 2364 GNUNET_JSON_spec_fixed_auto ("h_donation_unit_pub", 2365 &bkp->h_donation_unit_pub), 2366 DONAU_JSON_spec_blinded_donation_identifier ("blinded_udi", 2367 &bkp->blinded_udi), 2368 GNUNET_JSON_spec_end () 2369 }; 2370 2371 if (GNUNET_OK != 2372 GNUNET_JSON_parse (bkp_key_obj, 2373 spec, 2374 NULL, 2375 NULL)) 2376 { 2377 GNUNET_break_op (0); 2378 return GNUNET_SYSERR; 2379 } 2380 return GNUNET_OK; 2381 } 2382 2383 2384 /** 2385 * Generate a donation signature for the bkp and charity. 2386 * 2387 * @param[in,out] pc payment context containing the charity and bkps 2388 */ 2389 static void 2390 phase_request_donation_receipt (struct PayContext *pc) 2391 { 2392 if ( (NULL == pc->parse_wallet_data.donau.donau_url) || 2393 (0 == pc->parse_wallet_data.num_bkps) ) 2394 { 2395 pc->phase++; 2396 return; 2397 } 2398 pc->donau_receipt.birh = 2399 DONAU_charity_issue_receipt ( 2400 TMH_curl_ctx, 2401 pc->parse_wallet_data.donau.donau_url, 2402 &pc->parse_wallet_data.charity_priv, 2403 pc->parse_wallet_data.charity_id, 2404 pc->parse_wallet_data.donau.donation_year, 2405 pc->parse_wallet_data.num_bkps, 2406 pc->parse_wallet_data.bkps, 2407 &merchant_donau_issue_receipt_cb, 2408 pc); 2409 if (NULL == pc->donau_receipt.birh) 2410 { 2411 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 2412 "Failed to create Donau receipt request"); 2413 pay_end (pc, 2414 TALER_MHD_reply_with_error (pc->connection, 2415 MHD_HTTP_INTERNAL_SERVER_ERROR, 2416 TALER_EC_GENERIC_CLIENT_INTERNAL_ERROR, 2417 "Donau request creation error")); 2418 return; 2419 } 2420 MHD_suspend_connection (pc->connection); 2421 pc->suspended = GNUNET_YES; 2422 } 2423 2424 2425 /** 2426 * Increment the money pot @a pot_id in @a pc by @a increment. 2427 * 2428 * @param[in,out] pc context to update 2429 * @param pot_id money pot to increment 2430 * @param increment amount to add 2431 */ 2432 static void 2433 increment_pot (struct PayContext *pc, 2434 uint64_t pot_id, 2435 const struct TALER_Amount *increment) 2436 { 2437 for (unsigned int i = 0; i<pc->compute_money_pots.num_pots; i++) 2438 { 2439 if (pot_id == pc->compute_money_pots.pots[i]) 2440 { 2441 struct TALER_Amount *p; 2442 2443 p = &pc->compute_money_pots.increments[i]; 2444 GNUNET_assert (0 <= 2445 TALER_amount_add (p, 2446 p, 2447 increment)); 2448 return; 2449 } 2450 } 2451 GNUNET_array_append (pc->compute_money_pots.pots, 2452 pc->compute_money_pots.num_pots, 2453 pot_id); 2454 pc->compute_money_pots.num_pots--; /* do not increment twice... */ 2455 GNUNET_array_append (pc->compute_money_pots.increments, 2456 pc->compute_money_pots.num_pots, 2457 *increment); 2458 } 2459 2460 2461 /** 2462 * Compute the total changes to money pots in preparation 2463 * for the #PP_PAY_TRANSACTION phase. 2464 * 2465 * @param[in,out] pc payment context to transact 2466 */ 2467 static void 2468 phase_compute_money_pots (struct PayContext *pc) 2469 { 2470 const struct TALER_MERCHANT_Contract *contract 2471 = pc->check_contract.contract_terms; 2472 struct TALER_Amount assigned; 2473 2474 if (0 == pc->parse_pay.coins_cnt) 2475 { 2476 /* Did not pay with any coins, so no currency/amount involved, 2477 hence no money pot update possible. */ 2478 pc->phase++; 2479 return; 2480 } 2481 2482 if (pc->compute_money_pots.pots_computed) 2483 { 2484 pc->phase++; 2485 return; 2486 } 2487 /* reset, in case this phase is run a 2nd time */ 2488 GNUNET_free (pc->compute_money_pots.pots); 2489 GNUNET_free (pc->compute_money_pots.increments); 2490 pc->compute_money_pots.num_pots = 0; 2491 2492 GNUNET_assert (GNUNET_OK == 2493 TALER_amount_set_zero (pc->parse_pay.dc[0].cdd.amount.currency, 2494 &assigned)); 2495 GNUNET_assert (NULL != contract); 2496 for (size_t i = 0; i<contract->pc->products_len; i++) 2497 { 2498 const struct TALER_MERCHANT_ProductSold *product 2499 = &contract->pc->products[i]; 2500 const struct TALER_Amount *price = NULL; 2501 2502 /* find price in the right currency */ 2503 for (unsigned int j = 0; j<product->prices_length; j++) 2504 { 2505 if (GNUNET_OK == 2506 TALER_amount_cmp_currency (&assigned, 2507 &product->prices[j])) 2508 { 2509 price = &product->prices[j]; 2510 break; 2511 } 2512 } 2513 if (NULL == price) 2514 { 2515 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 2516 "Product `%s' has no price given in `%s'.\n", 2517 product->product_id, 2518 assigned.currency); 2519 continue; 2520 } 2521 if (0 != product->product_money_pot) 2522 { 2523 GNUNET_assert (0 <= 2524 TALER_amount_add (&assigned, 2525 &assigned, 2526 price)); 2527 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 2528 "Contributing to product money pot %llu increment of %s\n", 2529 (unsigned long long) product->product_money_pot, 2530 TALER_amount2s (price)); 2531 increment_pot (pc, 2532 product->product_money_pot, 2533 price); 2534 } 2535 } 2536 2537 { 2538 /* Compute what is left from the order total and account for that. 2539 Also sanity-check and handle the case where the overall order 2540 is below that of the sum of the products. */ 2541 struct TALER_Amount left; 2542 2543 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 2544 "Order brutto is %s\n", 2545 TALER_amount2s (&pc->validate_tokens.brutto)); 2546 if (0 > 2547 TALER_amount_subtract (&left, 2548 &pc->validate_tokens.brutto, 2549 &assigned)) 2550 { 2551 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 2552 "Total order brutto amount below sum from products, skipping per-product money pots\n"); 2553 GNUNET_free (pc->compute_money_pots.pots); 2554 GNUNET_free (pc->compute_money_pots.increments); 2555 pc->compute_money_pots.num_pots = 0; 2556 left = pc->validate_tokens.brutto; 2557 } 2558 2559 if ( (! TALER_amount_is_zero (&left)) && 2560 (0 != contract->pc->base->default_money_pot) ) 2561 { 2562 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 2563 "Computing money pot %llu increment as %s\n", 2564 (unsigned long long) contract->pc->base->default_money_pot, 2565 TALER_amount2s (&left)); 2566 increment_pot (pc, 2567 contract->pc->base->default_money_pot, 2568 &left); 2569 } 2570 } 2571 pc->compute_money_pots.pots_computed = true; 2572 pc->phase++; 2573 } 2574 2575 2576 /** 2577 * Function called with information about a coin that was deposited. 2578 * 2579 * @param cls closure 2580 * @param exchange_url exchange where @a coin_pub was deposited 2581 * @param coin_pub public key of the coin 2582 * @param amount_with_fee amount the exchange will deposit for this coin 2583 * @param deposit_fee fee the exchange will charge for this coin 2584 * @param refund_fee fee the exchange will charge for refunding this coin 2585 * @param wire_fee fee the exchange will charge for wiring this coin 2586 */ 2587 static void 2588 check_coin_paid (void *cls, 2589 const char *exchange_url, 2590 const struct TALER_CoinSpendPublicKeyP *coin_pub, 2591 const struct TALER_Amount *amount_with_fee, 2592 const struct TALER_Amount *deposit_fee, 2593 const struct TALER_Amount *refund_fee, 2594 const struct TALER_Amount *wire_fee) 2595 { 2596 struct PayContext *pc = cls; 2597 2598 for (size_t i = 0; i<pc->parse_pay.coins_cnt; i++) 2599 { 2600 struct DepositConfirmation *dc = &pc->parse_pay.dc[i]; 2601 2602 if (dc->found_in_db) 2603 continue; /* processed earlier, skip "expensive" memcmp() */ 2604 /* Get matching coin from results*/ 2605 if ( (0 != GNUNET_memcmp (coin_pub, 2606 &dc->cdd.coin_pub)) || 2607 (0 != 2608 strcmp (exchange_url, 2609 dc->exchange_url)) || 2610 (GNUNET_OK != 2611 TALER_amount_cmp_currency (amount_with_fee, 2612 &dc->cdd.amount)) || 2613 (0 != TALER_amount_cmp (amount_with_fee, 2614 &dc->cdd.amount)) ) 2615 continue; /* does not match, skip */ 2616 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 2617 "Deposit of coin `%s' already in our DB.\n", 2618 TALER_B2S (coin_pub)); 2619 if ( (GNUNET_OK != 2620 TALER_amount_cmp_currency (&pc->pay_transaction.total_paid, 2621 amount_with_fee)) || 2622 (GNUNET_OK != 2623 TALER_amount_cmp_currency (&pc->pay_transaction.total_fees_paid, 2624 deposit_fee)) ) 2625 { 2626 GNUNET_break_op (0); 2627 pc->pay_transaction.deposit_currency_mismatch = true; 2628 break; 2629 } 2630 GNUNET_assert (0 <= 2631 TALER_amount_add (&pc->pay_transaction.total_paid, 2632 &pc->pay_transaction.total_paid, 2633 amount_with_fee)); 2634 GNUNET_assert (0 <= 2635 TALER_amount_add (&pc->pay_transaction.total_fees_paid, 2636 &pc->pay_transaction.total_fees_paid, 2637 deposit_fee)); 2638 dc->deposit_fee = *deposit_fee; 2639 dc->refund_fee = *refund_fee; 2640 dc->wire_fee = *wire_fee; 2641 dc->cdd.amount = *amount_with_fee; 2642 dc->found_in_db = true; 2643 pc->pay_transaction.pending--; 2644 } 2645 } 2646 2647 2648 /** 2649 * Function called with information about a refund. Check if this coin was 2650 * claimed by the wallet for the transaction, and if so add the refunded 2651 * amount to the pc's "total_refunded" amount. 2652 * 2653 * @param cls closure with a `struct PayContext` 2654 * @param coin_pub public coin from which the refund comes from 2655 * @param refund_amount refund amount which is being taken from @a coin_pub 2656 */ 2657 static void 2658 check_coin_refunded (void *cls, 2659 const struct TALER_CoinSpendPublicKeyP *coin_pub, 2660 const struct TALER_Amount *refund_amount) 2661 { 2662 struct PayContext *pc = cls; 2663 2664 /* We look at refunds here that apply to the coins 2665 that the customer is currently trying to pay us with. 2666 2667 Such refunds are not "normal" refunds, but abort-pay refunds, which are 2668 given in the case that the wallet aborts the payment. 2669 In the case the wallet then decides to complete the payment *after* doing 2670 an abort-pay refund (an unusual but possible case), we need 2671 to make sure that existing refunds are accounted for. */ 2672 2673 for (size_t i = 0; i<pc->parse_pay.coins_cnt; i++) 2674 { 2675 struct DepositConfirmation *dc = &pc->parse_pay.dc[i]; 2676 2677 /* Get matching coins from results. */ 2678 if (0 != GNUNET_memcmp (coin_pub, 2679 &dc->cdd.coin_pub)) 2680 continue; 2681 if (GNUNET_OK != 2682 TALER_amount_cmp_currency (&pc->pay_transaction.total_refunded, 2683 refund_amount)) 2684 { 2685 GNUNET_break (0); 2686 pc->pay_transaction.refund_currency_mismatch = true; 2687 break; 2688 } 2689 GNUNET_assert (0 <= 2690 TALER_amount_add (&pc->pay_transaction.total_refunded, 2691 &pc->pay_transaction.total_refunded, 2692 refund_amount)); 2693 break; 2694 } 2695 } 2696 2697 2698 /** 2699 * Check whether the amount paid is sufficient to cover the price. 2700 * 2701 * @param pc payment context to check 2702 * @return true if the payment is sufficient, false if it is 2703 * insufficient 2704 */ 2705 static bool 2706 check_payment_sufficient (struct PayContext *pc) 2707 { 2708 struct TALER_Amount acc_fee; 2709 struct TALER_Amount acc_amount; 2710 struct TALER_Amount final_amount; 2711 struct TALER_Amount total_wire_fee; 2712 struct TALER_Amount total_needed; 2713 2714 if (0 == pc->parse_pay.coins_cnt) 2715 return TALER_amount_is_zero (&pc->validate_tokens.brutto); 2716 GNUNET_assert (GNUNET_OK == 2717 TALER_amount_set_zero (pc->validate_tokens.brutto.currency, 2718 &total_wire_fee)); 2719 for (unsigned int i = 0; i < pc->parse_pay.num_exchanges; i++) 2720 { 2721 const struct ExchangeGroup *egsi = pc->parse_pay.egs[i]; 2722 const struct TALER_Amount *wire_fee = NULL; 2723 2724 /* Note: we cannot just use egsi->wire_fee here, as that field 2725 MAY not be initialized if the deposit for that exchange was 2726 done earlier this is an idempotent request, for example 2727 to deposit coins of another exchange or just because the 2728 previous answer was lost; thus, we must get the fee from 2729 the "dc" as that is guaranteed to be set! */ 2730 for (size_t j = 0; j < pc->parse_pay.coins_cnt; j++) 2731 { 2732 const struct DepositConfirmation *dc = &pc->parse_pay.dc[j]; 2733 2734 if (0 == strcmp (dc->exchange_url, 2735 egsi->exchange_url)) 2736 { 2737 wire_fee = &dc->wire_fee; 2738 break; 2739 } 2740 } 2741 if (NULL == wire_fee) 2742 { 2743 /* Exchange group without a single deposit? Strange! */ 2744 GNUNET_break (0); 2745 continue; 2746 } 2747 2748 if (GNUNET_OK != 2749 TALER_amount_cmp_currency (&total_wire_fee, 2750 wire_fee)) 2751 { 2752 GNUNET_break_op (0); 2753 pay_end (pc, 2754 TALER_MHD_reply_with_error (pc->connection, 2755 MHD_HTTP_BAD_REQUEST, 2756 TALER_EC_GENERIC_CURRENCY_MISMATCH, 2757 total_wire_fee.currency)); 2758 return false; 2759 } 2760 if (0 > 2761 TALER_amount_add (&total_wire_fee, 2762 &total_wire_fee, 2763 wire_fee)) 2764 { 2765 GNUNET_break (0); 2766 pay_end (pc, 2767 TALER_MHD_reply_with_error ( 2768 pc->connection, 2769 MHD_HTTP_INTERNAL_SERVER_ERROR, 2770 TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_EXCHANGE_WIRE_FEE_ADDITION_FAILED, 2771 "could not add exchange wire fee to total")); 2772 return false; 2773 } 2774 } 2775 2776 /** 2777 * This loops calculates what are the deposit fee / total 2778 * amount with fee / and wire fee, for all the coins. 2779 */ 2780 GNUNET_assert (GNUNET_OK == 2781 TALER_amount_set_zero (pc->validate_tokens.brutto.currency, 2782 &acc_fee)); 2783 GNUNET_assert (GNUNET_OK == 2784 TALER_amount_set_zero (pc->validate_tokens.brutto.currency, 2785 &acc_amount)); 2786 for (size_t i = 0; i<pc->parse_pay.coins_cnt; i++) 2787 { 2788 struct DepositConfirmation *dc = &pc->parse_pay.dc[i]; 2789 2790 GNUNET_assert (dc->found_in_db); 2791 if ( (GNUNET_OK != 2792 TALER_amount_cmp_currency (&acc_fee, 2793 &dc->deposit_fee)) || 2794 (GNUNET_OK != 2795 TALER_amount_cmp_currency (&acc_amount, 2796 &dc->cdd.amount)) ) 2797 { 2798 GNUNET_break_op (0); 2799 pay_end (pc, 2800 TALER_MHD_reply_with_error ( 2801 pc->connection, 2802 MHD_HTTP_BAD_REQUEST, 2803 TALER_EC_GENERIC_CURRENCY_MISMATCH, 2804 dc->deposit_fee.currency)); 2805 return false; 2806 } 2807 if ( (0 > 2808 TALER_amount_add (&acc_fee, 2809 &dc->deposit_fee, 2810 &acc_fee)) || 2811 (0 > 2812 TALER_amount_add (&acc_amount, 2813 &dc->cdd.amount, 2814 &acc_amount)) ) 2815 { 2816 GNUNET_break (0); 2817 /* Overflow in these amounts? Very strange. */ 2818 pay_end (pc, 2819 TALER_MHD_reply_with_error ( 2820 pc->connection, 2821 MHD_HTTP_INTERNAL_SERVER_ERROR, 2822 TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_AMOUNT_OVERFLOW, 2823 "Overflow adding up amounts")); 2824 return false; 2825 } 2826 if (1 == 2827 TALER_amount_cmp (&dc->deposit_fee, 2828 &dc->cdd.amount)) 2829 { 2830 GNUNET_break_op (0); 2831 pay_end (pc, 2832 TALER_MHD_reply_with_error ( 2833 pc->connection, 2834 MHD_HTTP_BAD_REQUEST, 2835 TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_FEES_EXCEED_PAYMENT, 2836 "Deposit fees exceed coin's contribution")); 2837 return false; 2838 } 2839 } /* end deposit loop */ 2840 2841 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 2842 "Amount received from wallet: %s\n", 2843 TALER_amount2s (&acc_amount)); 2844 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 2845 "Deposit fee for all coins: %s\n", 2846 TALER_amount2s (&acc_fee)); 2847 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 2848 "Total wire fee: %s\n", 2849 TALER_amount2s (&total_wire_fee)); 2850 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 2851 "Deposit fee limit for merchant: %s\n", 2852 TALER_amount2s (&pc->validate_tokens.max_fee)); 2853 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 2854 "Total refunded amount: %s\n", 2855 TALER_amount2s (&pc->pay_transaction.total_refunded)); 2856 2857 /* Now compare exchange wire fee compared to what we are willing to pay */ 2858 if (GNUNET_YES != 2859 TALER_amount_cmp_currency (&total_wire_fee, 2860 &acc_fee)) 2861 { 2862 GNUNET_break (0); 2863 pay_end (pc, 2864 TALER_MHD_reply_with_error ( 2865 pc->connection, 2866 MHD_HTTP_BAD_REQUEST, 2867 TALER_EC_GENERIC_CURRENCY_MISMATCH, 2868 total_wire_fee.currency)); 2869 return false; 2870 } 2871 2872 /* add wire fee to the total fees */ 2873 if (0 > 2874 TALER_amount_add (&acc_fee, 2875 &acc_fee, 2876 &total_wire_fee)) 2877 { 2878 GNUNET_break (0); 2879 pay_end (pc, 2880 TALER_MHD_reply_with_error ( 2881 pc->connection, 2882 MHD_HTTP_INTERNAL_SERVER_ERROR, 2883 TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_AMOUNT_OVERFLOW, 2884 "Overflow adding up amounts")); 2885 return false; 2886 } 2887 if (-1 == TALER_amount_cmp (&pc->validate_tokens.max_fee, 2888 &acc_fee)) 2889 { 2890 /** 2891 * Sum of fees of *all* the different exchanges of all the coins are 2892 * higher than the fixed limit that the merchant is willing to pay. The 2893 * difference must be paid by the customer. 2894 */ 2895 struct TALER_Amount excess_fee; 2896 2897 /* compute fee amount to be covered by customer */ 2898 GNUNET_assert (TALER_AAR_RESULT_POSITIVE == 2899 TALER_amount_subtract (&excess_fee, 2900 &acc_fee, 2901 &pc->validate_tokens.max_fee)); 2902 /* add that to the total */ 2903 if (0 > 2904 TALER_amount_add (&total_needed, 2905 &excess_fee, 2906 &pc->validate_tokens.brutto)) 2907 { 2908 GNUNET_break (0); 2909 pay_end (pc, 2910 TALER_MHD_reply_with_error ( 2911 pc->connection, 2912 MHD_HTTP_INTERNAL_SERVER_ERROR, 2913 TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_AMOUNT_OVERFLOW, 2914 "Overflow adding up amounts")); 2915 return false; 2916 } 2917 } 2918 else 2919 { 2920 /* Fees are fully covered by the merchant, all we require 2921 is that the total payment is not below the contract's amount */ 2922 total_needed = pc->validate_tokens.brutto; 2923 } 2924 2925 /* Do not count refunds towards the payment */ 2926 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 2927 "Subtracting total refunds from paid amount: %s\n", 2928 TALER_amount2s (&pc->pay_transaction.total_refunded)); 2929 if (0 > 2930 TALER_amount_subtract (&final_amount, 2931 &acc_amount, 2932 &pc->pay_transaction.total_refunded)) 2933 { 2934 GNUNET_break (0); 2935 pay_end (pc, 2936 TALER_MHD_reply_with_error ( 2937 pc->connection, 2938 MHD_HTTP_INTERNAL_SERVER_ERROR, 2939 TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_REFUNDS_EXCEED_PAYMENTS, 2940 "refunded amount exceeds total payments")); 2941 return false; 2942 } 2943 2944 if (-1 == TALER_amount_cmp (&final_amount, 2945 &total_needed)) 2946 { 2947 /* acc_amount < total_needed */ 2948 if (-1 < TALER_amount_cmp (&acc_amount, 2949 &total_needed)) 2950 { 2951 GNUNET_break_op (0); 2952 pay_end (pc, 2953 TALER_MHD_reply_with_error ( 2954 pc->connection, 2955 MHD_HTTP_PAYMENT_REQUIRED, 2956 TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_REFUNDED, 2957 "contract not paid up due to refunds")); 2958 return false; 2959 } 2960 if (-1 < TALER_amount_cmp (&acc_amount, 2961 &pc->validate_tokens.brutto)) 2962 { 2963 GNUNET_break_op (0); 2964 pay_end (pc, 2965 TALER_MHD_reply_with_error ( 2966 pc->connection, 2967 MHD_HTTP_BAD_REQUEST, 2968 TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_INSUFFICIENT_DUE_TO_FEES, 2969 "contract not paid up due to fees (client may have calculated them badly)")); 2970 return false; 2971 } 2972 GNUNET_break_op (0); 2973 pay_end (pc, 2974 TALER_MHD_reply_with_error ( 2975 pc->connection, 2976 MHD_HTTP_BAD_REQUEST, 2977 TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_PAYMENT_INSUFFICIENT, 2978 "payment insufficient")); 2979 return false; 2980 } 2981 return true; 2982 } 2983 2984 2985 /** 2986 * Execute the DB transaction. If required (from 2987 * soft/serialization errors), the transaction can be 2988 * restarted here. 2989 * 2990 * @param[in,out] pc payment context to transact 2991 */ 2992 static void 2993 phase_execute_pay_transaction (struct PayContext *pc) 2994 { 2995 struct TMH_HandlerContext *hc = pc->hc; 2996 const char *instance_id = hc->instance->settings.id; 2997 2998 if (pc->batch_deposits.got_451) 2999 { 3000 pc->phase = PP_FAIL_LEGAL_REASONS; 3001 return; 3002 } 3003 /* Avoid re-trying transactions on soft errors forever! */ 3004 if (pc->pay_transaction.retry_counter++ > MAX_RETRIES) 3005 { 3006 GNUNET_break (0); 3007 pay_end (pc, 3008 TALER_MHD_reply_with_error (pc->connection, 3009 MHD_HTTP_INTERNAL_SERVER_ERROR, 3010 TALER_EC_GENERIC_DB_SOFT_FAILURE, 3011 NULL)); 3012 return; 3013 } 3014 3015 /* Initialize some amount accumulators 3016 (used in check_coin_paid(), check_coin_refunded() 3017 and check_payment_sufficient()). */ 3018 GNUNET_break (GNUNET_OK == 3019 TALER_amount_set_zero (pc->validate_tokens.brutto.currency, 3020 &pc->pay_transaction.total_paid)); 3021 GNUNET_break (GNUNET_OK == 3022 TALER_amount_set_zero (pc->validate_tokens.brutto.currency, 3023 &pc->pay_transaction.total_fees_paid)); 3024 GNUNET_break (GNUNET_OK == 3025 TALER_amount_set_zero (pc->validate_tokens.brutto.currency, 3026 &pc->pay_transaction.total_refunded)); 3027 for (size_t i = 0; i<pc->parse_pay.coins_cnt; i++) 3028 pc->parse_pay.dc[i].found_in_db = false; 3029 pc->pay_transaction.pending = pc->parse_pay.coins_cnt; 3030 3031 /* First, try to see if we have all we need already done */ 3032 TALER_MERCHANTDB_preflight (TMH_db); 3033 if (GNUNET_OK != 3034 TALER_MERCHANTDB_start (TMH_db, 3035 "run pay")) 3036 { 3037 GNUNET_break (0); 3038 pay_end (pc, 3039 TALER_MHD_reply_with_error (pc->connection, 3040 MHD_HTTP_INTERNAL_SERVER_ERROR, 3041 TALER_EC_GENERIC_DB_START_FAILED, 3042 NULL)); 3043 return; 3044 } 3045 3046 for (size_t i = 0; i<pc->parse_pay.tokens_cnt; i++) 3047 { 3048 struct TokenUseConfirmation *tuc = &pc->parse_pay.tokens[i]; 3049 enum GNUNET_DB_QueryStatus qs; 3050 bool no_family; 3051 3052 /* Insert used token into database, the unique constraint will 3053 case an error if this token was used before. */ 3054 qs = TALER_MERCHANTDB_insert_used_token (TMH_db, 3055 &pc->check_contract.h_contract_terms, 3056 &tuc->h_issue, 3057 &tuc->pub, 3058 &tuc->sig, 3059 &tuc->unblinded_sig, 3060 &no_family); 3061 3062 switch (qs) 3063 { 3064 case GNUNET_DB_STATUS_SOFT_ERROR: 3065 TALER_MERCHANTDB_rollback (TMH_db); 3066 return; /* do it again */ 3067 case GNUNET_DB_STATUS_HARD_ERROR: 3068 /* Always report on hard error as well to enable diagnostics */ 3069 TALER_MERCHANTDB_rollback (TMH_db); 3070 pay_end (pc, 3071 TALER_MHD_reply_with_error (pc->connection, 3072 MHD_HTTP_INTERNAL_SERVER_ERROR, 3073 TALER_EC_GENERIC_DB_STORE_FAILED, 3074 "insert used token")); 3075 return; 3076 case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS: 3077 TALER_MERCHANTDB_rollback (TMH_db); 3078 if (no_family) 3079 { 3080 /* The token family key was deleted after the order was created, 3081 so we cannot accept this token anymore. */ 3082 GNUNET_break_op (0); 3083 pay_end (pc, 3084 TALER_MHD_reply_with_error ( 3085 pc->connection, 3086 MHD_HTTP_NOT_FOUND, 3087 TALER_EC_MERCHANT_GENERIC_TOKEN_KEY_UNKNOWN, 3088 NULL)); 3089 return; 3090 } 3091 /* UNIQUE constraint violation, meaning this token was already used. */ 3092 pay_end (pc, 3093 TALER_MHD_reply_with_error (pc->connection, 3094 MHD_HTTP_CONFLICT, 3095 TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_TOKEN_INVALID, 3096 NULL)); 3097 return; 3098 case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT: 3099 /* Good, proceed! */ 3100 break; 3101 } 3102 } /* for all tokens */ 3103 3104 { 3105 enum GNUNET_DB_QueryStatus qs; 3106 3107 /* Check if some of these coins already succeeded for _this_ contract. */ 3108 qs = TALER_MERCHANTDB_iterate_deposits (TMH_db, 3109 instance_id, 3110 &pc->check_contract.h_contract_terms, 3111 &check_coin_paid, 3112 pc); 3113 if (0 > qs) 3114 { 3115 TALER_MERCHANTDB_rollback (TMH_db); 3116 if (GNUNET_DB_STATUS_SOFT_ERROR == qs) 3117 return; /* do it again */ 3118 /* Always report on hard error as well to enable diagnostics */ 3119 GNUNET_break (GNUNET_DB_STATUS_HARD_ERROR == qs); 3120 pay_end (pc, 3121 TALER_MHD_reply_with_error ( 3122 pc->connection, 3123 MHD_HTTP_INTERNAL_SERVER_ERROR, 3124 TALER_EC_GENERIC_DB_FETCH_FAILED, 3125 "lookup deposits")); 3126 return; 3127 } 3128 if (pc->pay_transaction.deposit_currency_mismatch) 3129 { 3130 TALER_MERCHANTDB_rollback (TMH_db); 3131 GNUNET_break_op (0); 3132 pay_end (pc, 3133 TALER_MHD_reply_with_error ( 3134 pc->connection, 3135 MHD_HTTP_BAD_REQUEST, 3136 TALER_EC_MERCHANT_GENERIC_CURRENCY_MISMATCH, 3137 pc->validate_tokens.brutto.currency)); 3138 return; 3139 } 3140 } 3141 3142 { 3143 enum GNUNET_DB_QueryStatus qs; 3144 3145 /* Check if we refunded some of the coins */ 3146 qs = TALER_MERCHANTDB_iterate_refunds (TMH_db, 3147 instance_id, 3148 &pc->check_contract.h_contract_terms, 3149 &check_coin_refunded, 3150 pc); 3151 if (0 > qs) 3152 { 3153 TALER_MERCHANTDB_rollback (TMH_db); 3154 if (GNUNET_DB_STATUS_SOFT_ERROR == qs) 3155 return; /* do it again */ 3156 /* Always report on hard error as well to enable diagnostics */ 3157 GNUNET_break (GNUNET_DB_STATUS_HARD_ERROR == qs); 3158 pay_end (pc, 3159 TALER_MHD_reply_with_error (pc->connection, 3160 MHD_HTTP_INTERNAL_SERVER_ERROR, 3161 TALER_EC_GENERIC_DB_FETCH_FAILED, 3162 "lookup refunds")); 3163 return; 3164 } 3165 if (pc->pay_transaction.refund_currency_mismatch) 3166 { 3167 TALER_MERCHANTDB_rollback (TMH_db); 3168 pay_end (pc, 3169 TALER_MHD_reply_with_error (pc->connection, 3170 MHD_HTTP_INTERNAL_SERVER_ERROR, 3171 TALER_EC_GENERIC_DB_FETCH_FAILED, 3172 "refund currency in database does not match order currency")); 3173 return; 3174 } 3175 } 3176 3177 /* Check if there are coins that still need to be processed */ 3178 if (0 != pc->pay_transaction.pending) 3179 { 3180 /* we made no DB changes, so we can just rollback */ 3181 TALER_MERCHANTDB_rollback (TMH_db); 3182 /* Ok, we need to first go to the network to process more coins. 3183 We that interaction in *tiny* transactions (hence the rollback 3184 above). */ 3185 pc->phase = PP_BATCH_DEPOSITS; 3186 return; 3187 } 3188 3189 /* 0 == pc->pay_transaction.pending: all coins processed, let's see if that was enough */ 3190 if (! check_payment_sufficient (pc)) 3191 { 3192 /* check_payment_sufficient() will have queued an error already. 3193 We need to still abort the transaction. */ 3194 TALER_MERCHANTDB_rollback (TMH_db); 3195 return; 3196 } 3197 /* Payment succeeded, save in database */ 3198 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 3199 "Order `%s' (%s) was fully paid\n", 3200 pc->order_id, 3201 GNUNET_h2s (&pc->check_contract.h_contract_terms.hash)); 3202 { 3203 enum GNUNET_DB_QueryStatus qs; 3204 3205 qs = TALER_MERCHANTDB_update_to_contract_terms_paid (TMH_db, 3206 instance_id, 3207 &pc->check_contract.h_contract_terms, 3208 pc->parse_pay.session_id, 3209 pc->parse_wallet_data.choice_index); 3210 if (qs < 0) 3211 { 3212 TALER_MERCHANTDB_rollback (TMH_db); 3213 if (GNUNET_DB_STATUS_SOFT_ERROR == qs) 3214 return; /* do it again */ 3215 GNUNET_break (0); 3216 pay_end (pc, 3217 TALER_MHD_reply_with_error (pc->connection, 3218 MHD_HTTP_INTERNAL_SERVER_ERROR, 3219 TALER_EC_GENERIC_DB_STORE_FAILED, 3220 "mark contract paid")); 3221 return; 3222 } 3223 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 3224 "Marked contract paid returned %d\n", 3225 (int) qs); 3226 3227 if ( (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT == qs) && 3228 (0 < pc->compute_money_pots.num_pots) ) 3229 { 3230 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 3231 "Incrementing %u money pots by %s\n", 3232 pc->compute_money_pots.num_pots, 3233 TALER_amount2s (&pc->compute_money_pots.increments[0])); 3234 qs = TALER_MERCHANTDB_update_money_pot_totals ( 3235 TMH_db, 3236 instance_id, 3237 pc->compute_money_pots.num_pots, 3238 pc->compute_money_pots.pots, 3239 pc->compute_money_pots.increments); 3240 switch (qs) 3241 { 3242 case GNUNET_DB_STATUS_SOFT_ERROR: 3243 TALER_MERCHANTDB_rollback (TMH_db); 3244 return; /* do it again */ 3245 case GNUNET_DB_STATUS_HARD_ERROR: 3246 /* Always report on hard error as well to enable diagnostics */ 3247 TALER_MERCHANTDB_rollback (TMH_db); 3248 pay_end (pc, 3249 TALER_MHD_reply_with_error ( 3250 pc->connection, 3251 MHD_HTTP_INTERNAL_SERVER_ERROR, 3252 TALER_EC_GENERIC_DB_STORE_FAILED, 3253 "update_money_pot_totals")); 3254 return; 3255 case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS: 3256 /* strange */ 3257 GNUNET_break (0); 3258 break; 3259 case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT: 3260 /* Good, proceed! */ 3261 break; 3262 } 3263 } 3264 } 3265 3266 { 3267 const struct TALER_MERCHANT_ContractChoice *choice = 3268 &pc->check_contract.contract_terms->pc->details.v1 3269 .choices[pc->parse_wallet_data.choice_index]; 3270 3271 for (size_t i = 0; i<pc->output_tokens_len; i++) 3272 { 3273 unsigned int output_index; 3274 enum TALER_MERCHANT_ContractOutputType type; 3275 3276 output_index = pc->output_tokens[i].output_index; 3277 GNUNET_assert (output_index < choice->outputs_len); 3278 type = choice->outputs[output_index].type; 3279 switch (type) 3280 { 3281 case TALER_MERCHANT_CONTRACT_OUTPUT_TYPE_INVALID: 3282 /* Well, good luck getting here */ 3283 GNUNET_break (0); 3284 pay_end (pc, 3285 TALER_MHD_reply_with_error (pc->connection, 3286 MHD_HTTP_INTERNAL_SERVER_ERROR, 3287 TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE, 3288 "invalid output type")); 3289 break; 3290 case TALER_MERCHANT_CONTRACT_OUTPUT_TYPE_DONATION_RECEIPT: 3291 /* We skip output tokens of donation receipts here, as they are handled in the 3292 * phase_final_output_token_processing() callback from donau */ 3293 break; 3294 case TALER_MERCHANT_CONTRACT_OUTPUT_TYPE_TOKEN: 3295 struct SignedOutputToken *output = 3296 &pc->output_tokens[i]; 3297 enum GNUNET_DB_QueryStatus qs; 3298 bool no_family; 3299 3300 if (NULL == output->sig.signature) 3301 continue; /* must have been optional and not provided by wallet */ 3302 qs = TALER_MERCHANTDB_insert_issued_token ( 3303 TMH_db, 3304 &pc->check_contract.h_contract_terms, 3305 &output->h_issue, 3306 &output->sig, 3307 &no_family); 3308 switch (qs) 3309 { 3310 case GNUNET_DB_STATUS_HARD_ERROR: 3311 TALER_MERCHANTDB_rollback (TMH_db); 3312 GNUNET_break (GNUNET_DB_STATUS_HARD_ERROR == qs); 3313 pay_end (pc, 3314 TALER_MHD_reply_with_error ( 3315 pc->connection, 3316 MHD_HTTP_INTERNAL_SERVER_ERROR, 3317 TALER_EC_GENERIC_DB_STORE_FAILED, 3318 "insert output token")); 3319 return; 3320 case GNUNET_DB_STATUS_SOFT_ERROR: 3321 /* Serialization failure, retry */ 3322 TALER_MERCHANTDB_rollback (TMH_db); 3323 return; 3324 case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS: 3325 TALER_MERCHANTDB_rollback (TMH_db); 3326 if (no_family) 3327 { 3328 /* The token family key was deleted after the order was 3329 created, so we cannot issue this token anymore. */ 3330 GNUNET_break_op (0); 3331 pay_end (pc, 3332 TALER_MHD_reply_with_error ( 3333 pc->connection, 3334 MHD_HTTP_NOT_FOUND, 3335 TALER_EC_MERCHANT_GENERIC_TOKEN_KEY_UNKNOWN, 3336 NULL)); 3337 return; 3338 } 3339 /* UNIQUE constraint violation, meaning this token was already used. */ 3340 pay_end (pc, 3341 TALER_MHD_reply_with_error ( 3342 pc->connection, 3343 MHD_HTTP_INTERNAL_SERVER_ERROR, 3344 TALER_EC_GENERIC_DB_STORE_FAILED, 3345 "duplicate output token")); 3346 return; 3347 case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT: 3348 break; 3349 } 3350 break; 3351 } 3352 } 3353 } 3354 3355 TMH_notify_order_change ( 3356 hc->instance, 3357 TMH_OSF_CLAIMED | TMH_OSF_PAID, 3358 pc->check_contract.contract_terms->pc->timestamp, 3359 pc->check_contract.order_serial); 3360 { 3361 enum GNUNET_DB_QueryStatus qs; 3362 json_t *jhook; 3363 3364 jhook = GNUNET_JSON_PACK ( 3365 GNUNET_JSON_pack_object_incref ("contract_terms", 3366 pc->check_contract.contract_terms_json), 3367 GNUNET_JSON_pack_string ("order_id", 3368 pc->order_id) 3369 ); 3370 GNUNET_assert (NULL != jhook); 3371 qs = TMH_trigger_webhook (pc->hc->instance->settings.id, 3372 "pay", 3373 jhook); 3374 json_decref (jhook); 3375 if (qs < 0) 3376 { 3377 TALER_MERCHANTDB_rollback (TMH_db); 3378 if (GNUNET_DB_STATUS_SOFT_ERROR == qs) 3379 return; /* do it again */ 3380 GNUNET_break (0); 3381 pay_end (pc, 3382 TALER_MHD_reply_with_error (pc->connection, 3383 MHD_HTTP_INTERNAL_SERVER_ERROR, 3384 TALER_EC_GENERIC_DB_STORE_FAILED, 3385 "failed to trigger webhooks")); 3386 return; 3387 } 3388 } 3389 { 3390 enum GNUNET_DB_QueryStatus qs; 3391 3392 /* Now commit! */ 3393 qs = TALER_MERCHANTDB_commit (TMH_db); 3394 if (0 > qs) 3395 { 3396 /* commit failed */ 3397 TALER_MERCHANTDB_rollback (TMH_db); 3398 if (GNUNET_DB_STATUS_SOFT_ERROR == qs) 3399 return; /* do it again */ 3400 GNUNET_break (0); 3401 pay_end (pc, 3402 TALER_MHD_reply_with_error (pc->connection, 3403 MHD_HTTP_INTERNAL_SERVER_ERROR, 3404 TALER_EC_GENERIC_DB_COMMIT_FAILED, 3405 NULL)); 3406 return; 3407 } 3408 } 3409 pc->phase++; 3410 } 3411 3412 3413 /** 3414 * Ensures that the expected number of tokens for a @e key 3415 * are provided as inputs and have valid signatures. 3416 * 3417 * @param[in,out] pc payment context we are processing 3418 * @param family family the tokens should be from 3419 * @param index offset into parse_pay.tokens where the 3420 * input tokens for @a family should start 3421 * @param expected_num number of tokens expected 3422 * @return #GNUNET_YES on success 3423 */ 3424 static enum GNUNET_GenericReturnValue 3425 find_valid_input_tokens ( 3426 struct PayContext *pc, 3427 const struct TALER_MERCHANT_ContractTokenFamily *family, 3428 unsigned int index, 3429 unsigned int expected_num) 3430 { 3431 unsigned int num_validated = 0; 3432 struct GNUNET_TIME_Timestamp now 3433 = GNUNET_TIME_timestamp_get (); 3434 const struct TALER_MERCHANT_ContractTokenFamilyKey *kig = NULL; 3435 3436 for (unsigned int j = 0; j < expected_num; j++) 3437 { 3438 struct TokenUseConfirmation *tuc; 3439 const struct TALER_MERCHANT_ContractTokenFamilyKey *key = NULL; 3440 3441 if (index + j >= pc->parse_pay.tokens_cnt) 3442 { 3443 /* There are not a sufficient number of input tokens left 3444 to satisfy the request. Game over. */ 3445 GNUNET_break_op (0); 3446 pay_end (pc, 3447 TALER_MHD_reply_with_error ( 3448 pc->connection, 3449 MHD_HTTP_BAD_REQUEST, 3450 TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_TOKEN_COUNT_MISMATCH, 3451 NULL)); 3452 return GNUNET_NO; 3453 } 3454 tuc = &pc->parse_pay.tokens[index + j]; 3455 3456 for (unsigned int i = 0; i<family->keys_len; i++) 3457 { 3458 const struct TALER_MERCHANT_ContractTokenFamilyKey *ki 3459 = &family->keys[i]; 3460 3461 if (0 == 3462 GNUNET_memcmp (&ki->pub.public_key->pub_key_hash, 3463 &tuc->h_issue.hash)) 3464 { 3465 if (GNUNET_TIME_timestamp_cmp (ki->valid_after, 3466 >, 3467 now) || 3468 GNUNET_TIME_timestamp_cmp (ki->valid_before, 3469 <=, 3470 now)) 3471 { 3472 /* We have a match, but not in the current validity period */ 3473 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 3474 "Public key %s currently not valid\n", 3475 GNUNET_h2s (&ki->pub.public_key->pub_key_hash)); 3476 kig = ki; 3477 continue; 3478 } 3479 key = ki; 3480 break; 3481 } 3482 } 3483 if (NULL == key) 3484 { 3485 if (NULL != kig) 3486 { 3487 char start_str[128]; 3488 char end_str[128]; 3489 char emsg[350]; 3490 3491 GNUNET_snprintf (start_str, 3492 sizeof (start_str), 3493 "%s", 3494 GNUNET_STRINGS_timestamp_to_string (kig->valid_after)); 3495 GNUNET_snprintf (end_str, 3496 sizeof (end_str), 3497 "%s", 3498 GNUNET_STRINGS_timestamp_to_string (kig->valid_before)); 3499 /* FIXME: use more specific EC */ 3500 GNUNET_snprintf (emsg, 3501 sizeof (emsg), 3502 "Token is only valid from %s to %s", 3503 start_str, 3504 end_str); 3505 pay_end (pc, 3506 TALER_MHD_reply_with_error ( 3507 pc->connection, 3508 MHD_HTTP_GONE, 3509 TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_OFFER_EXPIRED, 3510 emsg)); 3511 return GNUNET_NO; 3512 } 3513 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 3514 "Input token supplied for public key %s that is not acceptable\n", 3515 GNUNET_h2s (&tuc->h_issue.hash)); 3516 GNUNET_break_op (0); 3517 pay_end (pc, 3518 TALER_MHD_reply_with_error ( 3519 pc->connection, 3520 MHD_HTTP_BAD_REQUEST, 3521 TALER_EC_MERCHANT_GENERIC_TOKEN_KEY_UNKNOWN, 3522 NULL)); 3523 return GNUNET_NO; 3524 } 3525 if (GNUNET_OK != 3526 TALER_token_issue_verify (&tuc->pub, 3527 &key->pub, 3528 &tuc->unblinded_sig)) 3529 { 3530 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 3531 "Input token for public key with valid_after " 3532 "`%s' has invalid issue signature\n", 3533 GNUNET_TIME_timestamp2s (key->valid_after)); 3534 GNUNET_break (0); 3535 pay_end (pc, 3536 TALER_MHD_reply_with_error ( 3537 pc->connection, 3538 MHD_HTTP_BAD_REQUEST, 3539 TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_TOKEN_ISSUE_SIG_INVALID, 3540 NULL)); 3541 return GNUNET_NO; 3542 } 3543 3544 if (GNUNET_OK != 3545 TALER_wallet_token_use_verify (&pc->check_contract.h_contract_terms, 3546 &pc->parse_wallet_data.h_wallet_data, 3547 &tuc->pub, 3548 &tuc->sig)) 3549 { 3550 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 3551 "Input token for public key with valid_before " 3552 "`%s' has invalid use signature\n", 3553 GNUNET_TIME_timestamp2s (key->valid_before)); 3554 GNUNET_break (0); 3555 pay_end (pc, 3556 TALER_MHD_reply_with_error ( 3557 pc->connection, 3558 MHD_HTTP_BAD_REQUEST, 3559 TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_TOKEN_USE_SIG_INVALID, 3560 NULL)); 3561 return GNUNET_NO; 3562 } 3563 num_validated++; 3564 } 3565 GNUNET_assert (num_validated == expected_num); 3566 return GNUNET_YES; 3567 } 3568 3569 3570 /** 3571 * Check if an output token of the given @a tfk is mandatory, or if 3572 * wallets are allowed to simply not support it and still proceed. 3573 * 3574 * @param tfk token family kind to check 3575 * @return true if such outputs are mandatory and wallets must supply 3576 * the corresponding blinded input 3577 */ 3578 /* FIXME: this function belongs into a lower-level lib! */ 3579 static bool 3580 test_tfk_mandatory (enum TALER_MERCHANTDB_TokenFamilyKind tfk) 3581 { 3582 switch (tfk) 3583 { 3584 case TALER_MERCHANTDB_TFK_Discount: 3585 return false; 3586 case TALER_MERCHANTDB_TFK_Subscription: 3587 return true; 3588 } 3589 GNUNET_break (0); 3590 return false; 3591 } 3592 3593 3594 /** 3595 * Sign the tokens provided by the wallet for a particular @a key. 3596 * 3597 * @param[in,out] pc reference for payment we are processing 3598 * @param key token family data 3599 * @param priv private key to use to sign with 3600 * @param mandatory true if the token must exist, if false 3601 * and the client did not provide an envelope, that's OK and 3602 * we just also skimp on the signature 3603 * @param wallet_index starting offset in the token envelopes array 3604 * @param output_index starting offset into the output_tokens array 3605 * @param expected_num number of tokens of this type that we should create 3606 * @return #GNUNET_NO on failure 3607 * #GNUNET_OK on success 3608 */ 3609 static enum GNUNET_GenericReturnValue 3610 sign_token_envelopes ( 3611 struct PayContext *pc, 3612 const struct TALER_MERCHANT_ContractTokenFamilyKey *key, 3613 const struct TALER_TokenIssuePrivateKey *priv, 3614 bool mandatory, 3615 unsigned int wallet_index, 3616 unsigned int output_index, 3617 unsigned int expected_num) 3618 { 3619 unsigned int num_signed = 0; 3620 3621 for (unsigned int j = 0; j<expected_num; j++) 3622 { 3623 unsigned int wallet_pos = wallet_index + j; 3624 unsigned int output_pos = output_index + j; 3625 const struct TokenEnvelope *env 3626 = &pc->parse_wallet_data.token_envelopes[wallet_pos]; 3627 struct SignedOutputToken *output 3628 = &pc->output_tokens[output_pos]; 3629 3630 if (wallet_pos >= pc->parse_wallet_data.token_envelopes_cnt) 3631 { 3632 if (! mandatory) 3633 return GNUNET_OK; /* wallet input too short, we can live with it */ 3634 3635 /* mandatory token families require a token envelope, and 3636 the wallet did not provide enough of them */ 3637 GNUNET_break_op (0); 3638 pay_end (pc, 3639 TALER_MHD_reply_with_error ( 3640 pc->connection, 3641 MHD_HTTP_BAD_REQUEST, 3642 TALER_EC_GENERIC_PARAMETER_MALFORMED, 3643 "Token envelope for mandatory token family missing")); 3644 return GNUNET_NO; 3645 } 3646 if (output_pos >= pc->output_tokens_len) 3647 { 3648 GNUNET_assert (0); /* this should not happen, we *computed* 3649 output_tokens_len to be big enough! */ 3650 return GNUNET_NO; 3651 } 3652 if (NULL == env->blinded_token.blinded_pub) 3653 { 3654 if (! mandatory) 3655 continue; 3656 3657 /* mandatory token families require a token envelope. */ 3658 GNUNET_break_op (0); 3659 pay_end (pc, 3660 TALER_MHD_reply_with_error ( 3661 pc->connection, 3662 MHD_HTTP_BAD_REQUEST, 3663 TALER_EC_GENERIC_PARAMETER_MALFORMED, 3664 "Token envelope for mandatory token family missing")); 3665 return GNUNET_NO; 3666 } 3667 TALER_token_issue_sign (priv, 3668 &env->blinded_token, 3669 &output->sig); 3670 output->h_issue.hash 3671 = key->pub.public_key->pub_key_hash; 3672 num_signed++; 3673 } 3674 3675 if (mandatory && 3676 (num_signed != expected_num) ) 3677 { 3678 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 3679 "Expected %d token envelopes for public key with valid_after " 3680 "'%s', but found %d\n", 3681 expected_num, 3682 GNUNET_TIME_timestamp2s (key->valid_after), 3683 num_signed); 3684 GNUNET_break (0); 3685 pay_end (pc, 3686 TALER_MHD_reply_with_error ( 3687 pc->connection, 3688 MHD_HTTP_BAD_REQUEST, 3689 TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_TOKEN_ENVELOPE_COUNT_MISMATCH, 3690 NULL)); 3691 return GNUNET_NO; 3692 } 3693 3694 return GNUNET_OK; 3695 } 3696 3697 3698 /** 3699 * Find the family entry for the family of the given @a slug 3700 * in @a pc. 3701 * 3702 * @param[in] pc payment context to search 3703 * @param slug slug to search for 3704 * @return NULL if @a slug was not found 3705 */ 3706 static const struct TALER_MERCHANT_ContractTokenFamily * 3707 find_family (const struct PayContext *pc, 3708 const char *slug) 3709 { 3710 for (unsigned int i = 0; 3711 i < pc->check_contract.contract_terms->pc->details.v1.token_authorities_len; 3712 i++) 3713 { 3714 const struct TALER_MERCHANT_ContractTokenFamily *tfi 3715 = &pc->check_contract.contract_terms->pc->details.v1.token_authorities[i]; 3716 3717 if (0 == strcmp (tfi->slug, 3718 slug)) 3719 { 3720 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 3721 "Token family %s found with %u keys\n", 3722 slug, 3723 tfi->keys_len); 3724 return tfi; 3725 } 3726 } 3727 return NULL; 3728 } 3729 3730 3731 /** 3732 * Handle contract output of type TALER_MERCHANT_CONTRACT_OUTPUT_TYPE_TOKEN. 3733 * Looks up the token family, loads the matching private key, 3734 * and signs the corresponding token envelopes from the wallet. 3735 * 3736 * @param[in,out] pc context for the pay request 3737 * @param wallet_index start index of this output in the 3738 * ``parse_wallet_data.token_envelopes`` array 3739 * @param output contract output we need to process 3740 * @param output_index start index of this output in the 3741 * ``output_tokens`` array of @a pc 3742 * @return #GNUNET_OK on success, #GNUNET_NO if an error was encountered 3743 */ 3744 static enum GNUNET_GenericReturnValue 3745 handle_output_token (struct PayContext *pc, 3746 unsigned int wallet_index, 3747 const struct TALER_MERCHANT_ContractOutput *output, 3748 unsigned int output_index) 3749 { 3750 const struct TALER_MERCHANT_ContractTokenFamily *family; 3751 struct TALER_MERCHANT_ContractTokenFamilyKey *key; 3752 struct TALER_MERCHANTDB_TokenFamilyKeyDetails details; 3753 enum GNUNET_DB_QueryStatus qs; 3754 bool mandatory; 3755 3756 /* Locate token family in the contract. 3757 This should ever fail as this invariant should 3758 have been checked when the contract was created. */ 3759 family = find_family (pc, 3760 output->details.token.token_family_slug); 3761 if (NULL == family) 3762 { 3763 /* This "should never happen", so treat it as an internal error */ 3764 GNUNET_break (0); 3765 pay_end (pc, 3766 TALER_MHD_reply_with_error ( 3767 pc->connection, 3768 MHD_HTTP_INTERNAL_SERVER_ERROR, 3769 TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE, 3770 "token family not found in order")); 3771 return GNUNET_SYSERR; 3772 } 3773 3774 /* Check the key_index field from the output. */ 3775 if (output->details.token.key_index >= family->keys_len) 3776 { 3777 /* Also "should never happen", contract was presumably validated on insert */ 3778 GNUNET_break (0); 3779 pay_end (pc, 3780 TALER_MHD_reply_with_error ( 3781 pc->connection, 3782 MHD_HTTP_INTERNAL_SERVER_ERROR, 3783 TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE, 3784 "key index invalid for token family")); 3785 return GNUNET_SYSERR; 3786 } 3787 3788 /* Pick the correct key inside that family. */ 3789 key = &family->keys[output->details.token.key_index]; 3790 3791 /* Fetch the private key from the DB for the merchant instance and 3792 * this particular family/time interval. */ 3793 qs = TALER_MERCHANTDB_get_token_family_key ( 3794 TMH_db, 3795 pc->hc->instance->settings.id, 3796 family->slug, 3797 pc->check_contract.contract_terms->pc->timestamp, 3798 pc->check_contract.contract_terms->pc->pay_deadline, 3799 &details); 3800 switch (qs) 3801 { 3802 case GNUNET_DB_STATUS_HARD_ERROR: 3803 case GNUNET_DB_STATUS_SOFT_ERROR: 3804 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 3805 "Database error looking up token-family key for %s\n", 3806 family->slug); 3807 GNUNET_break (0); 3808 pay_end (pc, 3809 TALER_MHD_reply_with_error ( 3810 pc->connection, 3811 MHD_HTTP_INTERNAL_SERVER_ERROR, 3812 TALER_EC_GENERIC_DB_FETCH_FAILED, 3813 NULL)); 3814 return GNUNET_NO; 3815 case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS: 3816 GNUNET_log ( 3817 GNUNET_ERROR_TYPE_ERROR, 3818 "Token-family key for %s not found at [%llu,%llu]\n", 3819 family->slug, 3820 (unsigned long long) 3821 pc->check_contract.contract_terms->pc->timestamp.abs_time.abs_value_us, 3822 (unsigned long long) 3823 pc->check_contract.contract_terms->pc->pay_deadline.abs_time.abs_value_us 3824 ); 3825 GNUNET_break (0); 3826 pay_end (pc, 3827 TALER_MHD_reply_with_error ( 3828 pc->connection, 3829 MHD_HTTP_NOT_FOUND, 3830 TALER_EC_MERCHANT_GENERIC_TOKEN_KEY_UNKNOWN, 3831 family->slug)); 3832 return GNUNET_NO; 3833 3834 case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT: 3835 break; 3836 } 3837 GNUNET_free (details.token_family.slug); 3838 GNUNET_free (details.token_family.name); 3839 GNUNET_free (details.token_family.description); 3840 json_decref (details.token_family.description_i18n); 3841 if (NULL != details.pub.public_key) 3842 GNUNET_CRYPTO_blind_sign_pub_decref (details.pub.public_key); 3843 GNUNET_free (details.token_family.cipher_spec); 3844 if (NULL == details.priv.private_key) 3845 { 3846 /* The key must exist: the LEFT JOIN in get_token_family_key() 3847 only yields a NULL private key if no key covers the validity 3848 period *and* survives until the pay deadline, and POST /orders 3849 guarantees exactly that before it commits the contract terms 3850 (it extends the retention of an existing key or mints a new 3851 one, see #11692). Kept as a safety net. */ 3852 GNUNET_break (0); 3853 pay_end (pc, 3854 TALER_MHD_reply_with_error ( 3855 pc->connection, 3856 MHD_HTTP_INTERNAL_SERVER_ERROR, 3857 TALER_EC_GENERIC_DB_INVARIANT_FAILURE, 3858 "private token family key not found")); 3859 return GNUNET_NO; 3860 3861 } 3862 3863 /* Depending on the token family, decide if the token envelope 3864 * is mandatory or optional. (Simplified logic here: adapt as needed.) */ 3865 mandatory = test_tfk_mandatory (details.token_family.kind); 3866 /* Actually sign the number of token envelopes specified in 'count'. 3867 * 'output_index' is the offset into the output_tokens while 3868 * 'wallet_index' is the offset into parse_wallet_data.token_envelopes */ 3869 if (GNUNET_OK != 3870 sign_token_envelopes (pc, 3871 key, 3872 &details.priv, 3873 mandatory, 3874 wallet_index, 3875 output_index, 3876 output->details.token.count)) 3877 { 3878 /* sign_token_envelopes() already queued up an error via pay_end() */ 3879 GNUNET_break_op (0); 3880 GNUNET_CRYPTO_blind_sign_priv_decref (details.priv.private_key); 3881 return GNUNET_NO; 3882 } 3883 GNUNET_CRYPTO_blind_sign_priv_decref (details.priv.private_key); 3884 return GNUNET_OK; 3885 } 3886 3887 3888 /** 3889 * Handle checks for contract output of type 3890 * #TALER_MERCHANT_CONTRACT_OUTPUT_TYPE_DONATION_RECEIPT. 3891 * 3892 * @param pc context for the pay request 3893 * @param output the contract output describing the donation receipt requirement 3894 * @return #GNUNET_OK on success, 3895 * #GNUNET_NO if an error was already queued 3896 */ 3897 static enum GNUNET_GenericReturnValue 3898 handle_output_donation_receipt ( 3899 struct PayContext *pc, 3900 const struct TALER_MERCHANT_ContractOutput *output) 3901 { 3902 enum GNUNET_GenericReturnValue ret; 3903 3904 ret = DONAU_get_donation_amount_from_bkps ( 3905 pc->parse_wallet_data.donau_keys, 3906 pc->parse_wallet_data.bkps, 3907 pc->parse_wallet_data.num_bkps, 3908 pc->parse_wallet_data.donau.donation_year, 3909 &pc->parse_wallet_data.donation_amount); 3910 switch (ret) 3911 { 3912 case GNUNET_SYSERR: 3913 GNUNET_break (0); 3914 pay_end (pc, 3915 TALER_MHD_reply_with_error ( 3916 pc->connection, 3917 MHD_HTTP_INTERNAL_SERVER_ERROR, 3918 TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE, 3919 NULL)); 3920 return GNUNET_NO; 3921 case GNUNET_NO: 3922 GNUNET_break_op (0); 3923 pay_end (pc, 3924 TALER_MHD_reply_with_error ( 3925 pc->connection, 3926 MHD_HTTP_BAD_REQUEST, 3927 TALER_EC_GENERIC_PARAMETER_MALFORMED, 3928 "inconsistent bkps / donau keys")); 3929 return GNUNET_NO; 3930 case GNUNET_OK: 3931 break; 3932 } 3933 3934 if (GNUNET_OK != 3935 TALER_amount_cmp_currency (&pc->parse_wallet_data.donation_amount, 3936 &output->details.donation_receipt.amount)) 3937 { 3938 GNUNET_break_op (0); 3939 pay_end (pc, 3940 TALER_MHD_reply_with_error ( 3941 pc->connection, 3942 MHD_HTTP_BAD_REQUEST, 3943 TALER_EC_GENERIC_CURRENCY_MISMATCH, 3944 output->details.donation_receipt.amount.currency)); 3945 return GNUNET_NO; 3946 } 3947 3948 if (0 != 3949 TALER_amount_cmp (&pc->parse_wallet_data.donation_amount, 3950 &output->details.donation_receipt.amount)) 3951 { 3952 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 3953 "Wallet amount: %s\n", 3954 TALER_amount2s (&pc->parse_wallet_data.donation_amount)); 3955 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 3956 "Donation receipt amount: %s\n", 3957 TALER_amount2s (&output->details.donation_receipt.amount)); 3958 GNUNET_break_op (0); 3959 pay_end (pc, 3960 TALER_MHD_reply_with_error ( 3961 pc->connection, 3962 MHD_HTTP_CONFLICT, 3963 TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_DONATION_AMOUNT_MISMATCH, 3964 "donation amount mismatch")); 3965 return GNUNET_NO; 3966 } 3967 { 3968 struct TALER_Amount receipts_to_date; 3969 3970 if (0 > 3971 TALER_amount_add (&receipts_to_date, 3972 &pc->parse_wallet_data.charity_receipts_to_date, 3973 &pc->parse_wallet_data.donation_amount)) 3974 { 3975 GNUNET_break (0); 3976 pay_end (pc, 3977 TALER_MHD_reply_with_error (pc->connection, 3978 MHD_HTTP_INTERNAL_SERVER_ERROR, 3979 TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_AMOUNT_OVERFLOW, 3980 "adding donation amount")); 3981 return GNUNET_NO; 3982 } 3983 3984 if (1 == 3985 TALER_amount_cmp (&receipts_to_date, 3986 &pc->parse_wallet_data.charity_max_per_year)) 3987 { 3988 GNUNET_break_op (0); 3989 pay_end (pc, 3990 TALER_MHD_reply_with_error (pc->connection, 3991 MHD_HTTP_CONFLICT, 3992 TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_DONATION_AMOUNT_MISMATCH, 3993 "donation limit exceeded")); 3994 return GNUNET_NO; 3995 } 3996 pc->parse_wallet_data.charity_receipts_to_date = receipts_to_date; 3997 } 3998 return GNUNET_OK; 3999 } 4000 4001 4002 /** 4003 * Count tokens produced by an output. 4004 * 4005 * @param pc pay context 4006 * @param output output to consider 4007 * @returns number of output tokens 4008 */ 4009 static unsigned int 4010 count_output_tokens (const struct PayContext *pc, 4011 const struct TALER_MERCHANT_ContractOutput *output) 4012 { 4013 switch (output->type) 4014 { 4015 case TALER_MERCHANT_CONTRACT_OUTPUT_TYPE_INVALID: 4016 GNUNET_assert (0); 4017 break; 4018 case TALER_MERCHANT_CONTRACT_OUTPUT_TYPE_TOKEN: 4019 return output->details.token.count; 4020 case TALER_MERCHANT_CONTRACT_OUTPUT_TYPE_DONATION_RECEIPT: 4021 return pc->parse_wallet_data.num_bkps; 4022 } 4023 /* Not reached. */ 4024 GNUNET_assert (0); 4025 } 4026 4027 4028 /** 4029 * Validate tokens and token envelopes. First, we check if all tokens listed 4030 * in the 'inputs' array of the selected choice are present in the 'tokens' 4031 * array of the request. Then, we validate the signatures of each provided 4032 * token. 4033 * 4034 * @param[in,out] pc context we use to handle the payment 4035 */ 4036 static void 4037 phase_validate_tokens (struct PayContext *pc) 4038 { 4039 /* We haven't seen a donau output yet. */ 4040 pc->validate_tokens.donau_output_index = -1; 4041 4042 switch (pc->check_contract.contract_terms->pc->base->version) 4043 { 4044 case TALER_MERCHANT_CONTRACT_VERSION_0: 4045 /* No tokens to validate */ 4046 pc->phase = PP_COMPUTE_MONEY_POTS; 4047 pc->validate_tokens.max_fee 4048 = pc->check_contract.contract_terms->pc->details.v0.max_fee; 4049 pc->validate_tokens.brutto 4050 = pc->check_contract.contract_terms->pc->details.v0.brutto; 4051 break; 4052 case TALER_MERCHANT_CONTRACT_VERSION_1: 4053 { 4054 const struct TALER_MERCHANT_ContractChoice *selected 4055 = &pc->check_contract.contract_terms->pc->details.v1.choices[ 4056 pc->parse_wallet_data.choice_index]; 4057 unsigned int output_off; 4058 unsigned int wallet_off; 4059 unsigned int cnt; 4060 4061 pc->validate_tokens.max_fee = selected->max_fee; 4062 pc->validate_tokens.brutto = selected->amount; 4063 wallet_off = 0; 4064 for (unsigned int i = 0; i<selected->inputs_len; i++) 4065 { 4066 const struct TALER_MERCHANT_ContractInput *input 4067 = &selected->inputs[i]; 4068 const struct TALER_MERCHANT_ContractTokenFamily *family; 4069 4070 switch (input->type) 4071 { 4072 case TALER_MERCHANT_CONTRACT_INPUT_TYPE_INVALID: 4073 GNUNET_break (0); 4074 pay_end (pc, 4075 TALER_MHD_reply_with_error ( 4076 pc->connection, 4077 MHD_HTTP_BAD_REQUEST, 4078 TALER_EC_GENERIC_PARAMETER_MALFORMED, 4079 "input token type not valid")); 4080 return; 4081 #if FUTURE 4082 case TALER_MERCHANT_CONTRACT_INPUT_TYPE_COIN: 4083 GNUNET_break (0); 4084 pay_end (pc, 4085 TALER_MHD_reply_with_error ( 4086 pc->connection, 4087 MHD_HTTP_NOT_IMPLEMENTED, 4088 TALER_EC_MERCHANT_GENERIC_FEATURE_NOT_AVAILABLE, 4089 "token type not yet supported")); 4090 return; 4091 #endif 4092 case TALER_MERCHANT_CONTRACT_INPUT_TYPE_TOKEN: 4093 family = find_family (pc, 4094 input->details.token.token_family_slug); 4095 if (NULL == family) 4096 { 4097 /* this should never happen, since the choices and 4098 token families are validated on insert. */ 4099 GNUNET_break (0); 4100 pay_end (pc, 4101 TALER_MHD_reply_with_error ( 4102 pc->connection, 4103 MHD_HTTP_INTERNAL_SERVER_ERROR, 4104 TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE, 4105 "token family not found in order")); 4106 return; 4107 } 4108 if (GNUNET_NO == 4109 find_valid_input_tokens (pc, 4110 family, 4111 wallet_off, 4112 input->details.token.count)) 4113 { 4114 /* Error is already scheduled from find_valid_input_token. */ 4115 return; 4116 } 4117 wallet_off += input->details.token.count; 4118 } 4119 } 4120 4121 /* calculate pc->output_tokens_len */ 4122 output_off = 0; 4123 for (unsigned int i = 0; i<selected->outputs_len; i++) 4124 { 4125 const struct TALER_MERCHANT_ContractOutput *output 4126 = &selected->outputs[i]; 4127 4128 switch (output->type) 4129 { 4130 case TALER_MERCHANT_CONTRACT_OUTPUT_TYPE_INVALID: 4131 GNUNET_assert (0); 4132 break; 4133 case TALER_MERCHANT_CONTRACT_OUTPUT_TYPE_TOKEN: 4134 cnt = output->details.token.count; 4135 if (output_off + cnt < output_off) 4136 { 4137 GNUNET_break_op (0); 4138 pay_end (pc, 4139 TALER_MHD_reply_with_error ( 4140 pc->connection, 4141 MHD_HTTP_BAD_REQUEST, 4142 TALER_EC_GENERIC_PARAMETER_MALFORMED, 4143 "output token counter overflow")); 4144 return; 4145 } 4146 output_off += cnt; 4147 break; 4148 case TALER_MERCHANT_CONTRACT_OUTPUT_TYPE_DONATION_RECEIPT: 4149 /* check that this output type appears at most once */ 4150 if (pc->validate_tokens.donau_output_index >= 0) 4151 { 4152 /* This should have been prevented when the 4153 contract was initially created */ 4154 GNUNET_break (0); 4155 pay_end (pc, 4156 TALER_MHD_reply_with_error ( 4157 pc->connection, 4158 MHD_HTTP_INTERNAL_SERVER_ERROR, 4159 TALER_EC_GENERIC_DB_INVARIANT_FAILURE, 4160 "two donau output sets in same contract")); 4161 return; 4162 } 4163 pc->validate_tokens.donau_output_index = i; 4164 if (output_off + pc->parse_wallet_data.num_bkps < output_off) 4165 { 4166 GNUNET_break_op (0); 4167 pay_end (pc, 4168 TALER_MHD_reply_with_error ( 4169 pc->connection, 4170 MHD_HTTP_BAD_REQUEST, 4171 TALER_EC_GENERIC_PARAMETER_MALFORMED, 4172 "output token counter overflow")); 4173 return; 4174 } 4175 output_off += pc->parse_wallet_data.num_bkps; 4176 break; 4177 } 4178 } 4179 4180 4181 pc->output_tokens_len = output_off; 4182 pc->output_tokens 4183 = GNUNET_new_array (pc->output_tokens_len, 4184 struct SignedOutputToken); 4185 4186 /* calculate pc->output_tokens[].output_index */ 4187 output_off = 0; /* index into output_tokens */ 4188 for (unsigned int i = 0; i<selected->outputs_len; i++) 4189 { 4190 const struct TALER_MERCHANT_ContractOutput *output 4191 = &selected->outputs[i]; 4192 4193 cnt = count_output_tokens (pc, 4194 output); 4195 for (unsigned int j = 0; j<cnt; j++) 4196 pc->output_tokens[output_off + j].output_index = i; 4197 output_off += cnt; 4198 } 4199 4200 /* compute non-donau outputs */ 4201 output_off = 0; /* index into output_tokens */ 4202 wallet_off = 0; /* index into parse_wallet_data.token_envelopes */ 4203 for (unsigned int i = 0; i<selected->outputs_len; i++) 4204 { 4205 const struct TALER_MERCHANT_ContractOutput *output 4206 = &selected->outputs[i]; 4207 4208 switch (output->type) 4209 { 4210 case TALER_MERCHANT_CONTRACT_OUTPUT_TYPE_INVALID: 4211 GNUNET_assert (0); 4212 break; 4213 case TALER_MERCHANT_CONTRACT_OUTPUT_TYPE_TOKEN: 4214 cnt = output->details.token.count; 4215 GNUNET_assert (output_off + cnt 4216 <= pc->output_tokens_len); 4217 if (GNUNET_OK != 4218 handle_output_token (pc, 4219 wallet_off, 4220 output, 4221 output_off)) 4222 { 4223 /* Error is already scheduled from handle_output_token. */ 4224 return; 4225 } 4226 output_off += cnt; 4227 wallet_off += cnt; 4228 break; 4229 case TALER_MERCHANT_CONTRACT_OUTPUT_TYPE_DONATION_RECEIPT: 4230 if ( (0 != pc->parse_wallet_data.num_bkps) && 4231 (GNUNET_OK != 4232 handle_output_donation_receipt (pc, 4233 output)) ) 4234 { 4235 /* Error is already scheduled from handle_output_donation_receipt. */ 4236 return; 4237 } 4238 output_off += pc->parse_wallet_data.num_bkps; 4239 /* Note: wallet_off NOT increased, as bkps are 4240 separate from parse_wallet_data.token_envelopes */ 4241 continue; 4242 } /* switch on output token */ 4243 } /* for all output token types */ 4244 } /* case contract v1 */ 4245 break; 4246 } /* switch on contract type */ 4247 4248 for (size_t i = 0; i<pc->parse_pay.coins_cnt; i++) 4249 { 4250 const struct DepositConfirmation *dc = &pc->parse_pay.dc[i]; 4251 4252 if (GNUNET_OK != 4253 TALER_amount_cmp_currency (&dc->cdd.amount, 4254 &pc->validate_tokens.brutto)) 4255 { 4256 GNUNET_break_op (0); 4257 pay_end (pc, 4258 TALER_MHD_reply_with_error ( 4259 pc->connection, 4260 MHD_HTTP_CONFLICT, 4261 TALER_EC_MERCHANT_GENERIC_CURRENCY_MISMATCH, 4262 pc->validate_tokens.brutto.currency)); 4263 return; 4264 } 4265 } 4266 4267 pc->phase = PP_COMPUTE_MONEY_POTS; 4268 } 4269 4270 4271 /** 4272 * Function called with information about a coin that was deposited. 4273 * Checks if this coin is in our list of deposits as well. 4274 * 4275 * @param cls closure with our `struct PayContext *` 4276 * @param deposit_serial which deposit operation is this about 4277 * @param exchange_url URL of the exchange that issued the coin 4278 * @param h_wire hash of merchant's wire details 4279 * @param deposit_timestamp when was the deposit made 4280 * @param amount_with_fee amount the exchange will deposit for this coin 4281 * @param deposit_fee fee the exchange will charge for this coin 4282 * @param coin_pub public key of the coin 4283 */ 4284 static void 4285 deposit_paid_check ( 4286 void *cls, 4287 uint64_t deposit_serial, 4288 const char *exchange_url, 4289 const struct TALER_MerchantWireHashP *h_wire, 4290 struct GNUNET_TIME_Timestamp deposit_timestamp, 4291 const struct TALER_Amount *amount_with_fee, 4292 const struct TALER_Amount *deposit_fee, 4293 const struct TALER_CoinSpendPublicKeyP *coin_pub) 4294 { 4295 struct PayContext *pc = cls; 4296 4297 for (size_t i = 0; i<pc->parse_pay.coins_cnt; i++) 4298 { 4299 struct DepositConfirmation *dci = &pc->parse_pay.dc[i]; 4300 4301 if ( (0 == 4302 GNUNET_memcmp (&dci->cdd.coin_pub, 4303 coin_pub)) && 4304 (0 == 4305 strcmp (dci->exchange_url, 4306 exchange_url)) && 4307 (GNUNET_YES == 4308 TALER_amount_cmp_currency (&dci->cdd.amount, 4309 amount_with_fee)) && 4310 (0 == 4311 TALER_amount_cmp (&dci->cdd.amount, 4312 amount_with_fee)) ) 4313 { 4314 dci->matched_in_db = true; 4315 break; 4316 } 4317 } 4318 } 4319 4320 4321 /** 4322 * Function called with information about a token that was spent. 4323 * FIXME: Replace this with a more specific function for this cb 4324 * 4325 * @param cls closure with `struct PayContext *` 4326 * @param spent_token_serial "serial" of the spent token unused 4327 * @param h_contract_terms hash of the contract terms unused 4328 * @param h_issue_pub hash of the token issue public key unused 4329 * @param use_pub public key of the token 4330 * @param use_sig signature of the token 4331 * @param issue_sig signature of the token issue 4332 */ 4333 static void 4334 input_tokens_paid_check ( 4335 void *cls, 4336 uint64_t spent_token_serial, 4337 const struct TALER_PrivateContractHashP *h_contract_terms, 4338 const struct TALER_TokenIssuePublicKeyHashP *h_issue_pub, 4339 const struct TALER_TokenUsePublicKeyP *use_pub, 4340 const struct TALER_TokenUseSignatureP *use_sig, 4341 const struct TALER_TokenIssueSignature *issue_sig) 4342 { 4343 struct PayContext *pc = cls; 4344 4345 for (size_t i = 0; i<pc->parse_pay.tokens_cnt; i++) 4346 { 4347 struct TokenUseConfirmation *tuc = &pc->parse_pay.tokens[i]; 4348 4349 if ( (0 == 4350 GNUNET_memcmp (&tuc->pub, 4351 use_pub)) && 4352 (0 == 4353 GNUNET_memcmp (&tuc->sig, 4354 use_sig)) && 4355 (0 == 4356 GNUNET_memcmp (&tuc->unblinded_sig, 4357 issue_sig)) ) 4358 { 4359 tuc->found_in_db = true; 4360 break; 4361 } 4362 } 4363 } 4364 4365 4366 /** 4367 * Small helper function to append an output token signature from db 4368 * 4369 * @param cls closure with `struct PayContext *` 4370 * @param h_issue hash of the token 4371 * @param sig signature of the token 4372 */ 4373 static void 4374 append_output_token_sig (void *cls, 4375 struct GNUNET_HashCode *h_issue, 4376 struct GNUNET_CRYPTO_BlindedSignature *sig) 4377 { 4378 struct PayContext *pc = cls; 4379 struct TALER_MERCHANT_ContractChoice *choice; 4380 const struct TALER_MERCHANT_ContractOutput *output; 4381 struct SignedOutputToken out; 4382 unsigned int cnt; 4383 4384 memset (&out, 4385 0, 4386 sizeof (out)); 4387 GNUNET_assert (TALER_MERCHANT_CONTRACT_VERSION_1 == 4388 pc->check_contract.contract_terms->pc->base->version); 4389 choice = &pc->check_contract.contract_terms->pc->details.v1 4390 .choices[pc->parse_wallet_data.choice_index]; 4391 output = &choice->outputs[pc->output_index_gen]; 4392 cnt = count_output_tokens (pc, 4393 output); 4394 out.output_index = pc->output_index_gen; 4395 out.h_issue.hash = *h_issue; 4396 out.sig.signature = sig; 4397 GNUNET_CRYPTO_blind_sig_incref (sig); 4398 GNUNET_array_append (pc->output_tokens, 4399 pc->output_tokens_len, 4400 out); 4401 /* Go to next output once we've output all tokens for the current one. */ 4402 pc->output_token_cnt++; 4403 if (pc->output_token_cnt >= cnt) 4404 { 4405 pc->output_token_cnt = 0; 4406 pc->output_index_gen++; 4407 } 4408 } 4409 4410 4411 /** 4412 * Handle case where contract was already paid. Either decides 4413 * the payment is idempotent, or refunds the excess payment. 4414 * 4415 * @param[in,out] pc context we use to handle the payment 4416 */ 4417 static void 4418 phase_contract_paid (struct PayContext *pc) 4419 { 4420 json_t *refunds; 4421 bool unmatched = false; 4422 4423 { 4424 enum GNUNET_DB_QueryStatus qs; 4425 4426 qs = TALER_MERCHANTDB_iterate_deposits_by_order (TMH_db, 4427 pc->check_contract.order_serial, 4428 &deposit_paid_check, 4429 pc); 4430 /* Since orders with choices can have a price of zero, 4431 0 is also a valid query state */ 4432 if (qs < 0) 4433 { 4434 GNUNET_break (0); 4435 pay_end (pc, 4436 TALER_MHD_reply_with_error ( 4437 pc->connection, 4438 MHD_HTTP_INTERNAL_SERVER_ERROR, 4439 TALER_EC_GENERIC_DB_FETCH_FAILED, 4440 "iterate_deposits_by_order")); 4441 return; 4442 } 4443 } 4444 for (size_t i = 0; 4445 i<pc->parse_pay.coins_cnt && ! unmatched; 4446 i++) 4447 { 4448 struct DepositConfirmation *dci = &pc->parse_pay.dc[i]; 4449 4450 if (! dci->matched_in_db) 4451 unmatched = true; 4452 } 4453 /* Check if provided input tokens match token in the database */ 4454 { 4455 enum GNUNET_DB_QueryStatus qs; 4456 4457 /* FIXME-Optimization: Maybe use h_contract instead of order_serial here? */ 4458 qs = TALER_MERCHANTDB_iterate_used_tokens_by_order (TMH_db, 4459 pc->check_contract.order_serial, 4460 &input_tokens_paid_check, 4461 pc); 4462 4463 if (qs < 0) 4464 { 4465 GNUNET_break (0); 4466 pay_end (pc, 4467 TALER_MHD_reply_with_error ( 4468 pc->connection, 4469 MHD_HTTP_INTERNAL_SERVER_ERROR, 4470 TALER_EC_GENERIC_DB_FETCH_FAILED, 4471 "iterate_used_tokens_by_order")); 4472 return; 4473 } 4474 } 4475 for (size_t i = 0; i<pc->parse_pay.tokens_cnt && ! unmatched; i++) 4476 { 4477 struct TokenUseConfirmation *tuc = &pc->parse_pay.tokens[i]; 4478 4479 if (! tuc->found_in_db) 4480 unmatched = true; 4481 } 4482 4483 /* In this part we are fetching token_sigs related output */ 4484 if (! unmatched) 4485 { 4486 /* Everything fine, idempotent request, generate response immediately */ 4487 enum GNUNET_DB_QueryStatus qs; 4488 4489 pc->output_index_gen = 0; 4490 qs = TALER_MERCHANTDB_iterate_order_token_blinded_sigs ( 4491 TMH_db, 4492 pc->order_id, 4493 &append_output_token_sig, 4494 pc); 4495 if (0 > qs) 4496 { 4497 GNUNET_break (0); 4498 pay_end (pc, 4499 TALER_MHD_reply_with_error ( 4500 pc->connection, 4501 MHD_HTTP_INTERNAL_SERVER_ERROR, 4502 TALER_EC_GENERIC_DB_FETCH_FAILED, 4503 "iterate_order_token_blinded_sigs")); 4504 return; 4505 } 4506 4507 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 4508 "Idempotent pay request for order `%s', signing again\n", 4509 pc->order_id); 4510 pc->phase = PP_SUCCESS_RESPONSE; 4511 return; 4512 } 4513 /* Conflict, double-payment detected! */ 4514 /* FIXME-#8674: What should we do with input tokens? 4515 Currently there is no refund for tokens. */ 4516 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 4517 "Client attempted to pay extra for already paid order `%s'\n", 4518 pc->order_id); 4519 refunds = json_array (); 4520 GNUNET_assert (NULL != refunds); 4521 for (size_t i = 0; i<pc->parse_pay.coins_cnt; i++) 4522 { 4523 struct DepositConfirmation *dci = &pc->parse_pay.dc[i]; 4524 struct TALER_MerchantSignatureP merchant_sig; 4525 4526 if (dci->matched_in_db) 4527 continue; 4528 TALER_merchant_refund_sign (&dci->cdd.coin_pub, 4529 &pc->check_contract.h_contract_terms, 4530 0, /* rtransaction id */ 4531 &dci->cdd.amount, 4532 &pc->hc->instance->merchant_priv, 4533 &merchant_sig); 4534 GNUNET_assert ( 4535 0 == 4536 json_array_append_new ( 4537 refunds, 4538 GNUNET_JSON_PACK ( 4539 GNUNET_JSON_pack_data_auto ( 4540 "coin_pub", 4541 &dci->cdd.coin_pub), 4542 GNUNET_JSON_pack_data_auto ( 4543 "merchant_sig", 4544 &merchant_sig), 4545 TALER_JSON_pack_amount ("amount", 4546 &dci->cdd.amount), 4547 GNUNET_JSON_pack_uint64 ("rtransaction_id", 4548 0)))); 4549 } 4550 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 4551 "Generating JSON response with code %d\n", 4552 (int) TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_ALREADY_PAID); 4553 pay_end (pc, 4554 TALER_MHD_REPLY_JSON_PACK ( 4555 pc->connection, 4556 MHD_HTTP_CONFLICT, 4557 TALER_MHD_PACK_EC ( 4558 TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_ALREADY_PAID), 4559 GNUNET_JSON_pack_array_steal ("refunds", 4560 refunds))); 4561 } 4562 4563 4564 /** 4565 * Check the database state for the given order. 4566 * Schedules an error response in the connection on failure. 4567 * 4568 * @param[in,out] pc context we use to handle the payment 4569 */ 4570 static void 4571 phase_check_contract (struct PayContext *pc) 4572 { 4573 /* obtain contract terms */ 4574 enum GNUNET_DB_QueryStatus qs; 4575 bool paid = false; 4576 4577 if (NULL != pc->check_contract.contract_terms_json) 4578 { 4579 json_decref (pc->check_contract.contract_terms_json); 4580 pc->check_contract.contract_terms_json = NULL; 4581 } 4582 if (NULL != pc->check_contract.contract_terms) 4583 { 4584 TALER_MERCHANT_contract_free (pc->check_contract.contract_terms); 4585 pc->check_contract.contract_terms = NULL; 4586 } 4587 qs = TALER_MERCHANTDB_get_contract_terms_pos ( 4588 TMH_db, 4589 pc->hc->instance->settings.id, 4590 pc->order_id, 4591 &pc->check_contract.contract_terms_json, 4592 &pc->check_contract.order_serial, 4593 &paid, 4594 NULL, 4595 &pc->check_contract.pos_key, 4596 &pc->check_contract.pos_alg); 4597 if (0 > qs) 4598 { 4599 /* single, read-only SQL statements should never cause 4600 serialization problems */ 4601 GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR != qs); 4602 /* Always report on hard error to enable diagnostics */ 4603 GNUNET_break (GNUNET_DB_STATUS_HARD_ERROR == qs); 4604 pay_end (pc, 4605 TALER_MHD_reply_with_error ( 4606 pc->connection, 4607 MHD_HTTP_INTERNAL_SERVER_ERROR, 4608 TALER_EC_GENERIC_DB_FETCH_FAILED, 4609 "contract terms")); 4610 return; 4611 } 4612 if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs) 4613 { 4614 pay_end (pc, 4615 TALER_MHD_reply_with_error ( 4616 pc->connection, 4617 MHD_HTTP_NOT_FOUND, 4618 TALER_EC_MERCHANT_GENERIC_ORDER_UNKNOWN, 4619 pc->order_id)); 4620 return; 4621 } 4622 /* hash contract (needed later) */ 4623 #if DEBUG 4624 json_dumpf (pc->check_contract.contract_terms_json, 4625 stderr, 4626 JSON_INDENT (2)); 4627 #endif 4628 if (GNUNET_OK != 4629 TALER_JSON_contract_hash (pc->check_contract.contract_terms_json, 4630 &pc->check_contract.h_contract_terms)) 4631 { 4632 GNUNET_break (0); 4633 pay_end (pc, 4634 TALER_MHD_reply_with_error ( 4635 pc->connection, 4636 MHD_HTTP_INTERNAL_SERVER_ERROR, 4637 TALER_EC_GENERIC_FAILED_COMPUTE_JSON_HASH, 4638 NULL)); 4639 return; 4640 } 4641 4642 /* Parse the contract terms even for paid orders, 4643 as later phases need it. */ 4644 4645 pc->check_contract.contract_terms = TALER_MERCHANT_contract_parse ( 4646 pc->check_contract.contract_terms_json); 4647 4648 if (NULL == pc->check_contract.contract_terms) 4649 { 4650 /* invalid contract */ 4651 GNUNET_break (0); 4652 pay_end (pc, 4653 TALER_MHD_reply_with_error ( 4654 pc->connection, 4655 MHD_HTTP_INTERNAL_SERVER_ERROR, 4656 TALER_EC_MERCHANT_GENERIC_DB_CONTRACT_CONTENT_INVALID, 4657 pc->order_id)); 4658 return; 4659 } 4660 4661 if (paid) 4662 { 4663 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 4664 "Order `%s' paid, checking for double-payment\n", 4665 pc->order_id); 4666 pc->phase = PP_CONTRACT_PAID; 4667 return; 4668 } 4669 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 4670 "Handling payment for order `%s' with contract hash `%s'\n", 4671 pc->order_id, 4672 GNUNET_h2s (&pc->check_contract.h_contract_terms.hash)); 4673 4674 /* Check fundamentals */ 4675 { 4676 switch (pc->check_contract.contract_terms->pc->base->version) 4677 { 4678 case TALER_MERCHANT_CONTRACT_VERSION_0: 4679 { 4680 if (pc->parse_wallet_data.choice_index > 0) 4681 { 4682 GNUNET_break (0); 4683 pay_end (pc, 4684 TALER_MHD_reply_with_error ( 4685 pc->connection, 4686 MHD_HTTP_BAD_REQUEST, 4687 TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_CHOICE_INDEX_OUT_OF_BOUNDS, 4688 "contract terms v0 has no choices")); 4689 return; 4690 } 4691 } 4692 break; 4693 case TALER_MERCHANT_CONTRACT_VERSION_1: 4694 { 4695 if (pc->parse_wallet_data.choice_index < 0) 4696 { 4697 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 4698 "Order `%s' has non-empty choices array but" 4699 "request is missing 'choice_index' field\n", 4700 pc->order_id); 4701 GNUNET_break (0); 4702 pay_end (pc, 4703 TALER_MHD_reply_with_error ( 4704 pc->connection, 4705 MHD_HTTP_BAD_REQUEST, 4706 TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_CHOICE_INDEX_MISSING, 4707 NULL)); 4708 return; 4709 } 4710 if (pc->parse_wallet_data.choice_index >= 4711 pc->check_contract.contract_terms->pc->details.v1.choices_len) 4712 { 4713 GNUNET_log ( 4714 GNUNET_ERROR_TYPE_INFO, 4715 "Order `%s' has choices array with %u elements but " 4716 "request has 'choice_index' field with value %d\n", 4717 pc->order_id, 4718 pc->check_contract.contract_terms->pc->details.v1.choices_len, 4719 pc->parse_wallet_data.choice_index); 4720 GNUNET_break (0); 4721 pay_end (pc, 4722 TALER_MHD_reply_with_error ( 4723 pc->connection, 4724 MHD_HTTP_BAD_REQUEST, 4725 TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_CHOICE_INDEX_OUT_OF_BOUNDS, 4726 NULL)); 4727 return; 4728 } 4729 } 4730 break; 4731 default: 4732 GNUNET_break (0); 4733 pay_end (pc, 4734 TALER_MHD_reply_with_error ( 4735 pc->connection, 4736 MHD_HTTP_INTERNAL_SERVER_ERROR, 4737 TALER_EC_GENERIC_DB_FETCH_FAILED, 4738 "contract 'version' in database not supported by this backend") 4739 ); 4740 return; 4741 } 4742 } 4743 4744 if (GNUNET_TIME_timestamp_cmp ( 4745 pc->check_contract.contract_terms->pc->wire_deadline, 4746 <, 4747 pc->check_contract.contract_terms->pc->refund_deadline)) 4748 { 4749 /* This should already have been checked when creating the order! */ 4750 GNUNET_break (0); 4751 pay_end (pc, 4752 TALER_MHD_reply_with_error ( 4753 pc->connection, 4754 MHD_HTTP_INTERNAL_SERVER_ERROR, 4755 TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_REFUND_DEADLINE_PAST_WIRE_TRANSFER_DEADLINE, 4756 NULL)); 4757 return; 4758 } 4759 if (GNUNET_TIME_absolute_is_past ( 4760 pc->check_contract.contract_terms->pc->pay_deadline.abs_time)) 4761 { 4762 /* too late */ 4763 pay_end (pc, 4764 TALER_MHD_reply_with_error ( 4765 pc->connection, 4766 MHD_HTTP_GONE, 4767 TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_OFFER_EXPIRED, 4768 NULL)); 4769 return; 4770 } 4771 4772 /* Make sure wire method (still) exists for this instance */ 4773 { 4774 struct TMH_WireMethod *wm; 4775 4776 wm = pc->hc->instance->wm_head; 4777 while ( (NULL != wm) && 4778 (0 != 4779 GNUNET_memcmp ( 4780 &pc->check_contract.contract_terms->pc->h_wire, 4781 &wm->h_wire)) ) 4782 wm = wm->next; 4783 if (NULL == wm) 4784 { 4785 GNUNET_break (0); 4786 pay_end (pc, 4787 TALER_MHD_reply_with_error ( 4788 pc->connection, 4789 MHD_HTTP_INTERNAL_SERVER_ERROR, 4790 TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_WIRE_HASH_UNKNOWN, 4791 NULL)); 4792 return; 4793 } 4794 pc->check_contract.wm = wm; 4795 } 4796 pc->phase = PP_VALIDATE_TOKENS; 4797 } 4798 4799 4800 /** 4801 * Try to parse the wallet_data object of the pay request into 4802 * the given context. Schedules an error response in the connection 4803 * on failure. 4804 * 4805 * @param[in,out] pc context we use to handle the payment 4806 */ 4807 static void 4808 phase_parse_wallet_data (struct PayContext *pc) 4809 { 4810 const json_t *tokens_evs; 4811 const json_t *donau_obj; 4812 4813 struct GNUNET_JSON_Specification spec[] = { 4814 GNUNET_JSON_spec_mark_optional ( 4815 GNUNET_JSON_spec_int16 ("choice_index", 4816 &pc->parse_wallet_data.choice_index), 4817 NULL), 4818 GNUNET_JSON_spec_mark_optional ( 4819 GNUNET_JSON_spec_array_const ("tokens_evs", 4820 &tokens_evs), 4821 NULL), 4822 GNUNET_JSON_spec_mark_optional ( 4823 GNUNET_JSON_spec_object_const ("donau", 4824 &donau_obj), 4825 NULL), 4826 GNUNET_JSON_spec_end () 4827 }; 4828 4829 pc->parse_wallet_data.choice_index = -1; 4830 if (NULL == pc->parse_pay.wallet_data) 4831 { 4832 pc->phase = PP_CHECK_CONTRACT; 4833 return; 4834 } 4835 { 4836 enum GNUNET_GenericReturnValue res; 4837 4838 res = TALER_MHD_parse_json_data (pc->connection, 4839 pc->parse_pay.wallet_data, 4840 spec); 4841 if (GNUNET_YES != res) 4842 { 4843 GNUNET_break_op (0); 4844 pay_end (pc, 4845 (GNUNET_NO == res) 4846 ? MHD_YES 4847 : MHD_NO); 4848 return; 4849 } 4850 } 4851 4852 pc->parse_wallet_data.token_envelopes_cnt 4853 = json_array_size (tokens_evs); 4854 if (pc->parse_wallet_data.token_envelopes_cnt > 4855 MAX_TOKEN_ALLOWED_OUTPUTS) 4856 { 4857 GNUNET_break_op (0); 4858 pay_end (pc, 4859 TALER_MHD_reply_with_error ( 4860 pc->connection, 4861 MHD_HTTP_BAD_REQUEST, 4862 TALER_EC_GENERIC_PARAMETER_MALFORMED, 4863 "'tokens_evs' array too long")); 4864 return; 4865 } 4866 pc->parse_wallet_data.token_envelopes 4867 = GNUNET_new_array (pc->parse_wallet_data.token_envelopes_cnt, 4868 struct TokenEnvelope); 4869 4870 { 4871 unsigned int tokens_ev_index; 4872 json_t *token_ev; 4873 4874 json_array_foreach (tokens_evs, 4875 tokens_ev_index, 4876 token_ev) 4877 { 4878 struct TokenEnvelope *ev 4879 = &pc->parse_wallet_data.token_envelopes[tokens_ev_index]; 4880 struct GNUNET_JSON_Specification ispec[] = { 4881 TALER_JSON_spec_token_envelope (NULL, 4882 &ev->blinded_token), 4883 GNUNET_JSON_spec_end () 4884 }; 4885 enum GNUNET_GenericReturnValue res; 4886 4887 if (json_is_null (token_ev)) 4888 continue; 4889 res = TALER_MHD_parse_json_data (pc->connection, 4890 token_ev, 4891 ispec); 4892 if (GNUNET_YES != res) 4893 { 4894 GNUNET_break_op (0); 4895 pay_end (pc, 4896 (GNUNET_NO == res) 4897 ? MHD_YES 4898 : MHD_NO); 4899 return; 4900 } 4901 4902 for (unsigned int j = 0; j<tokens_ev_index; j++) 4903 { 4904 const struct TokenEnvelope *pev 4905 = &pc->parse_wallet_data.token_envelopes[j]; 4906 4907 if (NULL == pev->blinded_token.blinded_pub) 4908 continue; 4909 if (0 == 4910 GNUNET_CRYPTO_blinded_message_cmp ( 4911 ev->blinded_token.blinded_pub, 4912 pev->blinded_token.blinded_pub)) 4913 { 4914 GNUNET_break_op (0); 4915 pay_end (pc, 4916 TALER_MHD_reply_with_error ( 4917 pc->connection, 4918 MHD_HTTP_BAD_REQUEST, 4919 TALER_EC_GENERIC_PARAMETER_MALFORMED, 4920 "duplicate token envelope in list")); 4921 return; 4922 } 4923 } 4924 } 4925 } 4926 4927 if (NULL != donau_obj) 4928 { 4929 const char *donau_url_tmp; 4930 const json_t *budikeypairs; 4931 json_t *donau_keys_json; 4932 4933 /* Fetching and checking that all 3 are present in some way */ 4934 struct GNUNET_JSON_Specification dspec[] = { 4935 TALER_JSON_spec_web_url ("url", 4936 &donau_url_tmp), 4937 GNUNET_JSON_spec_uint64 ("year", 4938 &pc->parse_wallet_data.donau.donation_year), 4939 GNUNET_JSON_spec_array_const ("budikeypairs", 4940 &budikeypairs), 4941 GNUNET_JSON_spec_end () 4942 }; 4943 enum GNUNET_GenericReturnValue res; 4944 4945 res = TALER_MHD_parse_json_data (pc->connection, 4946 donau_obj, 4947 dspec); 4948 if (GNUNET_YES != res) 4949 { 4950 GNUNET_break_op (0); 4951 pay_end (pc, 4952 (GNUNET_NO == res) 4953 ? MHD_YES 4954 : MHD_NO); 4955 return; 4956 } 4957 4958 /* Check if the needed data is present for the given donau URL */ 4959 { 4960 enum GNUNET_DB_QueryStatus qs; 4961 4962 qs = TALER_MERCHANTDB_get_donau_instance_by_url ( 4963 TMH_db, 4964 pc->hc->instance->settings.id, 4965 donau_url_tmp, 4966 &pc->parse_wallet_data.charity_id, 4967 &pc->parse_wallet_data.charity_max_per_year, 4968 &pc->parse_wallet_data.charity_receipts_to_date, 4969 &donau_keys_json, 4970 &pc->parse_wallet_data.donau_instance_serial); 4971 4972 switch (qs) 4973 { 4974 case GNUNET_DB_STATUS_HARD_ERROR: 4975 case GNUNET_DB_STATUS_SOFT_ERROR: 4976 TALER_MERCHANTDB_rollback (TMH_db); 4977 pay_end (pc, 4978 TALER_MHD_reply_with_error ( 4979 pc->connection, 4980 MHD_HTTP_INTERNAL_SERVER_ERROR, 4981 TALER_EC_GENERIC_DB_FETCH_FAILED, 4982 "get_donau_instance_by_url")); 4983 return; 4984 case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS: 4985 TALER_MERCHANTDB_rollback (TMH_db); 4986 pay_end (pc, 4987 TALER_MHD_reply_with_error ( 4988 pc->connection, 4989 MHD_HTTP_NOT_FOUND, 4990 TALER_EC_MERCHANT_GENERIC_DONAU_CHARITY_UNKNOWN, 4991 donau_url_tmp)); 4992 return; 4993 case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT: 4994 GNUNET_static_assert (sizeof (pc->parse_wallet_data.charity_priv) == 4995 sizeof (pc->hc->instance->merchant_priv)); 4996 memcpy (&pc->parse_wallet_data.charity_priv, 4997 &pc->hc->instance->merchant_priv, 4998 sizeof (pc->hc->instance->merchant_priv)); 4999 pc->parse_wallet_data.donau.donau_url = 5000 GNUNET_strdup (donau_url_tmp); 5001 break; 5002 } 5003 } 5004 5005 { 5006 pc->parse_wallet_data.donau_keys = 5007 DONAU_keys_from_json (donau_keys_json); 5008 json_decref (donau_keys_json); 5009 if (NULL == pc->parse_wallet_data.donau_keys) 5010 { 5011 GNUNET_break_op (0); 5012 pay_end (pc, 5013 TALER_MHD_reply_with_error (pc->connection, 5014 MHD_HTTP_BAD_REQUEST, 5015 TALER_EC_GENERIC_PARAMETER_MALFORMED, 5016 "Invalid donau_keys")); 5017 return; 5018 } 5019 } 5020 5021 /* Stage to parse the budikeypairs from json to struct */ 5022 if (0 != json_array_size (budikeypairs)) 5023 { 5024 size_t num_bkps = json_array_size (budikeypairs); 5025 struct DONAU_BlindedUniqueDonorIdentifierKeyPair *bkps = 5026 GNUNET_new_array (num_bkps, 5027 struct DONAU_BlindedUniqueDonorIdentifierKeyPair); 5028 5029 /* Change to json for each */ 5030 for (size_t i = 0; i < num_bkps; i++) 5031 { 5032 const json_t *bkp_obj = json_array_get (budikeypairs, 5033 i); 5034 if (GNUNET_SYSERR == 5035 merchant_parse_json_bkp (&bkps[i], 5036 bkp_obj)) 5037 { 5038 GNUNET_break_op (0); 5039 for (size_t j = 0; j < i; j++) 5040 GNUNET_CRYPTO_blinded_message_decref ( 5041 bkps[j].blinded_udi.blinded_message); 5042 GNUNET_free (bkps); 5043 pay_end (pc, 5044 TALER_MHD_reply_with_error (pc->connection, 5045 MHD_HTTP_BAD_REQUEST, 5046 TALER_EC_GENERIC_PARAMETER_MALFORMED, 5047 "Failed to parse budikeypairs")); 5048 return; 5049 } 5050 } 5051 5052 pc->parse_wallet_data.num_bkps = num_bkps; 5053 pc->parse_wallet_data.bkps = bkps; 5054 } 5055 } 5056 TALER_json_hash (pc->parse_pay.wallet_data, 5057 &pc->parse_wallet_data.h_wallet_data); 5058 5059 pc->phase = PP_CHECK_CONTRACT; 5060 } 5061 5062 5063 /** 5064 * Try to parse the pay request into the given pay context. 5065 * Schedules an error response in the connection on failure. 5066 * 5067 * @param[in,out] pc context we use to handle the payment 5068 */ 5069 static void 5070 phase_parse_pay (struct PayContext *pc) 5071 { 5072 const char *session_id = NULL; 5073 const json_t *coins; 5074 const json_t *tokens; 5075 struct GNUNET_JSON_Specification spec[] = { 5076 GNUNET_JSON_spec_array_const ("coins", 5077 &coins), 5078 GNUNET_JSON_spec_mark_optional ( 5079 TALER_JSON_spec_session_id ("session_id", 5080 &session_id), 5081 NULL), 5082 GNUNET_JSON_spec_mark_optional ( 5083 GNUNET_JSON_spec_object_const ("wallet_data", 5084 &pc->parse_pay.wallet_data), 5085 NULL), 5086 GNUNET_JSON_spec_mark_optional ( 5087 GNUNET_JSON_spec_array_const ("tokens", 5088 &tokens), 5089 NULL), 5090 GNUNET_JSON_spec_end () 5091 }; 5092 5093 #if DEBUG 5094 { 5095 char *dump = json_dumps (pc->hc->request_body, 5096 JSON_INDENT (2) 5097 | JSON_ENCODE_ANY 5098 | JSON_SORT_KEYS); 5099 5100 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 5101 "POST /orders/%s/pay – request body follows:\n%s\n", 5102 pc->order_id, 5103 dump); 5104 5105 free (dump); 5106 5107 } 5108 #endif /* DEBUG */ 5109 5110 GNUNET_assert (PP_PARSE_PAY == pc->phase); 5111 { 5112 enum GNUNET_GenericReturnValue res; 5113 5114 res = TALER_MHD_parse_json_data (pc->connection, 5115 pc->hc->request_body, 5116 spec); 5117 if (GNUNET_YES != res) 5118 { 5119 GNUNET_break_op (0); 5120 pay_end (pc, 5121 (GNUNET_NO == res) 5122 ? MHD_YES 5123 : MHD_NO); 5124 return; 5125 } 5126 } 5127 5128 /* copy session ID (if set) */ 5129 if (NULL != session_id) 5130 { 5131 pc->parse_pay.session_id = GNUNET_strdup (session_id); 5132 } 5133 else 5134 { 5135 /* use empty string as default if client didn't specify it */ 5136 pc->parse_pay.session_id = GNUNET_strdup (""); 5137 } 5138 5139 pc->parse_pay.coins_cnt = json_array_size (coins); 5140 if (pc->parse_pay.coins_cnt > MAX_COIN_ALLOWED_COINS) 5141 { 5142 GNUNET_break_op (0); 5143 pay_end (pc, 5144 TALER_MHD_reply_with_error ( 5145 pc->connection, 5146 MHD_HTTP_BAD_REQUEST, 5147 TALER_EC_GENERIC_PARAMETER_MALFORMED, 5148 "'coins' array too long")); 5149 return; 5150 } 5151 /* note: 1 coin = 1 deposit confirmation expected */ 5152 pc->parse_pay.dc = GNUNET_new_array (pc->parse_pay.coins_cnt, 5153 struct DepositConfirmation); 5154 5155 /* This loop populates the array 'dc' in 'pc' */ 5156 { 5157 unsigned int coins_index; 5158 json_t *coin; 5159 5160 json_array_foreach (coins, coins_index, coin) 5161 { 5162 struct DepositConfirmation *dc = &pc->parse_pay.dc[coins_index]; 5163 const char *exchange_url; 5164 struct GNUNET_JSON_Specification ispec[] = { 5165 GNUNET_JSON_spec_fixed_auto ("coin_sig", 5166 &dc->cdd.coin_sig), 5167 GNUNET_JSON_spec_fixed_auto ("coin_pub", 5168 &dc->cdd.coin_pub), 5169 TALER_JSON_spec_denom_sig ("ub_sig", 5170 &dc->cdd.denom_sig), 5171 GNUNET_JSON_spec_fixed_auto ("h_denom", 5172 &dc->cdd.h_denom_pub), 5173 TALER_JSON_spec_amount_any ("contribution", 5174 &dc->cdd.amount), 5175 TALER_JSON_spec_web_url ("exchange_url", 5176 &exchange_url), 5177 /* if a minimum age was required, the minimum_age_sig and 5178 * age_commitment must be provided */ 5179 GNUNET_JSON_spec_mark_optional ( 5180 GNUNET_JSON_spec_fixed_auto ("minimum_age_sig", 5181 &dc->minimum_age_sig), 5182 &dc->no_minimum_age_sig), 5183 GNUNET_JSON_spec_mark_optional ( 5184 TALER_JSON_spec_age_commitment ("age_commitment", 5185 &dc->age_commitment), 5186 &dc->no_age_commitment), 5187 /* if minimum age was not required, but coin with age restriction set 5188 * was used, h_age_commitment must be provided. */ 5189 GNUNET_JSON_spec_mark_optional ( 5190 GNUNET_JSON_spec_fixed_auto ("h_age_commitment", 5191 &dc->cdd.h_age_commitment), 5192 &dc->no_h_age_commitment), 5193 GNUNET_JSON_spec_end () 5194 }; 5195 enum GNUNET_GenericReturnValue res; 5196 struct ExchangeGroup *eg = NULL; 5197 5198 res = TALER_MHD_parse_json_data (pc->connection, 5199 coin, 5200 ispec); 5201 if (GNUNET_YES != res) 5202 { 5203 GNUNET_break_op (0); 5204 pay_end (pc, 5205 (GNUNET_NO == res) 5206 ? MHD_YES 5207 : MHD_NO); 5208 return; 5209 } 5210 for (unsigned int j = 0; j<coins_index; j++) 5211 { 5212 if (0 == 5213 GNUNET_memcmp (&dc->cdd.coin_pub, 5214 &pc->parse_pay.dc[j].cdd.coin_pub)) 5215 { 5216 GNUNET_break_op (0); 5217 pay_end (pc, 5218 TALER_MHD_reply_with_error (pc->connection, 5219 MHD_HTTP_BAD_REQUEST, 5220 TALER_EC_GENERIC_PARAMETER_MALFORMED, 5221 "duplicate coin in list")); 5222 return; 5223 } 5224 } 5225 5226 dc->exchange_url = GNUNET_strdup (exchange_url); 5227 dc->index = coins_index; 5228 dc->pc = pc; 5229 5230 /* Check the consistency of the (potential) age restriction 5231 * information. */ 5232 if (dc->no_age_commitment != dc->no_minimum_age_sig) 5233 { 5234 GNUNET_break_op (0); 5235 pay_end (pc, 5236 TALER_MHD_reply_with_error ( 5237 pc->connection, 5238 MHD_HTTP_BAD_REQUEST, 5239 TALER_EC_GENERIC_PARAMETER_MALFORMED, 5240 "inconsistent: 'age_commitment' vs. 'minimum_age_sig'" 5241 )); 5242 return; 5243 } 5244 5245 /* Setup exchange group */ 5246 for (unsigned int i = 0; i<pc->parse_pay.num_exchanges; i++) 5247 { 5248 if (0 == 5249 strcmp (pc->parse_pay.egs[i]->exchange_url, 5250 exchange_url)) 5251 { 5252 eg = pc->parse_pay.egs[i]; 5253 break; 5254 } 5255 } 5256 if (NULL == eg) 5257 { 5258 eg = GNUNET_new (struct ExchangeGroup); 5259 eg->pc = pc; 5260 eg->exchange_url = dc->exchange_url; 5261 eg->total = dc->cdd.amount; 5262 GNUNET_array_append (pc->parse_pay.egs, 5263 pc->parse_pay.num_exchanges, 5264 eg); 5265 } 5266 else 5267 { 5268 if (0 > 5269 TALER_amount_add (&eg->total, 5270 &eg->total, 5271 &dc->cdd.amount)) 5272 { 5273 GNUNET_break_op (0); 5274 pay_end (pc, 5275 TALER_MHD_reply_with_error ( 5276 pc->connection, 5277 MHD_HTTP_INTERNAL_SERVER_ERROR, 5278 TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_AMOUNT_OVERFLOW, 5279 "Overflow adding up amounts")); 5280 return; 5281 } 5282 } 5283 } 5284 } 5285 5286 pc->parse_pay.tokens_cnt = json_array_size (tokens); 5287 if (pc->parse_pay.tokens_cnt > MAX_TOKEN_ALLOWED_INPUTS) 5288 { 5289 GNUNET_break_op (0); 5290 pay_end (pc, 5291 TALER_MHD_reply_with_error ( 5292 pc->connection, 5293 MHD_HTTP_BAD_REQUEST, 5294 TALER_EC_GENERIC_PARAMETER_MALFORMED, 5295 "'tokens' array too long")); 5296 return; 5297 } 5298 5299 pc->parse_pay.tokens = GNUNET_new_array (pc->parse_pay.tokens_cnt, 5300 struct TokenUseConfirmation); 5301 5302 /* This loop populates the array 'tokens' in 'pc' */ 5303 { 5304 unsigned int tokens_index; 5305 json_t *token; 5306 5307 json_array_foreach (tokens, tokens_index, token) 5308 { 5309 struct TokenUseConfirmation *tuc = &pc->parse_pay.tokens[tokens_index]; 5310 struct GNUNET_JSON_Specification ispec[] = { 5311 GNUNET_JSON_spec_fixed_auto ("token_sig", 5312 &tuc->sig), 5313 GNUNET_JSON_spec_fixed_auto ("token_pub", 5314 &tuc->pub), 5315 GNUNET_JSON_spec_fixed_auto ("h_issue", 5316 &tuc->h_issue), 5317 TALER_JSON_spec_token_issue_sig ("ub_sig", 5318 &tuc->unblinded_sig), 5319 GNUNET_JSON_spec_end () 5320 }; 5321 enum GNUNET_GenericReturnValue res; 5322 5323 res = TALER_MHD_parse_json_data (pc->connection, 5324 token, 5325 ispec); 5326 if (GNUNET_YES != res) 5327 { 5328 GNUNET_break_op (0); 5329 pay_end (pc, 5330 (GNUNET_NO == res) 5331 ? MHD_YES 5332 : MHD_NO); 5333 return; 5334 } 5335 5336 for (unsigned int j = 0; j<tokens_index; j++) 5337 { 5338 if (0 == 5339 GNUNET_memcmp (&tuc->pub, 5340 &pc->parse_pay.tokens[j].pub)) 5341 { 5342 GNUNET_break_op (0); 5343 pay_end (pc, 5344 TALER_MHD_reply_with_error ( 5345 pc->connection, 5346 MHD_HTTP_BAD_REQUEST, 5347 TALER_EC_GENERIC_PARAMETER_MALFORMED, 5348 "duplicate token in list")); 5349 return; 5350 } 5351 } 5352 } 5353 } 5354 5355 pc->phase = PP_PARSE_WALLET_DATA; 5356 } 5357 5358 5359 /** 5360 * Custom cleanup routine for a `struct PayContext`. 5361 * 5362 * @param cls the `struct PayContext` to clean up. 5363 */ 5364 static void 5365 pay_context_cleanup (void *cls) 5366 { 5367 struct PayContext *pc = cls; 5368 5369 if (NULL != pc->batch_deposits.timeout_task) 5370 { 5371 GNUNET_SCHEDULER_cancel (pc->batch_deposits.timeout_task); 5372 pc->batch_deposits.timeout_task = NULL; 5373 } 5374 if (NULL != pc->check_contract.contract_terms_json) 5375 { 5376 json_decref (pc->check_contract.contract_terms_json); 5377 pc->check_contract.contract_terms_json = NULL; 5378 } 5379 for (unsigned int i = 0; i<pc->parse_pay.coins_cnt; i++) 5380 { 5381 struct DepositConfirmation *dc = &pc->parse_pay.dc[i]; 5382 5383 TALER_denom_sig_free (&dc->cdd.denom_sig); 5384 GNUNET_free (dc->exchange_url); 5385 } 5386 GNUNET_free (pc->parse_pay.dc); 5387 for (unsigned int i = 0; i<pc->parse_pay.tokens_cnt; i++) 5388 { 5389 struct TokenUseConfirmation *tuc = &pc->parse_pay.tokens[i]; 5390 5391 TALER_token_issue_sig_free (&tuc->unblinded_sig); 5392 } 5393 GNUNET_free (pc->parse_pay.tokens); 5394 for (unsigned int i = 0; i<pc->parse_pay.num_exchanges; i++) 5395 { 5396 struct ExchangeGroup *eg = pc->parse_pay.egs[i]; 5397 5398 if (NULL != eg->fo) 5399 TMH_EXCHANGES_keys4exchange_cancel (eg->fo); 5400 if (NULL != eg->bdh) 5401 TALER_EXCHANGE_post_batch_deposit_cancel (eg->bdh); 5402 if (NULL != eg->keys) 5403 TALER_EXCHANGE_keys_decref (eg->keys); 5404 GNUNET_free (eg); 5405 } 5406 GNUNET_free (pc->parse_pay.egs); 5407 if (NULL != pc->check_contract.contract_terms) 5408 { 5409 TALER_MERCHANT_contract_free (pc->check_contract.contract_terms); 5410 pc->check_contract.contract_terms = NULL; 5411 } 5412 if (NULL != pc->response) 5413 { 5414 MHD_destroy_response (pc->response); 5415 pc->response = NULL; 5416 } 5417 GNUNET_free (pc->parse_pay.session_id); 5418 GNUNET_CONTAINER_DLL_remove (pc_head, 5419 pc_tail, 5420 pc); 5421 GNUNET_free (pc->check_contract.pos_key); 5422 GNUNET_free (pc->compute_money_pots.pots); 5423 GNUNET_free (pc->compute_money_pots.increments); 5424 if (NULL != pc->parse_wallet_data.bkps) 5425 { 5426 for (size_t i = 0; i < pc->parse_wallet_data.num_bkps; i++) 5427 GNUNET_CRYPTO_blinded_message_decref ( 5428 pc->parse_wallet_data.bkps[i].blinded_udi.blinded_message); 5429 GNUNET_array_grow (pc->parse_wallet_data.bkps, 5430 pc->parse_wallet_data.num_bkps, 5431 0); 5432 } 5433 if (NULL != pc->parse_wallet_data.donau_keys) 5434 { 5435 DONAU_keys_decref (pc->parse_wallet_data.donau_keys); 5436 pc->parse_wallet_data.donau_keys = NULL; 5437 } 5438 GNUNET_free (pc->parse_wallet_data.donau.donau_url); 5439 for (unsigned int i = 0; i<pc->parse_wallet_data.token_envelopes_cnt; i++) 5440 { 5441 struct TokenEnvelope *ev 5442 = &pc->parse_wallet_data.token_envelopes[i]; 5443 5444 GNUNET_CRYPTO_blinded_message_decref (ev->blinded_token.blinded_pub); 5445 } 5446 GNUNET_free (pc->parse_wallet_data.token_envelopes); 5447 if (NULL != pc->output_tokens) 5448 { 5449 for (unsigned int i = 0; i<pc->output_tokens_len; i++) 5450 if (NULL != pc->output_tokens[i].sig.signature) 5451 GNUNET_CRYPTO_blinded_sig_decref (pc->output_tokens[i].sig.signature); 5452 GNUNET_free (pc->output_tokens); 5453 } 5454 GNUNET_free (pc); 5455 } 5456 5457 5458 enum MHD_Result 5459 TMH_post_orders_ID_pay (const struct TMH_RequestHandler *rh, 5460 struct MHD_Connection *connection, 5461 struct TMH_HandlerContext *hc) 5462 { 5463 struct PayContext *pc = hc->ctx; 5464 5465 GNUNET_assert (NULL != hc->infix); 5466 if (NULL == pc) 5467 { 5468 pc = GNUNET_new (struct PayContext); 5469 pc->connection = connection; 5470 pc->hc = hc; 5471 pc->order_id = hc->infix; 5472 hc->ctx = pc; 5473 hc->cc = &pay_context_cleanup; 5474 GNUNET_CONTAINER_DLL_insert (pc_head, 5475 pc_tail, 5476 pc); 5477 } 5478 while (1) 5479 { 5480 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 5481 "Processing /pay in phase %d\n", 5482 (int) pc->phase); 5483 switch (pc->phase) 5484 { 5485 case PP_PARSE_PAY: 5486 phase_parse_pay (pc); 5487 break; 5488 case PP_PARSE_WALLET_DATA: 5489 phase_parse_wallet_data (pc); 5490 break; 5491 case PP_CHECK_CONTRACT: 5492 phase_check_contract (pc); 5493 break; 5494 case PP_VALIDATE_TOKENS: 5495 phase_validate_tokens (pc); 5496 break; 5497 case PP_CONTRACT_PAID: 5498 phase_contract_paid (pc); 5499 break; 5500 case PP_COMPUTE_MONEY_POTS: 5501 phase_compute_money_pots (pc); 5502 break; 5503 case PP_PAY_TRANSACTION: 5504 phase_execute_pay_transaction (pc); 5505 break; 5506 case PP_REQUEST_DONATION_RECEIPT: 5507 phase_request_donation_receipt (pc); 5508 break; 5509 case PP_FINAL_OUTPUT_TOKEN_PROCESSING: 5510 phase_final_output_token_processing (pc); 5511 break; 5512 case PP_PAYMENT_NOTIFICATION: 5513 phase_payment_notification (pc); 5514 break; 5515 case PP_SUCCESS_RESPONSE: 5516 phase_success_response (pc); 5517 break; 5518 case PP_BATCH_DEPOSITS: 5519 phase_batch_deposits (pc); 5520 break; 5521 case PP_RETURN_RESPONSE: 5522 phase_return_response (pc); 5523 break; 5524 case PP_FAIL_LEGAL_REASONS: 5525 phase_fail_for_legal_reasons (pc); 5526 break; 5527 case PP_END_YES: 5528 return MHD_YES; 5529 case PP_END_NO: 5530 return MHD_NO; 5531 default: 5532 /* should not be reachable */ 5533 GNUNET_assert (0); 5534 return MHD_NO; 5535 } 5536 switch (pc->suspended) 5537 { 5538 case GNUNET_SYSERR: 5539 /* during shutdown, we don't generate any more replies */ 5540 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 5541 "Processing /pay ends due to shutdown in phase %d\n", 5542 (int) pc->phase); 5543 return MHD_NO; 5544 case GNUNET_NO: 5545 /* continue to next phase */ 5546 break; 5547 case GNUNET_YES: 5548 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 5549 "Processing /pay suspended in phase %d\n", 5550 (int) pc->phase); 5551 return MHD_YES; 5552 } 5553 } 5554 /* impossible to get here */ 5555 GNUNET_assert (0); 5556 return MHD_YES; 5557 } 5558 5559 5560 /* end of taler-merchant-httpd_post-orders-ORDER_ID-pay.c */