taler-merchant-httpd_post-orders-ORDER_ID-pay.c (165001B)
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 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 1527 "Processing payment with keys from exchange %s\n", 1528 eg->exchange_url); 1529 GNUNET_assert (GNUNET_YES == pc->suspended); 1530 if (NULL == keys) 1531 { 1532 GNUNET_break_op (0); 1533 resume_pay_with_error ( 1534 pc, 1535 TALER_EC_MERCHANT_GENERIC_EXCHANGE_TIMEOUT, 1536 NULL); 1537 return; 1538 } 1539 eg->keys = TALER_EXCHANGE_keys_incref (keys); 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 GNUNET_assert (GNUNET_OK == 2395 TALER_amount_set_zero (pc->parse_pay.dc[0].cdd.amount.currency, 2396 &assigned)); 2397 GNUNET_assert (NULL != contract); 2398 for (size_t i = 0; i<contract->products_len; i++) 2399 { 2400 const struct TALER_MERCHANT_ProductSold *product 2401 = &contract->products[i]; 2402 const struct TALER_Amount *price = NULL; 2403 2404 /* find price in the right currency */ 2405 for (unsigned int j = 0; j<product->prices_length; j++) 2406 { 2407 if (GNUNET_OK == 2408 TALER_amount_cmp_currency (&assigned, 2409 &product->prices[j])) 2410 { 2411 price = &product->prices[j]; 2412 break; 2413 } 2414 } 2415 if (NULL == price) 2416 { 2417 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 2418 "Product `%s' has no price given in `%s'.\n", 2419 product->product_id, 2420 assigned.currency); 2421 continue; 2422 } 2423 if (0 != product->product_money_pot) 2424 { 2425 GNUNET_assert (0 <= 2426 TALER_amount_add (&assigned, 2427 &assigned, 2428 price)); 2429 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 2430 "Contributing to product money pot %llu increment of %s\n", 2431 (unsigned long long) product->product_money_pot, 2432 TALER_amount2s (price)); 2433 increment_pot (pc, 2434 product->product_money_pot, 2435 price); 2436 } 2437 } 2438 2439 { 2440 /* Compute what is left from the order total and account for that. 2441 Also sanity-check and handle the case where the overall order 2442 is below that of the sum of the products. */ 2443 struct TALER_Amount left; 2444 2445 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 2446 "Order brutto is %s\n", 2447 TALER_amount2s (&pc->validate_tokens.brutto)); 2448 if (0 > 2449 TALER_amount_subtract (&left, 2450 &pc->validate_tokens.brutto, 2451 &assigned)) 2452 { 2453 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 2454 "Total order brutto amount below sum from products, skipping per-product money pots\n"); 2455 GNUNET_free (pc->compute_money_pots.pots); 2456 GNUNET_free (pc->compute_money_pots.increments); 2457 pc->compute_money_pots.num_pots = 0; 2458 left = pc->validate_tokens.brutto; 2459 } 2460 2461 if ( (! TALER_amount_is_zero (&left)) && 2462 (0 != contract->default_money_pot) ) 2463 { 2464 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 2465 "Computing money pot %llu increment as %s\n", 2466 (unsigned long long) contract->default_money_pot, 2467 TALER_amount2s (&left)); 2468 increment_pot (pc, 2469 contract->default_money_pot, 2470 &left); 2471 } 2472 } 2473 pc->compute_money_pots.pots_computed = true; 2474 pc->phase++; 2475 } 2476 2477 2478 /** 2479 * Function called with information about a coin that was deposited. 2480 * 2481 * @param cls closure 2482 * @param exchange_url exchange where @a coin_pub was deposited 2483 * @param coin_pub public key of the coin 2484 * @param amount_with_fee amount the exchange will deposit for this coin 2485 * @param deposit_fee fee the exchange will charge for this coin 2486 * @param refund_fee fee the exchange will charge for refunding this coin 2487 */ 2488 static void 2489 check_coin_paid (void *cls, 2490 const char *exchange_url, 2491 const struct TALER_CoinSpendPublicKeyP *coin_pub, 2492 const struct TALER_Amount *amount_with_fee, 2493 const struct TALER_Amount *deposit_fee, 2494 const struct TALER_Amount *refund_fee) 2495 { 2496 struct PayContext *pc = cls; 2497 2498 for (size_t i = 0; i<pc->parse_pay.coins_cnt; i++) 2499 { 2500 struct DepositConfirmation *dc = &pc->parse_pay.dc[i]; 2501 2502 if (dc->found_in_db) 2503 continue; /* processed earlier, skip "expensive" memcmp() */ 2504 /* Get matching coin from results*/ 2505 if ( (0 != GNUNET_memcmp (coin_pub, 2506 &dc->cdd.coin_pub)) || 2507 (0 != 2508 strcmp (exchange_url, 2509 dc->exchange_url)) || 2510 (GNUNET_OK != 2511 TALER_amount_cmp_currency (amount_with_fee, 2512 &dc->cdd.amount)) || 2513 (0 != TALER_amount_cmp (amount_with_fee, 2514 &dc->cdd.amount)) ) 2515 continue; /* does not match, skip */ 2516 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 2517 "Deposit of coin `%s' already in our DB.\n", 2518 TALER_B2S (coin_pub)); 2519 if ( (GNUNET_OK != 2520 TALER_amount_cmp_currency (&pc->pay_transaction.total_paid, 2521 amount_with_fee)) || 2522 (GNUNET_OK != 2523 TALER_amount_cmp_currency (&pc->pay_transaction.total_fees_paid, 2524 deposit_fee)) ) 2525 { 2526 GNUNET_break_op (0); 2527 pc->pay_transaction.deposit_currency_mismatch = true; 2528 break; 2529 } 2530 GNUNET_assert (0 <= 2531 TALER_amount_add (&pc->pay_transaction.total_paid, 2532 &pc->pay_transaction.total_paid, 2533 amount_with_fee)); 2534 GNUNET_assert (0 <= 2535 TALER_amount_add (&pc->pay_transaction.total_fees_paid, 2536 &pc->pay_transaction.total_fees_paid, 2537 deposit_fee)); 2538 dc->deposit_fee = *deposit_fee; 2539 dc->refund_fee = *refund_fee; 2540 dc->cdd.amount = *amount_with_fee; 2541 dc->found_in_db = true; 2542 pc->pay_transaction.pending--; 2543 } 2544 } 2545 2546 2547 /** 2548 * Function called with information about a refund. Check if this coin was 2549 * claimed by the wallet for the transaction, and if so add the refunded 2550 * amount to the pc's "total_refunded" amount. 2551 * 2552 * @param cls closure with a `struct PayContext` 2553 * @param coin_pub public coin from which the refund comes from 2554 * @param refund_amount refund amount which is being taken from @a coin_pub 2555 */ 2556 static void 2557 check_coin_refunded (void *cls, 2558 const struct TALER_CoinSpendPublicKeyP *coin_pub, 2559 const struct TALER_Amount *refund_amount) 2560 { 2561 struct PayContext *pc = cls; 2562 2563 /* We look at refunds here that apply to the coins 2564 that the customer is currently trying to pay us with. 2565 2566 Such refunds are not "normal" refunds, but abort-pay refunds, which are 2567 given in the case that the wallet aborts the payment. 2568 In the case the wallet then decides to complete the payment *after* doing 2569 an abort-pay refund (an unusual but possible case), we need 2570 to make sure that existing refunds are accounted for. */ 2571 2572 for (size_t i = 0; i<pc->parse_pay.coins_cnt; i++) 2573 { 2574 struct DepositConfirmation *dc = &pc->parse_pay.dc[i]; 2575 2576 /* Get matching coins from results. */ 2577 if (0 != GNUNET_memcmp (coin_pub, 2578 &dc->cdd.coin_pub)) 2579 continue; 2580 if (GNUNET_OK != 2581 TALER_amount_cmp_currency (&pc->pay_transaction.total_refunded, 2582 refund_amount)) 2583 { 2584 GNUNET_break (0); 2585 pc->pay_transaction.refund_currency_mismatch = true; 2586 break; 2587 } 2588 GNUNET_assert (0 <= 2589 TALER_amount_add (&pc->pay_transaction.total_refunded, 2590 &pc->pay_transaction.total_refunded, 2591 refund_amount)); 2592 break; 2593 } 2594 } 2595 2596 2597 /** 2598 * Check whether the amount paid is sufficient to cover the price. 2599 * 2600 * @param pc payment context to check 2601 * @return true if the payment is sufficient, false if it is 2602 * insufficient 2603 */ 2604 static bool 2605 check_payment_sufficient (struct PayContext *pc) 2606 { 2607 struct TALER_Amount acc_fee; 2608 struct TALER_Amount acc_amount; 2609 struct TALER_Amount final_amount; 2610 struct TALER_Amount total_wire_fee; 2611 struct TALER_Amount total_needed; 2612 2613 if (0 == pc->parse_pay.coins_cnt) 2614 return TALER_amount_is_zero (&pc->validate_tokens.brutto); 2615 GNUNET_assert (GNUNET_OK == 2616 TALER_amount_set_zero (pc->validate_tokens.brutto.currency, 2617 &total_wire_fee)); 2618 for (unsigned int i = 0; i < pc->parse_pay.num_exchanges; i++) 2619 { 2620 if (GNUNET_OK != 2621 TALER_amount_cmp_currency (&total_wire_fee, 2622 &pc->parse_pay.egs[i]->wire_fee)) 2623 { 2624 GNUNET_break_op (0); 2625 pay_end (pc, 2626 TALER_MHD_reply_with_error (pc->connection, 2627 MHD_HTTP_BAD_REQUEST, 2628 TALER_EC_GENERIC_CURRENCY_MISMATCH, 2629 total_wire_fee.currency)); 2630 return false; 2631 } 2632 if (0 > 2633 TALER_amount_add (&total_wire_fee, 2634 &total_wire_fee, 2635 &pc->parse_pay.egs[i]->wire_fee)) 2636 { 2637 GNUNET_break (0); 2638 pay_end (pc, 2639 TALER_MHD_reply_with_error ( 2640 pc->connection, 2641 MHD_HTTP_INTERNAL_SERVER_ERROR, 2642 TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_EXCHANGE_WIRE_FEE_ADDITION_FAILED, 2643 "could not add exchange wire fee to total")); 2644 return false; 2645 } 2646 } 2647 2648 /** 2649 * This loops calculates what are the deposit fee / total 2650 * amount with fee / and wire fee, for all the coins. 2651 */ 2652 GNUNET_assert (GNUNET_OK == 2653 TALER_amount_set_zero (pc->validate_tokens.brutto.currency, 2654 &acc_fee)); 2655 GNUNET_assert (GNUNET_OK == 2656 TALER_amount_set_zero (pc->validate_tokens.brutto.currency, 2657 &acc_amount)); 2658 for (size_t i = 0; i<pc->parse_pay.coins_cnt; i++) 2659 { 2660 struct DepositConfirmation *dc = &pc->parse_pay.dc[i]; 2661 2662 GNUNET_assert (dc->found_in_db); 2663 if ( (GNUNET_OK != 2664 TALER_amount_cmp_currency (&acc_fee, 2665 &dc->deposit_fee)) || 2666 (GNUNET_OK != 2667 TALER_amount_cmp_currency (&acc_amount, 2668 &dc->cdd.amount)) ) 2669 { 2670 GNUNET_break_op (0); 2671 pay_end (pc, 2672 TALER_MHD_reply_with_error ( 2673 pc->connection, 2674 MHD_HTTP_BAD_REQUEST, 2675 TALER_EC_GENERIC_CURRENCY_MISMATCH, 2676 dc->deposit_fee.currency)); 2677 return false; 2678 } 2679 if ( (0 > 2680 TALER_amount_add (&acc_fee, 2681 &dc->deposit_fee, 2682 &acc_fee)) || 2683 (0 > 2684 TALER_amount_add (&acc_amount, 2685 &dc->cdd.amount, 2686 &acc_amount)) ) 2687 { 2688 GNUNET_break (0); 2689 /* Overflow in these amounts? Very strange. */ 2690 pay_end (pc, 2691 TALER_MHD_reply_with_error ( 2692 pc->connection, 2693 MHD_HTTP_INTERNAL_SERVER_ERROR, 2694 TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_AMOUNT_OVERFLOW, 2695 "Overflow adding up amounts")); 2696 return false; 2697 } 2698 if (1 == 2699 TALER_amount_cmp (&dc->deposit_fee, 2700 &dc->cdd.amount)) 2701 { 2702 GNUNET_break_op (0); 2703 pay_end (pc, 2704 TALER_MHD_reply_with_error ( 2705 pc->connection, 2706 MHD_HTTP_BAD_REQUEST, 2707 TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_FEES_EXCEED_PAYMENT, 2708 "Deposit fees exceed coin's contribution")); 2709 return false; 2710 } 2711 } /* end deposit loop */ 2712 2713 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 2714 "Amount received from wallet: %s\n", 2715 TALER_amount2s (&acc_amount)); 2716 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 2717 "Deposit fee for all coins: %s\n", 2718 TALER_amount2s (&acc_fee)); 2719 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 2720 "Total wire fee: %s\n", 2721 TALER_amount2s (&total_wire_fee)); 2722 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 2723 "Deposit fee limit for merchant: %s\n", 2724 TALER_amount2s (&pc->validate_tokens.max_fee)); 2725 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 2726 "Total refunded amount: %s\n", 2727 TALER_amount2s (&pc->pay_transaction.total_refunded)); 2728 2729 /* Now compare exchange wire fee compared to what we are willing to pay */ 2730 if (GNUNET_YES != 2731 TALER_amount_cmp_currency (&total_wire_fee, 2732 &acc_fee)) 2733 { 2734 GNUNET_break (0); 2735 pay_end (pc, 2736 TALER_MHD_reply_with_error ( 2737 pc->connection, 2738 MHD_HTTP_BAD_REQUEST, 2739 TALER_EC_GENERIC_CURRENCY_MISMATCH, 2740 total_wire_fee.currency)); 2741 return false; 2742 } 2743 2744 /* add wire fee to the total fees */ 2745 if (0 > 2746 TALER_amount_add (&acc_fee, 2747 &acc_fee, 2748 &total_wire_fee)) 2749 { 2750 GNUNET_break (0); 2751 pay_end (pc, 2752 TALER_MHD_reply_with_error ( 2753 pc->connection, 2754 MHD_HTTP_INTERNAL_SERVER_ERROR, 2755 TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_AMOUNT_OVERFLOW, 2756 "Overflow adding up amounts")); 2757 return false; 2758 } 2759 if (-1 == TALER_amount_cmp (&pc->validate_tokens.max_fee, 2760 &acc_fee)) 2761 { 2762 /** 2763 * Sum of fees of *all* the different exchanges of all the coins are 2764 * higher than the fixed limit that the merchant is willing to pay. The 2765 * difference must be paid by the customer. 2766 */ 2767 struct TALER_Amount excess_fee; 2768 2769 /* compute fee amount to be covered by customer */ 2770 GNUNET_assert (TALER_AAR_RESULT_POSITIVE == 2771 TALER_amount_subtract (&excess_fee, 2772 &acc_fee, 2773 &pc->validate_tokens.max_fee)); 2774 /* add that to the total */ 2775 if (0 > 2776 TALER_amount_add (&total_needed, 2777 &excess_fee, 2778 &pc->validate_tokens.brutto)) 2779 { 2780 GNUNET_break (0); 2781 pay_end (pc, 2782 TALER_MHD_reply_with_error ( 2783 pc->connection, 2784 MHD_HTTP_INTERNAL_SERVER_ERROR, 2785 TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_AMOUNT_OVERFLOW, 2786 "Overflow adding up amounts")); 2787 return false; 2788 } 2789 } 2790 else 2791 { 2792 /* Fees are fully covered by the merchant, all we require 2793 is that the total payment is not below the contract's amount */ 2794 total_needed = pc->validate_tokens.brutto; 2795 } 2796 2797 /* Do not count refunds towards the payment */ 2798 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 2799 "Subtracting total refunds from paid amount: %s\n", 2800 TALER_amount2s (&pc->pay_transaction.total_refunded)); 2801 if (0 > 2802 TALER_amount_subtract (&final_amount, 2803 &acc_amount, 2804 &pc->pay_transaction.total_refunded)) 2805 { 2806 GNUNET_break (0); 2807 pay_end (pc, 2808 TALER_MHD_reply_with_error ( 2809 pc->connection, 2810 MHD_HTTP_INTERNAL_SERVER_ERROR, 2811 TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_REFUNDS_EXCEED_PAYMENTS, 2812 "refunded amount exceeds total payments")); 2813 return false; 2814 } 2815 2816 if (-1 == TALER_amount_cmp (&final_amount, 2817 &total_needed)) 2818 { 2819 /* acc_amount < total_needed */ 2820 if (-1 < TALER_amount_cmp (&acc_amount, 2821 &total_needed)) 2822 { 2823 GNUNET_break_op (0); 2824 pay_end (pc, 2825 TALER_MHD_reply_with_error ( 2826 pc->connection, 2827 MHD_HTTP_PAYMENT_REQUIRED, 2828 TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_REFUNDED, 2829 "contract not paid up due to refunds")); 2830 return false; 2831 } 2832 if (-1 < TALER_amount_cmp (&acc_amount, 2833 &pc->validate_tokens.brutto)) 2834 { 2835 GNUNET_break_op (0); 2836 pay_end (pc, 2837 TALER_MHD_reply_with_error ( 2838 pc->connection, 2839 MHD_HTTP_BAD_REQUEST, 2840 TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_INSUFFICIENT_DUE_TO_FEES, 2841 "contract not paid up due to fees (client may have calculated them badly)")); 2842 return false; 2843 } 2844 GNUNET_break_op (0); 2845 pay_end (pc, 2846 TALER_MHD_reply_with_error ( 2847 pc->connection, 2848 MHD_HTTP_BAD_REQUEST, 2849 TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_PAYMENT_INSUFFICIENT, 2850 "payment insufficient")); 2851 return false; 2852 } 2853 return true; 2854 } 2855 2856 2857 /** 2858 * Execute the DB transaction. If required (from 2859 * soft/serialization errors), the transaction can be 2860 * restarted here. 2861 * 2862 * @param[in,out] pc payment context to transact 2863 */ 2864 static void 2865 phase_execute_pay_transaction (struct PayContext *pc) 2866 { 2867 struct TMH_HandlerContext *hc = pc->hc; 2868 const char *instance_id = hc->instance->settings.id; 2869 2870 if (pc->batch_deposits.got_451) 2871 { 2872 pc->phase = PP_FAIL_LEGAL_REASONS; 2873 return; 2874 } 2875 /* Avoid re-trying transactions on soft errors forever! */ 2876 if (pc->pay_transaction.retry_counter++ > MAX_RETRIES) 2877 { 2878 GNUNET_break (0); 2879 pay_end (pc, 2880 TALER_MHD_reply_with_error (pc->connection, 2881 MHD_HTTP_INTERNAL_SERVER_ERROR, 2882 TALER_EC_GENERIC_DB_SOFT_FAILURE, 2883 NULL)); 2884 return; 2885 } 2886 2887 /* Initialize some amount accumulators 2888 (used in check_coin_paid(), check_coin_refunded() 2889 and check_payment_sufficient()). */ 2890 GNUNET_break (GNUNET_OK == 2891 TALER_amount_set_zero (pc->validate_tokens.brutto.currency, 2892 &pc->pay_transaction.total_paid)); 2893 GNUNET_break (GNUNET_OK == 2894 TALER_amount_set_zero (pc->validate_tokens.brutto.currency, 2895 &pc->pay_transaction.total_fees_paid)); 2896 GNUNET_break (GNUNET_OK == 2897 TALER_amount_set_zero (pc->validate_tokens.brutto.currency, 2898 &pc->pay_transaction.total_refunded)); 2899 for (size_t i = 0; i<pc->parse_pay.coins_cnt; i++) 2900 pc->parse_pay.dc[i].found_in_db = false; 2901 pc->pay_transaction.pending = pc->parse_pay.coins_cnt; 2902 2903 /* First, try to see if we have all we need already done */ 2904 TALER_MERCHANTDB_preflight (TMH_db); 2905 if (GNUNET_OK != 2906 TALER_MERCHANTDB_start (TMH_db, 2907 "run pay")) 2908 { 2909 GNUNET_break (0); 2910 pay_end (pc, 2911 TALER_MHD_reply_with_error (pc->connection, 2912 MHD_HTTP_INTERNAL_SERVER_ERROR, 2913 TALER_EC_GENERIC_DB_START_FAILED, 2914 NULL)); 2915 return; 2916 } 2917 2918 for (size_t i = 0; i<pc->parse_pay.tokens_cnt; i++) 2919 { 2920 struct TokenUseConfirmation *tuc = &pc->parse_pay.tokens[i]; 2921 enum GNUNET_DB_QueryStatus qs; 2922 2923 /* Insert used token into database, the unique constraint will 2924 case an error if this token was used before. */ 2925 qs = TALER_MERCHANTDB_insert_spent_token (TMH_db, 2926 &pc->check_contract.h_contract_terms, 2927 &tuc->h_issue, 2928 &tuc->pub, 2929 &tuc->sig, 2930 &tuc->unblinded_sig); 2931 2932 switch (qs) 2933 { 2934 case GNUNET_DB_STATUS_SOFT_ERROR: 2935 TALER_MERCHANTDB_rollback (TMH_db); 2936 return; /* do it again */ 2937 case GNUNET_DB_STATUS_HARD_ERROR: 2938 /* Always report on hard error as well to enable diagnostics */ 2939 TALER_MERCHANTDB_rollback (TMH_db); 2940 pay_end (pc, 2941 TALER_MHD_reply_with_error (pc->connection, 2942 MHD_HTTP_INTERNAL_SERVER_ERROR, 2943 TALER_EC_GENERIC_DB_STORE_FAILED, 2944 "insert used token")); 2945 return; 2946 case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS: 2947 /* UNIQUE constraint violation, meaning this token was already used. */ 2948 TALER_MERCHANTDB_rollback (TMH_db); 2949 pay_end (pc, 2950 TALER_MHD_reply_with_error (pc->connection, 2951 MHD_HTTP_CONFLICT, 2952 TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_TOKEN_INVALID, 2953 NULL)); 2954 return; 2955 case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT: 2956 /* Good, proceed! */ 2957 break; 2958 } 2959 } /* for all tokens */ 2960 2961 { 2962 enum GNUNET_DB_QueryStatus qs; 2963 2964 /* Check if some of these coins already succeeded for _this_ contract. */ 2965 qs = TALER_MERCHANTDB_lookup_deposits (TMH_db, 2966 instance_id, 2967 &pc->check_contract.h_contract_terms, 2968 &check_coin_paid, 2969 pc); 2970 if (0 > qs) 2971 { 2972 TALER_MERCHANTDB_rollback (TMH_db); 2973 if (GNUNET_DB_STATUS_SOFT_ERROR == qs) 2974 return; /* do it again */ 2975 /* Always report on hard error as well to enable diagnostics */ 2976 GNUNET_break (GNUNET_DB_STATUS_HARD_ERROR == qs); 2977 pay_end (pc, 2978 TALER_MHD_reply_with_error (pc->connection, 2979 MHD_HTTP_INTERNAL_SERVER_ERROR, 2980 TALER_EC_GENERIC_DB_FETCH_FAILED, 2981 "lookup deposits")); 2982 return; 2983 } 2984 if (pc->pay_transaction.deposit_currency_mismatch) 2985 { 2986 TALER_MERCHANTDB_rollback (TMH_db); 2987 GNUNET_break_op (0); 2988 pay_end (pc, 2989 TALER_MHD_reply_with_error ( 2990 pc->connection, 2991 MHD_HTTP_BAD_REQUEST, 2992 TALER_EC_MERCHANT_GENERIC_CURRENCY_MISMATCH, 2993 pc->validate_tokens.brutto.currency)); 2994 return; 2995 } 2996 } 2997 2998 { 2999 enum GNUNET_DB_QueryStatus qs; 3000 3001 /* Check if we refunded some of the coins */ 3002 qs = TALER_MERCHANTDB_lookup_refunds (TMH_db, 3003 instance_id, 3004 &pc->check_contract.h_contract_terms, 3005 &check_coin_refunded, 3006 pc); 3007 if (0 > qs) 3008 { 3009 TALER_MERCHANTDB_rollback (TMH_db); 3010 if (GNUNET_DB_STATUS_SOFT_ERROR == qs) 3011 return; /* do it again */ 3012 /* Always report on hard error as well to enable diagnostics */ 3013 GNUNET_break (GNUNET_DB_STATUS_HARD_ERROR == qs); 3014 pay_end (pc, 3015 TALER_MHD_reply_with_error (pc->connection, 3016 MHD_HTTP_INTERNAL_SERVER_ERROR, 3017 TALER_EC_GENERIC_DB_FETCH_FAILED, 3018 "lookup refunds")); 3019 return; 3020 } 3021 if (pc->pay_transaction.refund_currency_mismatch) 3022 { 3023 TALER_MERCHANTDB_rollback (TMH_db); 3024 pay_end (pc, 3025 TALER_MHD_reply_with_error (pc->connection, 3026 MHD_HTTP_INTERNAL_SERVER_ERROR, 3027 TALER_EC_GENERIC_DB_FETCH_FAILED, 3028 "refund currency in database does not match order currency")); 3029 return; 3030 } 3031 } 3032 3033 /* Check if there are coins that still need to be processed */ 3034 if (0 != pc->pay_transaction.pending) 3035 { 3036 /* we made no DB changes, so we can just rollback */ 3037 TALER_MERCHANTDB_rollback (TMH_db); 3038 /* Ok, we need to first go to the network to process more coins. 3039 We that interaction in *tiny* transactions (hence the rollback 3040 above). */ 3041 pc->phase = PP_BATCH_DEPOSITS; 3042 return; 3043 } 3044 3045 /* 0 == pc->pay_transaction.pending: all coins processed, let's see if that was enough */ 3046 if (! check_payment_sufficient (pc)) 3047 { 3048 /* check_payment_sufficient() will have queued an error already. 3049 We need to still abort the transaction. */ 3050 TALER_MERCHANTDB_rollback (TMH_db); 3051 return; 3052 } 3053 /* Payment succeeded, save in database */ 3054 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 3055 "Order `%s' (%s) was fully paid\n", 3056 pc->order_id, 3057 GNUNET_h2s (&pc->check_contract.h_contract_terms.hash)); 3058 { 3059 enum GNUNET_DB_QueryStatus qs; 3060 3061 qs = TALER_MERCHANTDB_mark_contract_paid (TMH_db, 3062 instance_id, 3063 &pc->check_contract.h_contract_terms, 3064 pc->parse_pay.session_id, 3065 pc->parse_wallet_data.choice_index); 3066 if (qs < 0) 3067 { 3068 TALER_MERCHANTDB_rollback (TMH_db); 3069 if (GNUNET_DB_STATUS_SOFT_ERROR == qs) 3070 return; /* do it again */ 3071 GNUNET_break (0); 3072 pay_end (pc, 3073 TALER_MHD_reply_with_error (pc->connection, 3074 MHD_HTTP_INTERNAL_SERVER_ERROR, 3075 TALER_EC_GENERIC_DB_STORE_FAILED, 3076 "mark contract paid")); 3077 return; 3078 } 3079 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 3080 "Marked contract paid returned %d\n", 3081 (int) qs); 3082 3083 if ( (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT == qs) && 3084 (0 < pc->compute_money_pots.num_pots) ) 3085 { 3086 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 3087 "Incrementing %u money pots by %s\n", 3088 pc->compute_money_pots.num_pots, 3089 TALER_amount2s (&pc->compute_money_pots.increments[0])); 3090 qs = TALER_MERCHANTDB_increment_money_pots (TMH_db, 3091 instance_id, 3092 pc->compute_money_pots.num_pots, 3093 pc->compute_money_pots.pots, 3094 pc->compute_money_pots.increments); 3095 switch (qs) 3096 { 3097 case GNUNET_DB_STATUS_SOFT_ERROR: 3098 TALER_MERCHANTDB_rollback (TMH_db); 3099 return; /* do it again */ 3100 case GNUNET_DB_STATUS_HARD_ERROR: 3101 /* Always report on hard error as well to enable diagnostics */ 3102 TALER_MERCHANTDB_rollback (TMH_db); 3103 pay_end (pc, 3104 TALER_MHD_reply_with_error (pc->connection, 3105 MHD_HTTP_INTERNAL_SERVER_ERROR, 3106 TALER_EC_GENERIC_DB_STORE_FAILED, 3107 "increment_money_pots")); 3108 return; 3109 case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS: 3110 /* strange */ 3111 GNUNET_break (0); 3112 break; 3113 case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT: 3114 /* Good, proceed! */ 3115 break; 3116 } 3117 3118 } 3119 3120 3121 } 3122 3123 3124 { 3125 const struct TALER_MERCHANT_ContractChoice *choice = 3126 &pc->check_contract.contract_terms->details.v1 3127 .choices[pc->parse_wallet_data.choice_index]; 3128 3129 for (size_t i = 0; i<pc->output_tokens_len; i++) 3130 { 3131 unsigned int output_index; 3132 enum TALER_MERCHANT_ContractOutputType type; 3133 3134 output_index = pc->output_tokens[i].output_index; 3135 GNUNET_assert (output_index < choice->outputs_len); 3136 type = choice->outputs[output_index].type; 3137 3138 switch (type) 3139 { 3140 case TALER_MERCHANT_CONTRACT_OUTPUT_TYPE_INVALID: 3141 /* Well, good luck getting here */ 3142 GNUNET_break (0); 3143 pay_end (pc, 3144 TALER_MHD_reply_with_error (pc->connection, 3145 MHD_HTTP_INTERNAL_SERVER_ERROR, 3146 TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE, 3147 "invalid output type")); 3148 break; 3149 case TALER_MERCHANT_CONTRACT_OUTPUT_TYPE_DONATION_RECEIPT: 3150 /* We skip output tokens of donation receipts here, as they are handled in the 3151 * phase_final_output_token_processing() callback from donau */ 3152 break; 3153 case TALER_MERCHANT_CONTRACT_OUTPUT_TYPE_TOKEN: 3154 struct SignedOutputToken *output = 3155 &pc->output_tokens[i]; 3156 enum GNUNET_DB_QueryStatus qs; 3157 3158 qs = TALER_MERCHANTDB_insert_issued_token (TMH_db, 3159 &pc->check_contract.h_contract_terms, 3160 &output->h_issue, 3161 &output->sig); 3162 switch (qs) 3163 { 3164 case GNUNET_DB_STATUS_HARD_ERROR: 3165 TALER_MERCHANTDB_rollback (TMH_db); 3166 GNUNET_break (GNUNET_DB_STATUS_HARD_ERROR == qs); 3167 pay_end (pc, 3168 TALER_MHD_reply_with_error (pc->connection, 3169 MHD_HTTP_INTERNAL_SERVER_ERROR, 3170 TALER_EC_GENERIC_DB_STORE_FAILED, 3171 "insert output token")); 3172 return; 3173 case GNUNET_DB_STATUS_SOFT_ERROR: 3174 /* Serialization failure, retry */ 3175 TALER_MERCHANTDB_rollback (TMH_db); 3176 return; 3177 case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS: 3178 /* UNIQUE constraint violation, meaning this token was already used. */ 3179 TALER_MERCHANTDB_rollback (TMH_db); 3180 pay_end (pc, 3181 TALER_MHD_reply_with_error (pc->connection, 3182 MHD_HTTP_INTERNAL_SERVER_ERROR, 3183 TALER_EC_GENERIC_DB_STORE_FAILED, 3184 "duplicate output token")); 3185 return; 3186 case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT: 3187 break; 3188 } 3189 break; 3190 } 3191 } 3192 } 3193 3194 TMH_notify_order_change (hc->instance, 3195 TMH_OSF_CLAIMED | TMH_OSF_PAID, 3196 pc->check_contract.contract_terms->timestamp, 3197 pc->check_contract.order_serial); 3198 { 3199 enum GNUNET_DB_QueryStatus qs; 3200 json_t *jhook; 3201 3202 jhook = GNUNET_JSON_PACK ( 3203 GNUNET_JSON_pack_object_incref ("contract_terms", 3204 pc->check_contract.contract_terms_json), 3205 GNUNET_JSON_pack_string ("order_id", 3206 pc->order_id) 3207 ); 3208 GNUNET_assert (NULL != jhook); 3209 qs = TMH_trigger_webhook (pc->hc->instance->settings.id, 3210 "pay", 3211 jhook); 3212 json_decref (jhook); 3213 if (qs < 0) 3214 { 3215 TALER_MERCHANTDB_rollback (TMH_db); 3216 if (GNUNET_DB_STATUS_SOFT_ERROR == qs) 3217 return; /* do it again */ 3218 GNUNET_break (0); 3219 pay_end (pc, 3220 TALER_MHD_reply_with_error (pc->connection, 3221 MHD_HTTP_INTERNAL_SERVER_ERROR, 3222 TALER_EC_GENERIC_DB_STORE_FAILED, 3223 "failed to trigger webhooks")); 3224 return; 3225 } 3226 } 3227 { 3228 enum GNUNET_DB_QueryStatus qs; 3229 3230 /* Now commit! */ 3231 qs = TALER_MERCHANTDB_commit (TMH_db); 3232 if (0 > qs) 3233 { 3234 /* commit failed */ 3235 TALER_MERCHANTDB_rollback (TMH_db); 3236 if (GNUNET_DB_STATUS_SOFT_ERROR == qs) 3237 return; /* do it again */ 3238 GNUNET_break (0); 3239 pay_end (pc, 3240 TALER_MHD_reply_with_error (pc->connection, 3241 MHD_HTTP_INTERNAL_SERVER_ERROR, 3242 TALER_EC_GENERIC_DB_COMMIT_FAILED, 3243 NULL)); 3244 return; 3245 } 3246 } 3247 pc->phase++; 3248 } 3249 3250 3251 /** 3252 * Ensures that the expected number of tokens for a @e key 3253 * are provided as inputs and have valid signatures. 3254 * 3255 * @param[in,out] pc payment context we are processing 3256 * @param family family the tokens should be from 3257 * @param index number of the input we are handling 3258 * @param expected_num number of tokens expected 3259 * @return #GNUNET_YES on success 3260 */ 3261 static enum GNUNET_GenericReturnValue 3262 find_valid_input_tokens ( 3263 struct PayContext *pc, 3264 const struct TALER_MERCHANT_ContractTokenFamily *family, 3265 unsigned int index, 3266 unsigned int expected_num) 3267 { 3268 unsigned int num_validated = 0; 3269 struct GNUNET_TIME_Timestamp now 3270 = GNUNET_TIME_timestamp_get (); 3271 const struct TALER_MERCHANT_ContractTokenFamilyKey *kig = NULL; 3272 3273 for (unsigned int j = 0; j < expected_num; j++) 3274 { 3275 struct TokenUseConfirmation *tuc 3276 = &pc->parse_pay.tokens[index + j]; 3277 const struct TALER_MERCHANT_ContractTokenFamilyKey *key = NULL; 3278 3279 for (unsigned int i = 0; i<family->keys_len; i++) 3280 { 3281 const struct TALER_MERCHANT_ContractTokenFamilyKey *ki 3282 = &family->keys[i]; 3283 3284 if (0 == 3285 GNUNET_memcmp (&ki->pub.public_key->pub_key_hash, 3286 &tuc->h_issue.hash)) 3287 { 3288 if (GNUNET_TIME_timestamp_cmp (ki->valid_after, 3289 >, 3290 now) || 3291 GNUNET_TIME_timestamp_cmp (ki->valid_before, 3292 <=, 3293 now)) 3294 { 3295 /* We have a match, but not in the current validity period */ 3296 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 3297 "Public key %s currently not valid\n", 3298 GNUNET_h2s (&ki->pub.public_key->pub_key_hash)); 3299 kig = ki; 3300 continue; 3301 } 3302 key = ki; 3303 break; 3304 } 3305 } 3306 if (NULL == key) 3307 { 3308 if (NULL != kig) 3309 { 3310 char start_str[128]; 3311 char end_str[128]; 3312 char emsg[350]; 3313 3314 GNUNET_snprintf (start_str, 3315 sizeof (start_str), 3316 "%s", 3317 GNUNET_STRINGS_timestamp_to_string (kig->valid_after)); 3318 GNUNET_snprintf (end_str, 3319 sizeof (end_str), 3320 "%s", 3321 GNUNET_STRINGS_timestamp_to_string (kig->valid_before)) 3322 ; 3323 /* FIXME: use more specific EC */ 3324 GNUNET_snprintf (emsg, 3325 sizeof (emsg), 3326 "Token is only valid from %s to %s", 3327 start_str, 3328 end_str); 3329 pay_end (pc, 3330 TALER_MHD_reply_with_error ( 3331 pc->connection, 3332 MHD_HTTP_GONE, 3333 TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_OFFER_EXPIRED, 3334 emsg)); 3335 return GNUNET_NO; 3336 } 3337 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 3338 "Input token supplied for public key %s that is not acceptable\n", 3339 GNUNET_h2s (&tuc->h_issue.hash)); 3340 GNUNET_break_op (0); 3341 pay_end (pc, 3342 TALER_MHD_reply_with_error ( 3343 pc->connection, 3344 MHD_HTTP_BAD_REQUEST, 3345 TALER_EC_MERCHANT_GENERIC_TOKEN_KEY_UNKNOWN, 3346 NULL)); 3347 return GNUNET_NO; 3348 } 3349 if (GNUNET_OK != 3350 TALER_token_issue_verify (&tuc->pub, 3351 &key->pub, 3352 &tuc->unblinded_sig)) 3353 { 3354 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 3355 "Input token for public key with valid_after " 3356 "`%s' has invalid issue signature\n", 3357 GNUNET_TIME_timestamp2s (key->valid_after)); 3358 GNUNET_break (0); 3359 pay_end (pc, 3360 TALER_MHD_reply_with_error ( 3361 pc->connection, 3362 MHD_HTTP_BAD_REQUEST, 3363 TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_TOKEN_ISSUE_SIG_INVALID, 3364 NULL)); 3365 return GNUNET_NO; 3366 } 3367 3368 if (GNUNET_OK != 3369 TALER_wallet_token_use_verify (&pc->check_contract.h_contract_terms, 3370 &pc->parse_wallet_data.h_wallet_data, 3371 &tuc->pub, 3372 &tuc->sig)) 3373 { 3374 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 3375 "Input token for public key with valid_before " 3376 "`%s' has invalid use signature\n", 3377 GNUNET_TIME_timestamp2s (key->valid_before)); 3378 GNUNET_break (0); 3379 pay_end (pc, 3380 TALER_MHD_reply_with_error ( 3381 pc->connection, 3382 MHD_HTTP_BAD_REQUEST, 3383 TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_TOKEN_USE_SIG_INVALID, 3384 NULL)); 3385 return GNUNET_NO; 3386 } 3387 3388 num_validated++; 3389 } 3390 3391 if (num_validated != expected_num) 3392 { 3393 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 3394 "Expected %d tokens for family %s, but found %d\n", 3395 expected_num, 3396 family->slug, 3397 num_validated); 3398 GNUNET_break (0); 3399 pay_end (pc, 3400 TALER_MHD_reply_with_error ( 3401 pc->connection, 3402 MHD_HTTP_BAD_REQUEST, 3403 TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_TOKEN_COUNT_MISMATCH, 3404 NULL)); 3405 return GNUNET_NO; 3406 } 3407 return GNUNET_YES; 3408 } 3409 3410 3411 /** 3412 * Check if an output token of the given @a tfk is mandatory, or if 3413 * wallets are allowed to simply not support it and still proceed. 3414 * 3415 * @param tfk token family kind to check 3416 * @return true if such outputs are mandatory and wallets must supply 3417 * the corresponding blinded input 3418 */ 3419 /* FIXME: this function belongs into a lower-level lib! */ 3420 static bool 3421 test_tfk_mandatory (enum TALER_MERCHANTDB_TokenFamilyKind tfk) 3422 { 3423 switch (tfk) 3424 { 3425 case TALER_MERCHANTDB_TFK_Discount: 3426 return false; 3427 case TALER_MERCHANTDB_TFK_Subscription: 3428 return true; 3429 } 3430 GNUNET_break (0); 3431 return false; 3432 } 3433 3434 3435 /** 3436 * Sign the tokens provided by the wallet for a particular @a key. 3437 * 3438 * @param[in,out] pc reference for payment we are processing 3439 * @param key token family data 3440 * @param priv private key to use to sign with 3441 * @param mandatory true if the token must exist, if false 3442 * and the client did not provide an envelope, that's OK and 3443 * we just also skimp on the signature 3444 * @param index offset in the token envelope array (from other families) 3445 * @param expected_num number of tokens of this type that we should create 3446 * @return #GNUNET_NO on failure 3447 * #GNUNET_OK on success 3448 */ 3449 static enum GNUNET_GenericReturnValue 3450 sign_token_envelopes ( 3451 struct PayContext *pc, 3452 const struct TALER_MERCHANT_ContractTokenFamilyKey *key, 3453 const struct TALER_TokenIssuePrivateKey *priv, 3454 bool mandatory, 3455 unsigned int index, 3456 unsigned int expected_num) 3457 { 3458 unsigned int num_signed = 0; 3459 3460 for (unsigned int j = 0; j<expected_num; j++) 3461 { 3462 unsigned int pos = index + j; 3463 const struct TokenEnvelope *env 3464 = &pc->parse_wallet_data.token_envelopes[pos]; 3465 struct SignedOutputToken *output 3466 = &pc->output_tokens[pos]; 3467 3468 if ( (pos >= pc->parse_wallet_data.token_envelopes_cnt) || 3469 (pos >= pc->output_tokens_len) ) 3470 { 3471 GNUNET_assert (0); /* this should not happen */ 3472 return GNUNET_NO; 3473 } 3474 if (NULL == env->blinded_token.blinded_pub) 3475 { 3476 if (! mandatory) 3477 continue; 3478 3479 /* mandatory token families require a token envelope. */ 3480 GNUNET_break_op (0); 3481 pay_end (pc, 3482 TALER_MHD_reply_with_error ( 3483 pc->connection, 3484 MHD_HTTP_BAD_REQUEST, 3485 TALER_EC_GENERIC_PARAMETER_MALFORMED, 3486 "Token envelope for mandatory token family missing")); 3487 return GNUNET_NO; 3488 } 3489 TALER_token_issue_sign (priv, 3490 &env->blinded_token, 3491 &output->sig); 3492 output->h_issue.hash 3493 = key->pub.public_key->pub_key_hash; 3494 num_signed++; 3495 } 3496 3497 if (mandatory && 3498 (num_signed != expected_num) ) 3499 { 3500 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 3501 "Expected %d token envelopes for public key with valid_after " 3502 "'%s', but found %d\n", 3503 expected_num, 3504 GNUNET_TIME_timestamp2s (key->valid_after), 3505 num_signed); 3506 GNUNET_break (0); 3507 pay_end (pc, 3508 TALER_MHD_reply_with_error ( 3509 pc->connection, 3510 MHD_HTTP_BAD_REQUEST, 3511 TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_TOKEN_ENVELOPE_COUNT_MISMATCH, 3512 NULL)); 3513 return GNUNET_NO; 3514 } 3515 3516 return GNUNET_OK; 3517 } 3518 3519 3520 /** 3521 * Find the family entry for the family of the given @a slug 3522 * in @a pc. 3523 * 3524 * @param[in] pc payment context to search 3525 * @param slug slug to search for 3526 * @return NULL if @a slug was not found 3527 */ 3528 static const struct TALER_MERCHANT_ContractTokenFamily * 3529 find_family (const struct PayContext *pc, 3530 const char *slug) 3531 { 3532 for (unsigned int i = 0; 3533 i < pc->check_contract.contract_terms->details.v1.token_authorities_len; 3534 i++) 3535 { 3536 const struct TALER_MERCHANT_ContractTokenFamily *tfi 3537 = &pc->check_contract.contract_terms->details.v1.token_authorities[i]; 3538 3539 if (0 == strcmp (tfi->slug, 3540 slug)) 3541 { 3542 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 3543 "Token family %s found with %u keys\n", 3544 slug, 3545 tfi->keys_len); 3546 return tfi; 3547 } 3548 } 3549 return NULL; 3550 } 3551 3552 3553 /** 3554 * Handle contract output of type TALER_MERCHANT_CONTRACT_OUTPUT_TYPE_TOKEN. 3555 * Looks up the token family, loads the matching private key, 3556 * and signs the corresponding token envelopes from the wallet. 3557 * 3558 * @param pc context for the pay request 3559 * @param output contract output we need to process 3560 * @param output_index index of this output in the contract's outputs array 3561 * @return #GNUNET_OK on success, #GNUNET_NO if an error was encountered 3562 */ 3563 static enum GNUNET_GenericReturnValue 3564 handle_output_token (struct PayContext *pc, 3565 const struct TALER_MERCHANT_ContractOutput *output, 3566 unsigned int output_index) 3567 { 3568 const struct TALER_MERCHANT_ContractTokenFamily *family; 3569 struct TALER_MERCHANT_ContractTokenFamilyKey *key; 3570 struct TALER_MERCHANTDB_TokenFamilyKeyDetails details; 3571 enum GNUNET_DB_QueryStatus qs; 3572 bool mandatory; 3573 3574 /* Locate token family in the contract. 3575 This should ever fail as this invariant should 3576 have been checked when the contract was created. */ 3577 family = find_family (pc, 3578 output->details.token.token_family_slug); 3579 if (NULL == family) 3580 { 3581 /* This "should never happen", so treat it as an internal error */ 3582 GNUNET_break (0); 3583 pay_end (pc, 3584 TALER_MHD_reply_with_error ( 3585 pc->connection, 3586 MHD_HTTP_INTERNAL_SERVER_ERROR, 3587 TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE, 3588 "token family not found in order")); 3589 return GNUNET_SYSERR; 3590 } 3591 3592 /* Check the key_index field from the output. */ 3593 if (output->details.token.key_index >= family->keys_len) 3594 { 3595 /* Also "should never happen", contract was presumably validated on insert */ 3596 GNUNET_break (0); 3597 pay_end (pc, 3598 TALER_MHD_reply_with_error ( 3599 pc->connection, 3600 MHD_HTTP_INTERNAL_SERVER_ERROR, 3601 TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE, 3602 "key index invalid for token family")); 3603 return GNUNET_SYSERR; 3604 } 3605 3606 /* Pick the correct key inside that family. */ 3607 key = &family->keys[output->details.token.key_index]; 3608 3609 /* Fetch the private key from the DB for the merchant instance and 3610 * this particular family/time interval. */ 3611 qs = TALER_MERCHANTDB_lookup_token_family_key ( 3612 TMH_db, 3613 pc->hc->instance->settings.id, 3614 family->slug, 3615 pc->check_contract.contract_terms->timestamp, 3616 pc->check_contract.contract_terms->pay_deadline, 3617 &details); 3618 switch (qs) 3619 { 3620 case GNUNET_DB_STATUS_HARD_ERROR: 3621 case GNUNET_DB_STATUS_SOFT_ERROR: 3622 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 3623 "Database error looking up token-family key for %s\n", 3624 family->slug); 3625 GNUNET_break (0); 3626 pay_end (pc, 3627 TALER_MHD_reply_with_error ( 3628 pc->connection, 3629 MHD_HTTP_INTERNAL_SERVER_ERROR, 3630 TALER_EC_GENERIC_DB_FETCH_FAILED, 3631 NULL)); 3632 return GNUNET_NO; 3633 case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS: 3634 GNUNET_log ( 3635 GNUNET_ERROR_TYPE_ERROR, 3636 "Token-family key for %s not found at [%llu,%llu]\n", 3637 family->slug, 3638 (unsigned long long) 3639 pc->check_contract.contract_terms->timestamp.abs_time.abs_value_us, 3640 (unsigned long long) 3641 pc->check_contract.contract_terms->pay_deadline.abs_time.abs_value_us 3642 ); 3643 GNUNET_break (0); 3644 pay_end (pc, 3645 TALER_MHD_reply_with_error ( 3646 pc->connection, 3647 MHD_HTTP_NOT_FOUND, 3648 TALER_EC_MERCHANT_GENERIC_TOKEN_KEY_UNKNOWN, 3649 family->slug)); 3650 return GNUNET_NO; 3651 3652 case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT: 3653 break; 3654 } 3655 GNUNET_assert (NULL != details.priv.private_key); 3656 GNUNET_free (details.token_family.slug); 3657 GNUNET_free (details.token_family.name); 3658 GNUNET_free (details.token_family.description); 3659 json_decref (details.token_family.description_i18n); 3660 GNUNET_CRYPTO_blind_sign_pub_decref (details.pub.public_key); 3661 GNUNET_free (details.token_family.cipher_spec); 3662 3663 /* Depending on the token family, decide if the token envelope 3664 * is mandatory or optional. (Simplified logic here: adapt as needed.) */ 3665 mandatory = test_tfk_mandatory (details.token_family.kind); 3666 /* Actually sign the number of token envelopes specified in 'count'. 3667 * 'output_index' is the offset into the parse_wallet_data arrays. */ 3668 if (GNUNET_OK != 3669 sign_token_envelopes (pc, 3670 key, 3671 &details.priv, 3672 mandatory, 3673 output_index, 3674 output->details.token.count)) 3675 { 3676 /* sign_token_envelopes() already queued up an error via pay_end() */ 3677 GNUNET_break_op (0); 3678 return GNUNET_NO; 3679 } 3680 GNUNET_CRYPTO_blind_sign_priv_decref (details.priv.private_key); 3681 return GNUNET_OK; 3682 } 3683 3684 3685 /** 3686 * Handle checks for contract output of type TALER_MERCHANT_CONTRACT_OUTPUT_TYPE_DONATION_RECEIPT. 3687 * For now, this does nothing and simply returns #GNUNET_OK. 3688 * 3689 * @param pc context for the pay request 3690 * @param output the contract output describing the donation receipt requirement 3691 * @return #GNUNET_OK on success, 3692 * #GNUNET_NO if an error was already queued 3693 */ 3694 static enum GNUNET_GenericReturnValue 3695 handle_output_donation_receipt ( 3696 struct PayContext *pc, 3697 const struct TALER_MERCHANT_ContractOutput *output) 3698 { 3699 enum GNUNET_GenericReturnValue ret; 3700 3701 ret = DONAU_get_donation_amount_from_bkps ( 3702 pc->parse_wallet_data.donau_keys, 3703 pc->parse_wallet_data.bkps, 3704 pc->parse_wallet_data.num_bkps, 3705 pc->parse_wallet_data.donau.donation_year, 3706 &pc->parse_wallet_data.donation_amount); 3707 switch (ret) 3708 { 3709 case GNUNET_SYSERR: 3710 GNUNET_break (0); 3711 pay_end (pc, 3712 TALER_MHD_reply_with_error ( 3713 pc->connection, 3714 MHD_HTTP_INTERNAL_SERVER_ERROR, 3715 TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE, 3716 NULL)); 3717 return GNUNET_NO; 3718 case GNUNET_NO: 3719 GNUNET_break_op (0); 3720 pay_end (pc, 3721 TALER_MHD_reply_with_error ( 3722 pc->connection, 3723 MHD_HTTP_BAD_REQUEST, 3724 TALER_EC_GENERIC_PARAMETER_MALFORMED, 3725 "inconsistent bkps / donau keys")); 3726 return GNUNET_NO; 3727 case GNUNET_OK: 3728 break; 3729 } 3730 3731 if (GNUNET_OK != 3732 TALER_amount_cmp_currency (&pc->parse_wallet_data.donation_amount, 3733 &output->details.donation_receipt.amount)) 3734 { 3735 GNUNET_break_op (0); 3736 pay_end (pc, 3737 TALER_MHD_reply_with_error ( 3738 pc->connection, 3739 MHD_HTTP_BAD_REQUEST, 3740 TALER_EC_GENERIC_CURRENCY_MISMATCH, 3741 output->details.donation_receipt.amount.currency)); 3742 return GNUNET_NO; 3743 } 3744 3745 if (0 != 3746 TALER_amount_cmp (&pc->parse_wallet_data.donation_amount, 3747 &output->details.donation_receipt.amount)) 3748 { 3749 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 3750 "Wallet amount: %s\n", 3751 TALER_amount2s (&pc->parse_wallet_data.donation_amount)); 3752 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 3753 "Donation receipt amount: %s\n", 3754 TALER_amount2s (&output->details.donation_receipt.amount)); 3755 GNUNET_break_op (0); 3756 pay_end (pc, 3757 TALER_MHD_reply_with_error ( 3758 pc->connection, 3759 MHD_HTTP_CONFLICT, 3760 TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_DONATION_AMOUNT_MISMATCH, 3761 "donation amount mismatch")); 3762 return GNUNET_NO; 3763 } 3764 { 3765 struct TALER_Amount receipts_to_date; 3766 3767 if (0 > 3768 TALER_amount_add (&receipts_to_date, 3769 &pc->parse_wallet_data.charity_receipts_to_date, 3770 &pc->parse_wallet_data.donation_amount)) 3771 { 3772 GNUNET_break (0); 3773 pay_end (pc, 3774 TALER_MHD_reply_with_error (pc->connection, 3775 MHD_HTTP_INTERNAL_SERVER_ERROR, 3776 TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_AMOUNT_OVERFLOW, 3777 "adding donation amount")); 3778 return GNUNET_NO; 3779 } 3780 3781 if (1 == 3782 TALER_amount_cmp (&receipts_to_date, 3783 &pc->parse_wallet_data.charity_max_per_year)) 3784 { 3785 GNUNET_break_op (0); 3786 pay_end (pc, 3787 TALER_MHD_reply_with_error (pc->connection, 3788 MHD_HTTP_CONFLICT, 3789 TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_DONATION_AMOUNT_MISMATCH, 3790 "donation limit exceeded")); 3791 return GNUNET_NO; 3792 } 3793 pc->parse_wallet_data.charity_receipts_to_date = receipts_to_date; 3794 } 3795 return GNUNET_OK; 3796 } 3797 3798 3799 /** 3800 * Count tokens produced by an output. 3801 * 3802 * @param pc pay context 3803 * @param output output to consider 3804 * @returns number of output tokens 3805 */ 3806 static unsigned int 3807 count_output_tokens (const struct PayContext *pc, 3808 const struct TALER_MERCHANT_ContractOutput *output) 3809 { 3810 switch (output->type) 3811 { 3812 case TALER_MERCHANT_CONTRACT_OUTPUT_TYPE_INVALID: 3813 GNUNET_assert (0); 3814 break; 3815 case TALER_MERCHANT_CONTRACT_OUTPUT_TYPE_TOKEN: 3816 return output->details.token.count; 3817 case TALER_MERCHANT_CONTRACT_OUTPUT_TYPE_DONATION_RECEIPT: 3818 return pc->parse_wallet_data.num_bkps; 3819 } 3820 /* Not reached. */ 3821 GNUNET_assert (0); 3822 } 3823 3824 3825 /** 3826 * Validate tokens and token envelopes. First, we check if all tokens listed 3827 * in the 'inputs' array of the selected choice are present in the 'tokens' 3828 * array of the request. Then, we validate the signatures of each provided 3829 * token. 3830 * 3831 * @param[in,out] pc context we use to handle the payment 3832 */ 3833 static void 3834 phase_validate_tokens (struct PayContext *pc) 3835 { 3836 /* We haven't seen a donau output yet. */ 3837 pc->validate_tokens.donau_output_index = -1; 3838 3839 switch (pc->check_contract.contract_terms->version) 3840 { 3841 case TALER_MERCHANT_CONTRACT_VERSION_0: 3842 /* No tokens to validate */ 3843 pc->phase = PP_COMPUTE_MONEY_POTS; 3844 pc->validate_tokens.max_fee 3845 = pc->check_contract.contract_terms->details.v0.max_fee; 3846 pc->validate_tokens.brutto 3847 = pc->check_contract.contract_terms->details.v0.brutto; 3848 break; 3849 case TALER_MERCHANT_CONTRACT_VERSION_1: 3850 { 3851 const struct TALER_MERCHANT_ContractChoice *selected 3852 = &pc->check_contract.contract_terms->details.v1.choices[ 3853 pc->parse_wallet_data.choice_index]; 3854 unsigned int output_off; 3855 unsigned int cnt; 3856 3857 pc->validate_tokens.max_fee = selected->max_fee; 3858 pc->validate_tokens.brutto = selected->amount; 3859 3860 for (unsigned int i = 0; i<selected->inputs_len; i++) 3861 { 3862 const struct TALER_MERCHANT_ContractInput *input 3863 = &selected->inputs[i]; 3864 const struct TALER_MERCHANT_ContractTokenFamily *family; 3865 3866 switch (input->type) 3867 { 3868 case TALER_MERCHANT_CONTRACT_INPUT_TYPE_INVALID: 3869 GNUNET_break (0); 3870 pay_end (pc, 3871 TALER_MHD_reply_with_error ( 3872 pc->connection, 3873 MHD_HTTP_BAD_REQUEST, 3874 TALER_EC_GENERIC_PARAMETER_MALFORMED, 3875 "input token type not valid")); 3876 return; 3877 #if FUTURE 3878 case TALER_MERCHANT_CONTRACT_INPUT_TYPE_COIN: 3879 GNUNET_break (0); 3880 pay_end (pc, 3881 TALER_MHD_reply_with_error ( 3882 pc->connection, 3883 MHD_HTTP_NOT_IMPLEMENTED, 3884 TALER_EC_MERCHANT_GENERIC_FEATURE_NOT_AVAILABLE, 3885 "token type not yet supported")); 3886 return; 3887 #endif 3888 case TALER_MERCHANT_CONTRACT_INPUT_TYPE_TOKEN: 3889 family = find_family (pc, 3890 input->details.token.token_family_slug); 3891 if (NULL == family) 3892 { 3893 /* this should never happen, since the choices and 3894 token families are validated on insert. */ 3895 GNUNET_break (0); 3896 pay_end (pc, 3897 TALER_MHD_reply_with_error ( 3898 pc->connection, 3899 MHD_HTTP_INTERNAL_SERVER_ERROR, 3900 TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE, 3901 "token family not found in order")); 3902 return; 3903 } 3904 if (GNUNET_NO == 3905 find_valid_input_tokens (pc, 3906 family, 3907 i, 3908 input->details.token.count)) 3909 { 3910 /* Error is already scheduled from find_valid_input_token. */ 3911 return; 3912 } 3913 } 3914 } 3915 3916 /* calculate pc->output_tokens_len */ 3917 output_off = 0; 3918 for (unsigned int i = 0; i<selected->outputs_len; i++) 3919 { 3920 const struct TALER_MERCHANT_ContractOutput *output 3921 = &selected->outputs[i]; 3922 3923 switch (output->type) 3924 { 3925 case TALER_MERCHANT_CONTRACT_OUTPUT_TYPE_INVALID: 3926 GNUNET_assert (0); 3927 break; 3928 case TALER_MERCHANT_CONTRACT_OUTPUT_TYPE_TOKEN: 3929 cnt = output->details.token.count; 3930 if (output_off + cnt < output_off) 3931 { 3932 GNUNET_break_op (0); 3933 pay_end (pc, 3934 TALER_MHD_reply_with_error ( 3935 pc->connection, 3936 MHD_HTTP_BAD_REQUEST, 3937 TALER_EC_GENERIC_PARAMETER_MALFORMED, 3938 "output token counter overflow")); 3939 return; 3940 } 3941 output_off += cnt; 3942 break; 3943 case TALER_MERCHANT_CONTRACT_OUTPUT_TYPE_DONATION_RECEIPT: 3944 /* check that this output type appears at most once */ 3945 if (pc->validate_tokens.donau_output_index >= 0) 3946 { 3947 /* This should have been prevented when the 3948 contract was initially created */ 3949 GNUNET_break (0); 3950 pay_end (pc, 3951 TALER_MHD_reply_with_error ( 3952 pc->connection, 3953 MHD_HTTP_INTERNAL_SERVER_ERROR, 3954 TALER_EC_GENERIC_DB_INVARIANT_FAILURE, 3955 "two donau output sets in same contract")); 3956 return; 3957 } 3958 pc->validate_tokens.donau_output_index = i; 3959 if (output_off + pc->parse_wallet_data.num_bkps < output_off) 3960 { 3961 GNUNET_break_op (0); 3962 pay_end (pc, 3963 TALER_MHD_reply_with_error ( 3964 pc->connection, 3965 MHD_HTTP_BAD_REQUEST, 3966 TALER_EC_GENERIC_PARAMETER_MALFORMED, 3967 "output token counter overflow")); 3968 return; 3969 } 3970 output_off += pc->parse_wallet_data.num_bkps; 3971 break; 3972 } 3973 } 3974 3975 3976 pc->output_tokens_len = output_off; 3977 pc->output_tokens 3978 = GNUNET_new_array (pc->output_tokens_len, 3979 struct SignedOutputToken); 3980 3981 /* calculate pc->output_tokens[].output_index */ 3982 output_off = 0; 3983 for (unsigned int i = 0; i<selected->outputs_len; i++) 3984 { 3985 const struct TALER_MERCHANT_ContractOutput *output 3986 = &selected->outputs[i]; 3987 cnt = count_output_tokens (pc, 3988 output); 3989 for (unsigned int j = 0; j<cnt; j++) 3990 pc->output_tokens[output_off + j].output_index = i; 3991 output_off += cnt; 3992 } 3993 3994 /* compute non-donau outputs */ 3995 output_off = 0; 3996 for (unsigned int i = 0; i<selected->outputs_len; i++) 3997 { 3998 const struct TALER_MERCHANT_ContractOutput *output 3999 = &selected->outputs[i]; 4000 4001 switch (output->type) 4002 { 4003 case TALER_MERCHANT_CONTRACT_OUTPUT_TYPE_INVALID: 4004 GNUNET_assert (0); 4005 break; 4006 case TALER_MERCHANT_CONTRACT_OUTPUT_TYPE_TOKEN: 4007 cnt = output->details.token.count; 4008 GNUNET_assert (output_off + cnt 4009 <= pc->output_tokens_len); 4010 if (GNUNET_OK != 4011 handle_output_token (pc, 4012 output, 4013 output_off)) 4014 { 4015 /* Error is already scheduled from handle_output_token. */ 4016 return; 4017 } 4018 output_off += cnt; 4019 break; 4020 case TALER_MERCHANT_CONTRACT_OUTPUT_TYPE_DONATION_RECEIPT: 4021 if ( (0 != pc->parse_wallet_data.num_bkps) && 4022 (GNUNET_OK != 4023 handle_output_donation_receipt (pc, 4024 output)) ) 4025 { 4026 /* Error is already scheduled from handle_output_donation_receipt. */ 4027 return; 4028 } 4029 output_off += pc->parse_wallet_data.num_bkps; 4030 continue; 4031 } /* switch on output token */ 4032 } /* for all output token types */ 4033 } /* case contract v1 */ 4034 break; 4035 } /* switch on contract type */ 4036 4037 for (size_t i = 0; i<pc->parse_pay.coins_cnt; i++) 4038 { 4039 const struct DepositConfirmation *dc = &pc->parse_pay.dc[i]; 4040 4041 if (GNUNET_OK != 4042 TALER_amount_cmp_currency (&dc->cdd.amount, 4043 &pc->validate_tokens.brutto)) 4044 { 4045 GNUNET_break_op (0); 4046 pay_end (pc, 4047 TALER_MHD_reply_with_error ( 4048 pc->connection, 4049 MHD_HTTP_CONFLICT, 4050 TALER_EC_MERCHANT_GENERIC_CURRENCY_MISMATCH, 4051 pc->validate_tokens.brutto.currency)); 4052 return; 4053 } 4054 } 4055 4056 pc->phase = PP_COMPUTE_MONEY_POTS; 4057 } 4058 4059 4060 /** 4061 * Function called with information about a coin that was deposited. 4062 * Checks if this coin is in our list of deposits as well. 4063 * 4064 * @param cls closure with our `struct PayContext *` 4065 * @param deposit_serial which deposit operation is this about 4066 * @param exchange_url URL of the exchange that issued the coin 4067 * @param h_wire hash of merchant's wire details 4068 * @param deposit_timestamp when was the deposit made 4069 * @param amount_with_fee amount the exchange will deposit for this coin 4070 * @param deposit_fee fee the exchange will charge for this coin 4071 * @param coin_pub public key of the coin 4072 */ 4073 static void 4074 deposit_paid_check ( 4075 void *cls, 4076 uint64_t deposit_serial, 4077 const char *exchange_url, 4078 const struct TALER_MerchantWireHashP *h_wire, 4079 struct GNUNET_TIME_Timestamp deposit_timestamp, 4080 const struct TALER_Amount *amount_with_fee, 4081 const struct TALER_Amount *deposit_fee, 4082 const struct TALER_CoinSpendPublicKeyP *coin_pub) 4083 { 4084 struct PayContext *pc = cls; 4085 4086 for (size_t i = 0; i<pc->parse_pay.coins_cnt; i++) 4087 { 4088 struct DepositConfirmation *dci = &pc->parse_pay.dc[i]; 4089 4090 if ( (0 == 4091 GNUNET_memcmp (&dci->cdd.coin_pub, 4092 coin_pub)) && 4093 (0 == 4094 strcmp (dci->exchange_url, 4095 exchange_url)) && 4096 (GNUNET_YES == 4097 TALER_amount_cmp_currency (&dci->cdd.amount, 4098 amount_with_fee)) && 4099 (0 == 4100 TALER_amount_cmp (&dci->cdd.amount, 4101 amount_with_fee)) ) 4102 { 4103 dci->matched_in_db = true; 4104 break; 4105 } 4106 } 4107 } 4108 4109 4110 /** 4111 * Function called with information about a token that was spent. 4112 * FIXME: Replace this with a more specific function for this cb 4113 * 4114 * @param cls closure with `struct PayContext *` 4115 * @param spent_token_serial "serial" of the spent token unused 4116 * @param h_contract_terms hash of the contract terms unused 4117 * @param h_issue_pub hash of the token issue public key unused 4118 * @param use_pub public key of the token 4119 * @param use_sig signature of the token 4120 * @param issue_sig signature of the token issue 4121 */ 4122 static void 4123 input_tokens_paid_check ( 4124 void *cls, 4125 uint64_t spent_token_serial, 4126 const struct TALER_PrivateContractHashP *h_contract_terms, 4127 const struct TALER_TokenIssuePublicKeyHashP *h_issue_pub, 4128 const struct TALER_TokenUsePublicKeyP *use_pub, 4129 const struct TALER_TokenUseSignatureP *use_sig, 4130 const struct TALER_TokenIssueSignature *issue_sig) 4131 { 4132 struct PayContext *pc = cls; 4133 4134 for (size_t i = 0; i<pc->parse_pay.tokens_cnt; i++) 4135 { 4136 struct TokenUseConfirmation *tuc = &pc->parse_pay.tokens[i]; 4137 4138 if ( (0 == 4139 GNUNET_memcmp (&tuc->pub, 4140 use_pub)) && 4141 (0 == 4142 GNUNET_memcmp (&tuc->sig, 4143 use_sig)) && 4144 (0 == 4145 GNUNET_memcmp (&tuc->unblinded_sig, 4146 issue_sig)) ) 4147 { 4148 tuc->found_in_db = true; 4149 break; 4150 } 4151 } 4152 } 4153 4154 4155 /** 4156 * Small helper function to append an output token signature from db 4157 * 4158 * @param cls closure with `struct PayContext *` 4159 * @param h_issue hash of the token 4160 * @param sig signature of the token 4161 */ 4162 static void 4163 append_output_token_sig (void *cls, 4164 struct GNUNET_HashCode *h_issue, 4165 struct GNUNET_CRYPTO_BlindedSignature *sig) 4166 { 4167 struct PayContext *pc = cls; 4168 struct TALER_MERCHANT_ContractChoice *choice; 4169 const struct TALER_MERCHANT_ContractOutput *output; 4170 struct SignedOutputToken out; 4171 unsigned int cnt; 4172 4173 memset (&out, 4174 0, 4175 sizeof (out)); 4176 GNUNET_assert (TALER_MERCHANT_CONTRACT_VERSION_1 == 4177 pc->check_contract.contract_terms->version); 4178 choice = &pc->check_contract.contract_terms->details.v1 4179 .choices[pc->parse_wallet_data.choice_index]; 4180 output = &choice->outputs[pc->output_index_gen]; 4181 cnt = count_output_tokens (pc, 4182 output); 4183 out.output_index = pc->output_index_gen; 4184 out.h_issue.hash = *h_issue; 4185 out.sig.signature = sig; 4186 GNUNET_CRYPTO_blind_sig_incref (sig); 4187 GNUNET_array_append (pc->output_tokens, 4188 pc->output_tokens_len, 4189 out); 4190 /* Go to next output once we've output all tokens for the current one. */ 4191 pc->output_token_cnt++; 4192 if (pc->output_token_cnt >= cnt) 4193 { 4194 pc->output_token_cnt = 0; 4195 pc->output_index_gen++; 4196 } 4197 } 4198 4199 4200 /** 4201 * Handle case where contract was already paid. Either decides 4202 * the payment is idempotent, or refunds the excess payment. 4203 * 4204 * @param[in,out] pc context we use to handle the payment 4205 */ 4206 static void 4207 phase_contract_paid (struct PayContext *pc) 4208 { 4209 json_t *refunds; 4210 bool unmatched = false; 4211 4212 { 4213 enum GNUNET_DB_QueryStatus qs; 4214 4215 qs = TALER_MERCHANTDB_lookup_deposits_by_order (TMH_db, 4216 pc->check_contract.order_serial, 4217 &deposit_paid_check, 4218 pc); 4219 /* Since orders with choices can have a price of zero, 4220 0 is also a valid query state */ 4221 if (qs < 0) 4222 { 4223 GNUNET_break (0); 4224 pay_end (pc, 4225 TALER_MHD_reply_with_error ( 4226 pc->connection, 4227 MHD_HTTP_INTERNAL_SERVER_ERROR, 4228 TALER_EC_GENERIC_DB_FETCH_FAILED, 4229 "lookup_deposits_by_order")); 4230 return; 4231 } 4232 } 4233 for (size_t i = 0; 4234 i<pc->parse_pay.coins_cnt && ! unmatched; 4235 i++) 4236 { 4237 struct DepositConfirmation *dci = &pc->parse_pay.dc[i]; 4238 4239 if (! dci->matched_in_db) 4240 unmatched = true; 4241 } 4242 /* Check if provided input tokens match token in the database */ 4243 { 4244 enum GNUNET_DB_QueryStatus qs; 4245 4246 /* FIXME-Optimization: Maybe use h_contract instead of order_serial here? */ 4247 qs = TALER_MERCHANTDB_lookup_spent_tokens_by_order (TMH_db, 4248 pc->check_contract.order_serial, 4249 &input_tokens_paid_check, 4250 pc); 4251 4252 if (qs < 0) 4253 { 4254 GNUNET_break (0); 4255 pay_end (pc, 4256 TALER_MHD_reply_with_error ( 4257 pc->connection, 4258 MHD_HTTP_INTERNAL_SERVER_ERROR, 4259 TALER_EC_GENERIC_DB_FETCH_FAILED, 4260 "lookup_spent_tokens_by_order")); 4261 return; 4262 } 4263 } 4264 for (size_t i = 0; i<pc->parse_pay.tokens_cnt && ! unmatched; i++) 4265 { 4266 struct TokenUseConfirmation *tuc = &pc->parse_pay.tokens[i]; 4267 4268 if (! tuc->found_in_db) 4269 unmatched = true; 4270 } 4271 4272 /* In this part we are fetching token_sigs related output */ 4273 if (! unmatched) 4274 { 4275 /* Everything fine, idempotent request, generate response immediately */ 4276 enum GNUNET_DB_QueryStatus qs; 4277 4278 pc->output_index_gen = 0; 4279 qs = TALER_MERCHANTDB_select_order_blinded_sigs ( 4280 TMH_db, 4281 pc->order_id, 4282 &append_output_token_sig, 4283 pc); 4284 if (0 > qs) 4285 { 4286 GNUNET_break (0); 4287 pay_end (pc, 4288 TALER_MHD_reply_with_error ( 4289 pc->connection, 4290 MHD_HTTP_INTERNAL_SERVER_ERROR, 4291 TALER_EC_GENERIC_DB_FETCH_FAILED, 4292 "select_order_blinded_sigs")); 4293 return; 4294 } 4295 4296 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 4297 "Idempotent pay request for order `%s', signing again\n", 4298 pc->order_id); 4299 pc->phase = PP_SUCCESS_RESPONSE; 4300 return; 4301 } 4302 /* Conflict, double-payment detected! */ 4303 /* FIXME-#8674: What should we do with input tokens? 4304 Currently there is no refund for tokens. */ 4305 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 4306 "Client attempted to pay extra for already paid order `%s'\n", 4307 pc->order_id); 4308 refunds = json_array (); 4309 GNUNET_assert (NULL != refunds); 4310 for (size_t i = 0; i<pc->parse_pay.coins_cnt; i++) 4311 { 4312 struct DepositConfirmation *dci = &pc->parse_pay.dc[i]; 4313 struct TALER_MerchantSignatureP merchant_sig; 4314 4315 if (dci->matched_in_db) 4316 continue; 4317 TALER_merchant_refund_sign (&dci->cdd.coin_pub, 4318 &pc->check_contract.h_contract_terms, 4319 0, /* rtransaction id */ 4320 &dci->cdd.amount, 4321 &pc->hc->instance->merchant_priv, 4322 &merchant_sig); 4323 GNUNET_assert ( 4324 0 == 4325 json_array_append_new ( 4326 refunds, 4327 GNUNET_JSON_PACK ( 4328 GNUNET_JSON_pack_data_auto ( 4329 "coin_pub", 4330 &dci->cdd.coin_pub), 4331 GNUNET_JSON_pack_data_auto ( 4332 "merchant_sig", 4333 &merchant_sig), 4334 TALER_JSON_pack_amount ("amount", 4335 &dci->cdd.amount), 4336 GNUNET_JSON_pack_uint64 ("rtransaction_id", 4337 0)))); 4338 } 4339 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 4340 "Generating JSON response with code %d\n", 4341 (int) TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_ALREADY_PAID); 4342 pay_end (pc, 4343 TALER_MHD_REPLY_JSON_PACK ( 4344 pc->connection, 4345 MHD_HTTP_CONFLICT, 4346 TALER_MHD_PACK_EC ( 4347 TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_ALREADY_PAID), 4348 GNUNET_JSON_pack_array_steal ("refunds", 4349 refunds))); 4350 } 4351 4352 4353 /** 4354 * Check the database state for the given order. 4355 * Schedules an error response in the connection on failure. 4356 * 4357 * @param[in,out] pc context we use to handle the payment 4358 */ 4359 static void 4360 phase_check_contract (struct PayContext *pc) 4361 { 4362 /* obtain contract terms */ 4363 enum GNUNET_DB_QueryStatus qs; 4364 bool paid = false; 4365 4366 if (NULL != pc->check_contract.contract_terms_json) 4367 { 4368 json_decref (pc->check_contract.contract_terms_json); 4369 pc->check_contract.contract_terms_json = NULL; 4370 } 4371 if (NULL != pc->check_contract.contract_terms) 4372 { 4373 TALER_MERCHANT_contract_free (pc->check_contract.contract_terms); 4374 pc->check_contract.contract_terms = NULL; 4375 } 4376 qs = TALER_MERCHANTDB_lookup_contract_terms2 (TMH_db, 4377 pc->hc->instance->settings.id, 4378 pc->order_id, 4379 &pc->check_contract.contract_terms_json, 4380 &pc->check_contract.order_serial, 4381 &paid, 4382 NULL, 4383 &pc->check_contract.pos_key, 4384 &pc->check_contract.pos_alg); 4385 if (0 > qs) 4386 { 4387 /* single, read-only SQL statements should never cause 4388 serialization problems */ 4389 GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR != qs); 4390 /* Always report on hard error to enable diagnostics */ 4391 GNUNET_break (GNUNET_DB_STATUS_HARD_ERROR == qs); 4392 pay_end (pc, 4393 TALER_MHD_reply_with_error ( 4394 pc->connection, 4395 MHD_HTTP_INTERNAL_SERVER_ERROR, 4396 TALER_EC_GENERIC_DB_FETCH_FAILED, 4397 "contract terms")); 4398 return; 4399 } 4400 if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs) 4401 { 4402 pay_end (pc, 4403 TALER_MHD_reply_with_error ( 4404 pc->connection, 4405 MHD_HTTP_NOT_FOUND, 4406 TALER_EC_MERCHANT_GENERIC_ORDER_UNKNOWN, 4407 pc->order_id)); 4408 return; 4409 } 4410 /* hash contract (needed later) */ 4411 #if DEBUG 4412 json_dumpf (pc->check_contract.contract_terms_json, 4413 stderr, 4414 JSON_INDENT (2)); 4415 #endif 4416 if (GNUNET_OK != 4417 TALER_JSON_contract_hash (pc->check_contract.contract_terms_json, 4418 &pc->check_contract.h_contract_terms)) 4419 { 4420 GNUNET_break (0); 4421 pay_end (pc, 4422 TALER_MHD_reply_with_error ( 4423 pc->connection, 4424 MHD_HTTP_INTERNAL_SERVER_ERROR, 4425 TALER_EC_GENERIC_FAILED_COMPUTE_JSON_HASH, 4426 NULL)); 4427 return; 4428 } 4429 4430 /* Parse the contract terms even for paid orders, 4431 as later phases need it. */ 4432 4433 pc->check_contract.contract_terms = TALER_MERCHANT_contract_parse ( 4434 pc->check_contract.contract_terms_json, 4435 true); 4436 4437 if (NULL == pc->check_contract.contract_terms) 4438 { 4439 /* invalid contract */ 4440 GNUNET_break (0); 4441 pay_end (pc, 4442 TALER_MHD_reply_with_error ( 4443 pc->connection, 4444 MHD_HTTP_INTERNAL_SERVER_ERROR, 4445 TALER_EC_MERCHANT_GENERIC_DB_CONTRACT_CONTENT_INVALID, 4446 pc->order_id)); 4447 return; 4448 } 4449 4450 if (paid) 4451 { 4452 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 4453 "Order `%s' paid, checking for double-payment\n", 4454 pc->order_id); 4455 pc->phase = PP_CONTRACT_PAID; 4456 return; 4457 } 4458 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 4459 "Handling payment for order `%s' with contract hash `%s'\n", 4460 pc->order_id, 4461 GNUNET_h2s (&pc->check_contract.h_contract_terms.hash)); 4462 4463 /* Check fundamentals */ 4464 { 4465 switch (pc->check_contract.contract_terms->version) 4466 { 4467 case TALER_MERCHANT_CONTRACT_VERSION_0: 4468 { 4469 if (pc->parse_wallet_data.choice_index > 0) 4470 { 4471 GNUNET_break (0); 4472 pay_end (pc, 4473 TALER_MHD_reply_with_error ( 4474 pc->connection, 4475 MHD_HTTP_BAD_REQUEST, 4476 TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_CHOICE_INDEX_OUT_OF_BOUNDS, 4477 "contract terms v0 has no choices")); 4478 return; 4479 } 4480 } 4481 break; 4482 case TALER_MERCHANT_CONTRACT_VERSION_1: 4483 { 4484 if (pc->parse_wallet_data.choice_index < 0) 4485 { 4486 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 4487 "Order `%s' has non-empty choices array but" 4488 "request is missing 'choice_index' field\n", 4489 pc->order_id); 4490 GNUNET_break (0); 4491 pay_end (pc, 4492 TALER_MHD_reply_with_error ( 4493 pc->connection, 4494 MHD_HTTP_BAD_REQUEST, 4495 TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_CHOICE_INDEX_MISSING, 4496 NULL)); 4497 return; 4498 } 4499 if (pc->parse_wallet_data.choice_index >= 4500 pc->check_contract.contract_terms->details.v1.choices_len) 4501 { 4502 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 4503 "Order `%s' has choices array with %u elements but " 4504 "request has 'choice_index' field with value %d\n", 4505 pc->order_id, 4506 pc->check_contract.contract_terms->details.v1.choices_len, 4507 pc->parse_wallet_data.choice_index); 4508 GNUNET_break (0); 4509 pay_end (pc, 4510 TALER_MHD_reply_with_error ( 4511 pc->connection, 4512 MHD_HTTP_BAD_REQUEST, 4513 TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_CHOICE_INDEX_OUT_OF_BOUNDS, 4514 NULL)); 4515 return; 4516 } 4517 } 4518 break; 4519 default: 4520 GNUNET_break (0); 4521 pay_end (pc, 4522 TALER_MHD_reply_with_error ( 4523 pc->connection, 4524 MHD_HTTP_INTERNAL_SERVER_ERROR, 4525 TALER_EC_GENERIC_DB_FETCH_FAILED, 4526 "contract 'version' in database not supported by this backend") 4527 ); 4528 return; 4529 } 4530 } 4531 4532 if (GNUNET_TIME_timestamp_cmp (pc->check_contract.contract_terms-> 4533 wire_deadline, 4534 <, 4535 pc->check_contract.contract_terms-> 4536 refund_deadline)) 4537 { 4538 /* This should already have been checked when creating the order! */ 4539 GNUNET_break (0); 4540 pay_end (pc, 4541 TALER_MHD_reply_with_error ( 4542 pc->connection, 4543 MHD_HTTP_INTERNAL_SERVER_ERROR, 4544 TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_REFUND_DEADLINE_PAST_WIRE_TRANSFER_DEADLINE, 4545 NULL)); 4546 return; 4547 } 4548 if (GNUNET_TIME_absolute_is_past (pc->check_contract.contract_terms-> 4549 pay_deadline.abs_time)) 4550 { 4551 /* too late */ 4552 pay_end (pc, 4553 TALER_MHD_reply_with_error ( 4554 pc->connection, 4555 MHD_HTTP_GONE, 4556 TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_OFFER_EXPIRED, 4557 NULL)); 4558 return; 4559 } 4560 4561 /* Make sure wire method (still) exists for this instance */ 4562 { 4563 struct TMH_WireMethod *wm; 4564 4565 wm = pc->hc->instance->wm_head; 4566 while (0 != GNUNET_memcmp (&pc->check_contract.contract_terms->h_wire, 4567 &wm->h_wire)) 4568 wm = wm->next; 4569 if (NULL == wm) 4570 { 4571 GNUNET_break (0); 4572 pay_end (pc, 4573 TALER_MHD_reply_with_error ( 4574 pc->connection, 4575 MHD_HTTP_INTERNAL_SERVER_ERROR, 4576 TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_WIRE_HASH_UNKNOWN, 4577 NULL)); 4578 return; 4579 } 4580 pc->check_contract.wm = wm; 4581 } 4582 pc->phase = PP_VALIDATE_TOKENS; 4583 } 4584 4585 4586 /** 4587 * Try to parse the wallet_data object of the pay request into 4588 * the given context. Schedules an error response in the connection 4589 * on failure. 4590 * 4591 * @param[in,out] pc context we use to handle the payment 4592 */ 4593 static void 4594 phase_parse_wallet_data (struct PayContext *pc) 4595 { 4596 const json_t *tokens_evs; 4597 const json_t *donau_obj; 4598 4599 struct GNUNET_JSON_Specification spec[] = { 4600 GNUNET_JSON_spec_mark_optional ( 4601 GNUNET_JSON_spec_int16 ("choice_index", 4602 &pc->parse_wallet_data.choice_index), 4603 NULL), 4604 GNUNET_JSON_spec_mark_optional ( 4605 GNUNET_JSON_spec_array_const ("tokens_evs", 4606 &tokens_evs), 4607 NULL), 4608 GNUNET_JSON_spec_mark_optional ( 4609 GNUNET_JSON_spec_object_const ("donau", 4610 &donau_obj), 4611 NULL), 4612 GNUNET_JSON_spec_end () 4613 }; 4614 4615 pc->parse_wallet_data.choice_index = -1; 4616 if (NULL == pc->parse_pay.wallet_data) 4617 { 4618 pc->phase = PP_CHECK_CONTRACT; 4619 return; 4620 } 4621 { 4622 enum GNUNET_GenericReturnValue res; 4623 4624 res = TALER_MHD_parse_json_data (pc->connection, 4625 pc->parse_pay.wallet_data, 4626 spec); 4627 if (GNUNET_YES != res) 4628 { 4629 GNUNET_break_op (0); 4630 pay_end (pc, 4631 (GNUNET_NO == res) 4632 ? MHD_YES 4633 : MHD_NO); 4634 return; 4635 } 4636 } 4637 4638 pc->parse_wallet_data.token_envelopes_cnt 4639 = json_array_size (tokens_evs); 4640 if (pc->parse_wallet_data.token_envelopes_cnt > 4641 MAX_TOKEN_ALLOWED_OUTPUTS) 4642 { 4643 GNUNET_break_op (0); 4644 pay_end (pc, 4645 TALER_MHD_reply_with_error ( 4646 pc->connection, 4647 MHD_HTTP_BAD_REQUEST, 4648 TALER_EC_GENERIC_PARAMETER_MALFORMED, 4649 "'tokens_evs' array too long")); 4650 return; 4651 } 4652 pc->parse_wallet_data.token_envelopes 4653 = GNUNET_new_array (pc->parse_wallet_data.token_envelopes_cnt, 4654 struct TokenEnvelope); 4655 4656 { 4657 unsigned int tokens_ev_index; 4658 json_t *token_ev; 4659 4660 json_array_foreach (tokens_evs, 4661 tokens_ev_index, 4662 token_ev) 4663 { 4664 struct TokenEnvelope *ev 4665 = &pc->parse_wallet_data.token_envelopes[tokens_ev_index]; 4666 struct GNUNET_JSON_Specification ispec[] = { 4667 TALER_JSON_spec_token_envelope (NULL, 4668 &ev->blinded_token), 4669 GNUNET_JSON_spec_end () 4670 }; 4671 enum GNUNET_GenericReturnValue res; 4672 4673 if (json_is_null (token_ev)) 4674 continue; 4675 res = TALER_MHD_parse_json_data (pc->connection, 4676 token_ev, 4677 ispec); 4678 if (GNUNET_YES != res) 4679 { 4680 GNUNET_break_op (0); 4681 pay_end (pc, 4682 (GNUNET_NO == res) 4683 ? MHD_YES 4684 : MHD_NO); 4685 return; 4686 } 4687 4688 for (unsigned int j = 0; j<tokens_ev_index; j++) 4689 { 4690 if (0 == 4691 GNUNET_memcmp (ev->blinded_token.blinded_pub, 4692 pc->parse_wallet_data.token_envelopes[j]. 4693 blinded_token.blinded_pub)) 4694 { 4695 GNUNET_break_op (0); 4696 pay_end (pc, 4697 TALER_MHD_reply_with_error ( 4698 pc->connection, 4699 MHD_HTTP_BAD_REQUEST, 4700 TALER_EC_GENERIC_PARAMETER_MALFORMED, 4701 "duplicate token envelope in list")); 4702 return; 4703 } 4704 } 4705 } 4706 } 4707 4708 if (NULL != donau_obj) 4709 { 4710 const char *donau_url_tmp; 4711 const json_t *budikeypairs; 4712 json_t *donau_keys_json; 4713 4714 /* Fetching and checking that all 3 are present in some way */ 4715 struct GNUNET_JSON_Specification dspec[] = { 4716 GNUNET_JSON_spec_string ("url", 4717 &donau_url_tmp), 4718 GNUNET_JSON_spec_uint64 ("year", 4719 &pc->parse_wallet_data.donau.donation_year), 4720 GNUNET_JSON_spec_array_const ("budikeypairs", 4721 &budikeypairs), 4722 GNUNET_JSON_spec_end () 4723 }; 4724 enum GNUNET_GenericReturnValue res; 4725 4726 res = TALER_MHD_parse_json_data (pc->connection, 4727 donau_obj, 4728 dspec); 4729 if (GNUNET_YES != res) 4730 { 4731 GNUNET_break_op (0); 4732 pay_end (pc, 4733 (GNUNET_NO == res) 4734 ? MHD_YES 4735 : MHD_NO); 4736 return; 4737 } 4738 4739 /* Check if the needed data is present for the given donau URL */ 4740 { 4741 enum GNUNET_DB_QueryStatus qs; 4742 4743 qs = TALER_MERCHANTDB_lookup_order_charity ( 4744 TMH_db, 4745 pc->hc->instance->settings.id, 4746 donau_url_tmp, 4747 &pc->parse_wallet_data.charity_id, 4748 &pc->parse_wallet_data.charity_priv, 4749 &pc->parse_wallet_data.charity_max_per_year, 4750 &pc->parse_wallet_data.charity_receipts_to_date, 4751 &donau_keys_json, 4752 &pc->parse_wallet_data.donau_instance_serial); 4753 4754 switch (qs) 4755 { 4756 case GNUNET_DB_STATUS_HARD_ERROR: 4757 case GNUNET_DB_STATUS_SOFT_ERROR: 4758 TALER_MERCHANTDB_rollback (TMH_db); 4759 pay_end (pc, 4760 TALER_MHD_reply_with_error ( 4761 pc->connection, 4762 MHD_HTTP_INTERNAL_SERVER_ERROR, 4763 TALER_EC_GENERIC_DB_FETCH_FAILED, 4764 "lookup_order_charity")); 4765 return; 4766 case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS: 4767 TALER_MERCHANTDB_rollback (TMH_db); 4768 pay_end (pc, 4769 TALER_MHD_reply_with_error ( 4770 pc->connection, 4771 MHD_HTTP_NOT_FOUND, 4772 TALER_EC_MERCHANT_GENERIC_DONAU_CHARITY_UNKNOWN, 4773 donau_url_tmp)); 4774 return; 4775 case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT: 4776 pc->parse_wallet_data.donau.donau_url = 4777 GNUNET_strdup (donau_url_tmp); 4778 break; 4779 } 4780 } 4781 4782 { 4783 pc->parse_wallet_data.donau_keys = 4784 DONAU_keys_from_json (donau_keys_json); 4785 json_decref (donau_keys_json); 4786 if (NULL == pc->parse_wallet_data.donau_keys) 4787 { 4788 GNUNET_break_op (0); 4789 pay_end (pc, 4790 TALER_MHD_reply_with_error (pc->connection, 4791 MHD_HTTP_BAD_REQUEST, 4792 TALER_EC_GENERIC_PARAMETER_MALFORMED, 4793 "Invalid donau_keys")); 4794 return; 4795 } 4796 } 4797 4798 /* Stage to parse the budikeypairs from json to struct */ 4799 if (0 != json_array_size (budikeypairs)) 4800 { 4801 size_t num_bkps = json_array_size (budikeypairs); 4802 struct DONAU_BlindedUniqueDonorIdentifierKeyPair *bkps = 4803 GNUNET_new_array (num_bkps, 4804 struct DONAU_BlindedUniqueDonorIdentifierKeyPair); 4805 4806 /* Change to json for each*/ 4807 for (size_t i = 0; i < num_bkps; i++) 4808 { 4809 const json_t *bkp_obj = json_array_get (budikeypairs, 4810 i); 4811 if (GNUNET_SYSERR == 4812 merchant_parse_json_bkp (&bkps[i], 4813 bkp_obj)) 4814 { 4815 GNUNET_break_op (0); 4816 for (size_t j = 0; j < i; j++) 4817 GNUNET_CRYPTO_blinded_message_decref ( 4818 bkps[j].blinded_udi.blinded_message); 4819 GNUNET_free (bkps); 4820 pay_end (pc, 4821 TALER_MHD_reply_with_error (pc->connection, 4822 MHD_HTTP_BAD_REQUEST, 4823 TALER_EC_GENERIC_PARAMETER_MALFORMED, 4824 "Failed to parse budikeypairs")); 4825 return; 4826 } 4827 } 4828 4829 pc->parse_wallet_data.num_bkps = num_bkps; 4830 pc->parse_wallet_data.bkps = bkps; 4831 } 4832 } 4833 TALER_json_hash (pc->parse_pay.wallet_data, 4834 &pc->parse_wallet_data.h_wallet_data); 4835 4836 pc->phase = PP_CHECK_CONTRACT; 4837 } 4838 4839 4840 /** 4841 * Try to parse the pay request into the given pay context. 4842 * Schedules an error response in the connection on failure. 4843 * 4844 * @param[in,out] pc context we use to handle the payment 4845 */ 4846 static void 4847 phase_parse_pay (struct PayContext *pc) 4848 { 4849 const char *session_id = NULL; 4850 const json_t *coins; 4851 const json_t *tokens; 4852 struct GNUNET_JSON_Specification spec[] = { 4853 GNUNET_JSON_spec_array_const ("coins", 4854 &coins), 4855 GNUNET_JSON_spec_mark_optional ( 4856 GNUNET_JSON_spec_string ("session_id", 4857 &session_id), 4858 NULL), 4859 GNUNET_JSON_spec_mark_optional ( 4860 GNUNET_JSON_spec_object_const ("wallet_data", 4861 &pc->parse_pay.wallet_data), 4862 NULL), 4863 GNUNET_JSON_spec_mark_optional ( 4864 GNUNET_JSON_spec_array_const ("tokens", 4865 &tokens), 4866 NULL), 4867 GNUNET_JSON_spec_end () 4868 }; 4869 4870 #if DEBUG 4871 { 4872 char *dump = json_dumps (pc->hc->request_body, 4873 JSON_INDENT (2) 4874 | JSON_ENCODE_ANY 4875 | JSON_SORT_KEYS); 4876 4877 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 4878 "POST /orders/%s/pay – request body follows:\n%s\n", 4879 pc->order_id, 4880 dump); 4881 4882 free (dump); 4883 4884 } 4885 #endif /* DEBUG */ 4886 4887 GNUNET_assert (PP_PARSE_PAY == pc->phase); 4888 { 4889 enum GNUNET_GenericReturnValue res; 4890 4891 res = TALER_MHD_parse_json_data (pc->connection, 4892 pc->hc->request_body, 4893 spec); 4894 if (GNUNET_YES != res) 4895 { 4896 GNUNET_break_op (0); 4897 pay_end (pc, 4898 (GNUNET_NO == res) 4899 ? MHD_YES 4900 : MHD_NO); 4901 return; 4902 } 4903 } 4904 4905 /* copy session ID (if set) */ 4906 if (NULL != session_id) 4907 { 4908 pc->parse_pay.session_id = GNUNET_strdup (session_id); 4909 } 4910 else 4911 { 4912 /* use empty string as default if client didn't specify it */ 4913 pc->parse_pay.session_id = GNUNET_strdup (""); 4914 } 4915 4916 pc->parse_pay.coins_cnt = json_array_size (coins); 4917 if (pc->parse_pay.coins_cnt > MAX_COIN_ALLOWED_COINS) 4918 { 4919 GNUNET_break_op (0); 4920 pay_end (pc, 4921 TALER_MHD_reply_with_error ( 4922 pc->connection, 4923 MHD_HTTP_BAD_REQUEST, 4924 TALER_EC_GENERIC_PARAMETER_MALFORMED, 4925 "'coins' array too long")); 4926 return; 4927 } 4928 /* note: 1 coin = 1 deposit confirmation expected */ 4929 pc->parse_pay.dc = GNUNET_new_array (pc->parse_pay.coins_cnt, 4930 struct DepositConfirmation); 4931 4932 /* This loop populates the array 'dc' in 'pc' */ 4933 { 4934 unsigned int coins_index; 4935 json_t *coin; 4936 4937 json_array_foreach (coins, coins_index, coin) 4938 { 4939 struct DepositConfirmation *dc = &pc->parse_pay.dc[coins_index]; 4940 const char *exchange_url; 4941 struct GNUNET_JSON_Specification ispec[] = { 4942 GNUNET_JSON_spec_fixed_auto ("coin_sig", 4943 &dc->cdd.coin_sig), 4944 GNUNET_JSON_spec_fixed_auto ("coin_pub", 4945 &dc->cdd.coin_pub), 4946 TALER_JSON_spec_denom_sig ("ub_sig", 4947 &dc->cdd.denom_sig), 4948 GNUNET_JSON_spec_fixed_auto ("h_denom", 4949 &dc->cdd.h_denom_pub), 4950 TALER_JSON_spec_amount_any ("contribution", 4951 &dc->cdd.amount), 4952 TALER_JSON_spec_web_url ("exchange_url", 4953 &exchange_url), 4954 /* if a minimum age was required, the minimum_age_sig and 4955 * age_commitment must be provided */ 4956 GNUNET_JSON_spec_mark_optional ( 4957 GNUNET_JSON_spec_fixed_auto ("minimum_age_sig", 4958 &dc->minimum_age_sig), 4959 &dc->no_minimum_age_sig), 4960 GNUNET_JSON_spec_mark_optional ( 4961 TALER_JSON_spec_age_commitment ("age_commitment", 4962 &dc->age_commitment), 4963 &dc->no_age_commitment), 4964 /* if minimum age was not required, but coin with age restriction set 4965 * was used, h_age_commitment must be provided. */ 4966 GNUNET_JSON_spec_mark_optional ( 4967 GNUNET_JSON_spec_fixed_auto ("h_age_commitment", 4968 &dc->cdd.h_age_commitment), 4969 &dc->no_h_age_commitment), 4970 GNUNET_JSON_spec_end () 4971 }; 4972 enum GNUNET_GenericReturnValue res; 4973 struct ExchangeGroup *eg = NULL; 4974 4975 res = TALER_MHD_parse_json_data (pc->connection, 4976 coin, 4977 ispec); 4978 if (GNUNET_YES != res) 4979 { 4980 GNUNET_break_op (0); 4981 pay_end (pc, 4982 (GNUNET_NO == res) 4983 ? MHD_YES 4984 : MHD_NO); 4985 return; 4986 } 4987 for (unsigned int j = 0; j<coins_index; j++) 4988 { 4989 if (0 == 4990 GNUNET_memcmp (&dc->cdd.coin_pub, 4991 &pc->parse_pay.dc[j].cdd.coin_pub)) 4992 { 4993 GNUNET_break_op (0); 4994 pay_end (pc, 4995 TALER_MHD_reply_with_error (pc->connection, 4996 MHD_HTTP_BAD_REQUEST, 4997 TALER_EC_GENERIC_PARAMETER_MALFORMED, 4998 "duplicate coin in list")); 4999 return; 5000 } 5001 } 5002 5003 dc->exchange_url = GNUNET_strdup (exchange_url); 5004 dc->index = coins_index; 5005 dc->pc = pc; 5006 5007 /* Check the consistency of the (potential) age restriction 5008 * information. */ 5009 if (dc->no_age_commitment != dc->no_minimum_age_sig) 5010 { 5011 GNUNET_break_op (0); 5012 pay_end (pc, 5013 TALER_MHD_reply_with_error ( 5014 pc->connection, 5015 MHD_HTTP_BAD_REQUEST, 5016 TALER_EC_GENERIC_PARAMETER_MALFORMED, 5017 "inconsistent: 'age_commitment' vs. 'minimum_age_sig'" 5018 )); 5019 return; 5020 } 5021 5022 /* Setup exchange group */ 5023 for (unsigned int i = 0; i<pc->parse_pay.num_exchanges; i++) 5024 { 5025 if (0 == 5026 strcmp (pc->parse_pay.egs[i]->exchange_url, 5027 exchange_url)) 5028 { 5029 eg = pc->parse_pay.egs[i]; 5030 break; 5031 } 5032 } 5033 if (NULL == eg) 5034 { 5035 eg = GNUNET_new (struct ExchangeGroup); 5036 eg->pc = pc; 5037 eg->exchange_url = dc->exchange_url; 5038 eg->total = dc->cdd.amount; 5039 GNUNET_array_append (pc->parse_pay.egs, 5040 pc->parse_pay.num_exchanges, 5041 eg); 5042 } 5043 else 5044 { 5045 if (0 > 5046 TALER_amount_add (&eg->total, 5047 &eg->total, 5048 &dc->cdd.amount)) 5049 { 5050 GNUNET_break_op (0); 5051 pay_end (pc, 5052 TALER_MHD_reply_with_error ( 5053 pc->connection, 5054 MHD_HTTP_INTERNAL_SERVER_ERROR, 5055 TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_AMOUNT_OVERFLOW, 5056 "Overflow adding up amounts")); 5057 return; 5058 } 5059 } 5060 } 5061 } 5062 5063 pc->parse_pay.tokens_cnt = json_array_size (tokens); 5064 if (pc->parse_pay.tokens_cnt > MAX_TOKEN_ALLOWED_INPUTS) 5065 { 5066 GNUNET_break_op (0); 5067 pay_end (pc, 5068 TALER_MHD_reply_with_error ( 5069 pc->connection, 5070 MHD_HTTP_BAD_REQUEST, 5071 TALER_EC_GENERIC_PARAMETER_MALFORMED, 5072 "'tokens' array too long")); 5073 return; 5074 } 5075 5076 pc->parse_pay.tokens = GNUNET_new_array (pc->parse_pay.tokens_cnt, 5077 struct TokenUseConfirmation); 5078 5079 /* This loop populates the array 'tokens' in 'pc' */ 5080 { 5081 unsigned int tokens_index; 5082 json_t *token; 5083 5084 json_array_foreach (tokens, tokens_index, token) 5085 { 5086 struct TokenUseConfirmation *tuc = &pc->parse_pay.tokens[tokens_index]; 5087 struct GNUNET_JSON_Specification ispec[] = { 5088 GNUNET_JSON_spec_fixed_auto ("token_sig", 5089 &tuc->sig), 5090 GNUNET_JSON_spec_fixed_auto ("token_pub", 5091 &tuc->pub), 5092 GNUNET_JSON_spec_fixed_auto ("h_issue", 5093 &tuc->h_issue), 5094 TALER_JSON_spec_token_issue_sig ("ub_sig", 5095 &tuc->unblinded_sig), 5096 GNUNET_JSON_spec_end () 5097 }; 5098 enum GNUNET_GenericReturnValue res; 5099 5100 res = TALER_MHD_parse_json_data (pc->connection, 5101 token, 5102 ispec); 5103 if (GNUNET_YES != res) 5104 { 5105 GNUNET_break_op (0); 5106 pay_end (pc, 5107 (GNUNET_NO == res) 5108 ? MHD_YES 5109 : MHD_NO); 5110 return; 5111 } 5112 5113 for (unsigned int j = 0; j<tokens_index; j++) 5114 { 5115 if (0 == 5116 GNUNET_memcmp (&tuc->pub, 5117 &pc->parse_pay.tokens[j].pub)) 5118 { 5119 GNUNET_break_op (0); 5120 pay_end (pc, 5121 TALER_MHD_reply_with_error (pc->connection, 5122 MHD_HTTP_BAD_REQUEST, 5123 TALER_EC_GENERIC_PARAMETER_MALFORMED, 5124 "duplicate token in list")); 5125 return; 5126 } 5127 } 5128 } 5129 } 5130 5131 pc->phase = PP_PARSE_WALLET_DATA; 5132 } 5133 5134 5135 /** 5136 * Custom cleanup routine for a `struct PayContext`. 5137 * 5138 * @param cls the `struct PayContext` to clean up. 5139 */ 5140 static void 5141 pay_context_cleanup (void *cls) 5142 { 5143 struct PayContext *pc = cls; 5144 5145 if (NULL != pc->batch_deposits.timeout_task) 5146 { 5147 GNUNET_SCHEDULER_cancel (pc->batch_deposits.timeout_task); 5148 pc->batch_deposits.timeout_task = NULL; 5149 } 5150 if (NULL != pc->check_contract.contract_terms_json) 5151 { 5152 json_decref (pc->check_contract.contract_terms_json); 5153 pc->check_contract.contract_terms_json = NULL; 5154 } 5155 for (unsigned int i = 0; i<pc->parse_pay.coins_cnt; i++) 5156 { 5157 struct DepositConfirmation *dc = &pc->parse_pay.dc[i]; 5158 5159 TALER_denom_sig_free (&dc->cdd.denom_sig); 5160 GNUNET_free (dc->exchange_url); 5161 } 5162 GNUNET_free (pc->parse_pay.dc); 5163 for (unsigned int i = 0; i<pc->parse_pay.tokens_cnt; i++) 5164 { 5165 struct TokenUseConfirmation *tuc = &pc->parse_pay.tokens[i]; 5166 5167 TALER_token_issue_sig_free (&tuc->unblinded_sig); 5168 } 5169 GNUNET_free (pc->parse_pay.tokens); 5170 for (unsigned int i = 0; i<pc->parse_pay.num_exchanges; i++) 5171 { 5172 struct ExchangeGroup *eg = pc->parse_pay.egs[i]; 5173 5174 if (NULL != eg->fo) 5175 TMH_EXCHANGES_keys4exchange_cancel (eg->fo); 5176 if (NULL != eg->bdh) 5177 TALER_EXCHANGE_post_batch_deposit_cancel (eg->bdh); 5178 if (NULL != eg->keys) 5179 TALER_EXCHANGE_keys_decref (eg->keys); 5180 GNUNET_free (eg); 5181 } 5182 GNUNET_free (pc->parse_pay.egs); 5183 if (NULL != pc->check_contract.contract_terms) 5184 { 5185 TALER_MERCHANT_contract_free (pc->check_contract.contract_terms); 5186 pc->check_contract.contract_terms = NULL; 5187 } 5188 if (NULL != pc->response) 5189 { 5190 MHD_destroy_response (pc->response); 5191 pc->response = NULL; 5192 } 5193 GNUNET_free (pc->parse_pay.session_id); 5194 GNUNET_CONTAINER_DLL_remove (pc_head, 5195 pc_tail, 5196 pc); 5197 GNUNET_free (pc->check_contract.pos_key); 5198 GNUNET_free (pc->compute_money_pots.pots); 5199 GNUNET_free (pc->compute_money_pots.increments); 5200 if (NULL != pc->parse_wallet_data.bkps) 5201 { 5202 for (size_t i = 0; i < pc->parse_wallet_data.num_bkps; i++) 5203 GNUNET_CRYPTO_blinded_message_decref ( 5204 pc->parse_wallet_data.bkps[i].blinded_udi.blinded_message); 5205 GNUNET_array_grow (pc->parse_wallet_data.bkps, 5206 pc->parse_wallet_data.num_bkps, 5207 0); 5208 } 5209 if (NULL != pc->parse_wallet_data.donau_keys) 5210 { 5211 DONAU_keys_decref (pc->parse_wallet_data.donau_keys); 5212 pc->parse_wallet_data.donau_keys = NULL; 5213 } 5214 GNUNET_free (pc->parse_wallet_data.donau.donau_url); 5215 for (unsigned int i = 0; i<pc->parse_wallet_data.token_envelopes_cnt; i++) 5216 { 5217 struct TokenEnvelope *ev 5218 = &pc->parse_wallet_data.token_envelopes[i]; 5219 5220 GNUNET_CRYPTO_blinded_message_decref (ev->blinded_token.blinded_pub); 5221 } 5222 GNUNET_free (pc->parse_wallet_data.token_envelopes); 5223 if (NULL != pc->output_tokens) 5224 { 5225 for (unsigned int i = 0; i<pc->output_tokens_len; i++) 5226 if (NULL != pc->output_tokens[i].sig.signature) 5227 GNUNET_CRYPTO_blinded_sig_decref (pc->output_tokens[i].sig.signature); 5228 GNUNET_free (pc->output_tokens); 5229 pc->output_tokens = NULL; 5230 } 5231 GNUNET_free (pc); 5232 } 5233 5234 5235 enum MHD_Result 5236 TMH_post_orders_ID_pay (const struct TMH_RequestHandler *rh, 5237 struct MHD_Connection *connection, 5238 struct TMH_HandlerContext *hc) 5239 { 5240 struct PayContext *pc = hc->ctx; 5241 5242 GNUNET_assert (NULL != hc->infix); 5243 if (NULL == pc) 5244 { 5245 pc = GNUNET_new (struct PayContext); 5246 pc->connection = connection; 5247 pc->hc = hc; 5248 pc->order_id = hc->infix; 5249 hc->ctx = pc; 5250 hc->cc = &pay_context_cleanup; 5251 GNUNET_CONTAINER_DLL_insert (pc_head, 5252 pc_tail, 5253 pc); 5254 } 5255 while (1) 5256 { 5257 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 5258 "Processing /pay in phase %d\n", 5259 (int) pc->phase); 5260 switch (pc->phase) 5261 { 5262 case PP_PARSE_PAY: 5263 phase_parse_pay (pc); 5264 break; 5265 case PP_PARSE_WALLET_DATA: 5266 phase_parse_wallet_data (pc); 5267 break; 5268 case PP_CHECK_CONTRACT: 5269 phase_check_contract (pc); 5270 break; 5271 case PP_VALIDATE_TOKENS: 5272 phase_validate_tokens (pc); 5273 break; 5274 case PP_CONTRACT_PAID: 5275 phase_contract_paid (pc); 5276 break; 5277 case PP_COMPUTE_MONEY_POTS: 5278 phase_compute_money_pots (pc); 5279 break; 5280 case PP_PAY_TRANSACTION: 5281 phase_execute_pay_transaction (pc); 5282 break; 5283 case PP_REQUEST_DONATION_RECEIPT: 5284 phase_request_donation_receipt (pc); 5285 break; 5286 case PP_FINAL_OUTPUT_TOKEN_PROCESSING: 5287 phase_final_output_token_processing (pc); 5288 break; 5289 case PP_PAYMENT_NOTIFICATION: 5290 phase_payment_notification (pc); 5291 break; 5292 case PP_SUCCESS_RESPONSE: 5293 phase_success_response (pc); 5294 break; 5295 case PP_BATCH_DEPOSITS: 5296 phase_batch_deposits (pc); 5297 break; 5298 case PP_RETURN_RESPONSE: 5299 phase_return_response (pc); 5300 break; 5301 case PP_FAIL_LEGAL_REASONS: 5302 phase_fail_for_legal_reasons (pc); 5303 break; 5304 case PP_END_YES: 5305 return MHD_YES; 5306 case PP_END_NO: 5307 return MHD_NO; 5308 default: 5309 /* should not be reachable */ 5310 GNUNET_assert (0); 5311 return MHD_NO; 5312 } 5313 switch (pc->suspended) 5314 { 5315 case GNUNET_SYSERR: 5316 /* during shutdown, we don't generate any more replies */ 5317 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 5318 "Processing /pay ends due to shutdown in phase %d\n", 5319 (int) pc->phase); 5320 return MHD_NO; 5321 case GNUNET_NO: 5322 /* continue to next phase */ 5323 break; 5324 case GNUNET_YES: 5325 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 5326 "Processing /pay suspended in phase %d\n", 5327 (int) pc->phase); 5328 return MHD_YES; 5329 } 5330 } 5331 /* impossible to get here */ 5332 GNUNET_assert (0); 5333 return MHD_YES; 5334 } 5335 5336 5337 /* end of taler-merchant-httpd_post-orders-ORDER_ID-pay.c */