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