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