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