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