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