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