taler-merchant-httpd_post-orders-ORDER_ID-pay.c (164600B)
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->pc->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->pc->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->pc->h_wire, 1224 sizeof (eg->pc->check_contract.contract_terms->pc->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 1417 = pc->check_contract.contract_terms->pc->wire_deadline, 1418 .merchant_payto_uri 1419 = pc->check_contract.wm->payto_uri, 1420 .extra_wire_subject_metadata 1421 = pc->check_contract.wm->extra_wire_subject_metadata, 1422 .wire_salt 1423 = pc->check_contract.wm->wire_salt, 1424 .h_contract_terms 1425 = pc->check_contract.h_contract_terms, 1426 .wallet_data_hash 1427 = pc->parse_wallet_data.h_wallet_data, 1428 .wallet_timestamp 1429 = pc->check_contract.contract_terms->pc->timestamp, 1430 .merchant_pub 1431 = hc->instance->merchant_pub, 1432 .refund_deadline 1433 = pc->check_contract.contract_terms->pc->refund_deadline 1434 }; 1435 /* Collect up to TALER_MAX_COINS eligible coins for this batch */ 1436 struct TALER_EXCHANGE_CoinDepositDetail cdds[group_size]; 1437 unsigned int batch_size = 0; 1438 enum TALER_ErrorCode ec; 1439 1440 /* FIXME-optimization: move signing outside of this 'loop' 1441 and into the code that runs long before we look at a 1442 specific exchange, otherwise we sign repeatedly! */ 1443 TALER_merchant_contract_sign (&pc->check_contract.h_contract_terms, 1444 &pc->hc->instance->merchant_priv, 1445 &dcd.merchant_sig); 1446 for (size_t i = 0; i<pc->parse_pay.coins_cnt; i++) 1447 { 1448 struct DepositConfirmation *dc = &pc->parse_pay.dc[i]; 1449 1450 if (dc->found_in_db) 1451 continue; 1452 if (0 != strcmp (dc->exchange_url, 1453 eg->exchange_url)) 1454 continue; 1455 dc->in_batch = true; 1456 cdds[batch_size++] = dc->cdd; 1457 if (batch_size == group_size) 1458 break; 1459 } 1460 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 1461 "Initiating batch deposit with %u coins\n", 1462 batch_size); 1463 /* Note: the coin signatures over the wallet_data_hash are 1464 checked inside of this call */ 1465 eg->bdh = TALER_EXCHANGE_post_batch_deposit_create ( 1466 TMH_curl_ctx, 1467 eg->exchange_url, 1468 eg->keys, 1469 &dcd, 1470 batch_size, 1471 cdds, 1472 &ec); 1473 if (NULL == eg->bdh) 1474 { 1475 /* Signature was invalid or some other constraint was not satisfied. If 1476 the exchange was unavailable, we'd get that information in the 1477 callback. */ 1478 GNUNET_break_op (0); 1479 resume_pay_with_response ( 1480 pc, 1481 TALER_ErrorCode_get_http_status_safe (ec), 1482 TALER_MHD_MAKE_JSON_PACK ( 1483 TALER_JSON_pack_ec (ec), 1484 GNUNET_JSON_pack_string ("exchange_url", 1485 eg->exchange_url))); 1486 return; 1487 } 1488 pc->batch_deposits.pending_at_eg++; 1489 if (TMH_force_audit) 1490 { 1491 GNUNET_assert ( 1492 GNUNET_OK == 1493 TALER_EXCHANGE_post_batch_deposit_set_options ( 1494 eg->bdh, 1495 TALER_EXCHANGE_post_batch_deposit_option_force_dc ())); 1496 } 1497 TALER_EXCHANGE_post_batch_deposit_start (eg->bdh, 1498 &batch_deposit_cb, 1499 eg); 1500 } 1501 } 1502 1503 1504 /** 1505 * Force re-downloading keys for @a eg. 1506 * 1507 * @param[in,out] eg group to re-download keys for 1508 */ 1509 static void 1510 force_keys (struct ExchangeGroup *eg); 1511 1512 1513 /** 1514 * Function called with the result of our exchange keys lookup. 1515 * 1516 * @param cls the `struct ExchangeGroup` 1517 * @param keys the keys of the exchange 1518 * @param exchange representation of the exchange 1519 */ 1520 static void 1521 process_pay_with_keys ( 1522 void *cls, 1523 struct TALER_EXCHANGE_Keys *keys, 1524 struct TMH_Exchange *exchange) 1525 { 1526 struct ExchangeGroup *eg = cls; 1527 struct PayContext *pc = eg->pc; 1528 struct TMH_HandlerContext *hc = pc->hc; 1529 struct TALER_Amount max_amount; 1530 enum TMH_ExchangeStatus es; 1531 1532 eg->fo = NULL; 1533 pc->batch_deposits.pending_at_eg--; 1534 GNUNET_SCHEDULER_begin_async_scope (&hc->async_scope_id); 1535 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 1536 "Processing payment with keys from exchange %s\n", 1537 eg->exchange_url); 1538 GNUNET_assert (GNUNET_YES == pc->suspended); 1539 if (NULL == keys) 1540 { 1541 GNUNET_break_op (0); 1542 resume_pay_with_error ( 1543 pc, 1544 TALER_EC_MERCHANT_GENERIC_EXCHANGE_TIMEOUT, 1545 NULL); 1546 return; 1547 } 1548 eg->keys = TALER_EXCHANGE_keys_incref (keys); 1549 if (! TMH_EXCHANGES_is_below_limit (keys, 1550 TALER_KYCLOGIC_KYC_TRIGGER_TRANSACTION, 1551 &eg->total)) 1552 { 1553 GNUNET_break_op (0); 1554 resume_pay_with_error ( 1555 pc, 1556 TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_EXCHANGE_TRANSACTION_LIMIT_VIOLATION, 1557 eg->exchange_url); 1558 return; 1559 } 1560 1561 max_amount = eg->total; 1562 es = TMH_exchange_check_debit ( 1563 pc->hc->instance->settings.id, 1564 exchange, 1565 pc->check_contract.wm, 1566 &max_amount); 1567 if ( (TMH_ES_OK != es) && 1568 (TMH_ES_RETRY_OK != es) ) 1569 { 1570 if (eg->tried_force_keys || 1571 (0 == (TMH_ES_RETRY_OK & es)) ) 1572 { 1573 GNUNET_break_op (0); 1574 resume_pay_with_error ( 1575 pc, 1576 TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_WIRE_METHOD_UNSUPPORTED, 1577 NULL); 1578 return; 1579 } 1580 force_keys (eg); 1581 return; 1582 } 1583 if (-1 == 1584 TALER_amount_cmp (&max_amount, 1585 &eg->total)) 1586 { 1587 /* max_amount < eg->total */ 1588 GNUNET_break_op (0); 1589 resume_pay_with_error ( 1590 pc, 1591 TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_EXCHANGE_TRANSACTION_LIMIT_VIOLATION, 1592 eg->exchange_url); 1593 return; 1594 } 1595 1596 if (GNUNET_OK != 1597 TMH_EXCHANGES_lookup_wire_fee (exchange, 1598 pc->check_contract.wm->wire_method, 1599 &eg->wire_fee)) 1600 { 1601 if (eg->tried_force_keys) 1602 { 1603 GNUNET_break_op (0); 1604 resume_pay_with_error ( 1605 pc, 1606 TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_WIRE_METHOD_UNSUPPORTED, 1607 pc->check_contract.wm->wire_method); 1608 return; 1609 } 1610 force_keys (eg); 1611 return; 1612 } 1613 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 1614 "Got wire data for %s\n", 1615 eg->exchange_url); 1616 1617 /* Check all coins satisfy constraints like deposit deadlines 1618 and age restrictions */ 1619 for (size_t i = 0; i<pc->parse_pay.coins_cnt; i++) 1620 { 1621 struct DepositConfirmation *dc = &pc->parse_pay.dc[i]; 1622 const struct TALER_EXCHANGE_DenomPublicKey *denom_details; 1623 bool is_age_restricted_denom = false; 1624 1625 if (0 != strcmp (eg->exchange_url, 1626 pc->parse_pay.dc[i].exchange_url)) 1627 continue; 1628 if (dc->found_in_db) 1629 continue; 1630 1631 denom_details 1632 = TALER_EXCHANGE_get_denomination_key_by_hash (keys, 1633 &dc->cdd.h_denom_pub); 1634 if (NULL == denom_details) 1635 { 1636 if (eg->tried_force_keys) 1637 { 1638 GNUNET_break_op (0); 1639 resume_pay_with_response ( 1640 pc, 1641 MHD_HTTP_BAD_REQUEST, 1642 TALER_MHD_MAKE_JSON_PACK ( 1643 TALER_JSON_pack_ec ( 1644 TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_DENOMINATION_KEY_NOT_FOUND), 1645 GNUNET_JSON_pack_data_auto ("h_denom_pub", 1646 &dc->cdd.h_denom_pub), 1647 GNUNET_JSON_pack_allow_null ( 1648 GNUNET_JSON_pack_object_steal ( 1649 "exchange_keys", 1650 TALER_EXCHANGE_keys_to_json (keys))))); 1651 return; 1652 } 1653 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 1654 "Missing denomination %s from exchange %s, updating keys\n", 1655 GNUNET_h2s (&dc->cdd.h_denom_pub.hash), 1656 eg->exchange_url); 1657 force_keys (eg); 1658 return; 1659 } 1660 dc->deposit_fee = denom_details->fees.deposit; 1661 dc->refund_fee = denom_details->fees.refund; 1662 1663 if (GNUNET_TIME_absolute_is_past ( 1664 denom_details->expire_deposit.abs_time)) 1665 { 1666 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 1667 "Denomination key offered by client has expired for deposits\n"); 1668 resume_pay_with_response ( 1669 pc, 1670 MHD_HTTP_GONE, 1671 TALER_MHD_MAKE_JSON_PACK ( 1672 TALER_JSON_pack_ec ( 1673 TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_DENOMINATION_DEPOSIT_EXPIRED), 1674 GNUNET_JSON_pack_data_auto ("h_denom_pub", 1675 &denom_details->h_key))); 1676 return; 1677 } 1678 1679 /* Now that we have the details about the denomination, we can verify age 1680 * restriction requirements, if applicable. Note that denominations with an 1681 * age_mask equal to zero always pass the age verification. */ 1682 is_age_restricted_denom = (0 != denom_details->key.age_mask.bits); 1683 1684 if (is_age_restricted_denom && 1685 (0 < pc->check_contract.contract_terms->pc->base->minimum_age)) 1686 { 1687 /* Minimum age given and restricted coin provided: We need to verify the 1688 * minimum age */ 1689 unsigned int code = 0; 1690 1691 if (dc->no_age_commitment) 1692 { 1693 GNUNET_break_op (0); 1694 code = TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_AGE_COMMITMENT_MISSING; 1695 goto AGE_FAIL; 1696 } 1697 dc->age_commitment.mask = denom_details->key.age_mask; 1698 if (((int) (dc->age_commitment.num + 1)) != 1699 __builtin_popcount (dc->age_commitment.mask.bits)) 1700 { 1701 GNUNET_break_op (0); 1702 code = 1703 TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_AGE_COMMITMENT_SIZE_MISMATCH; 1704 goto AGE_FAIL; 1705 } 1706 if (GNUNET_OK != 1707 TALER_age_commitment_verify ( 1708 &dc->age_commitment, 1709 pc->check_contract.contract_terms->pc->base->minimum_age, 1710 &dc->minimum_age_sig)) 1711 code = TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_AGE_VERIFICATION_FAILED; 1712 AGE_FAIL: 1713 if (0 < code) 1714 { 1715 GNUNET_break_op (0); 1716 TALER_age_commitment_free (&dc->age_commitment); 1717 resume_pay_with_response ( 1718 pc, 1719 MHD_HTTP_BAD_REQUEST, 1720 TALER_MHD_MAKE_JSON_PACK ( 1721 TALER_JSON_pack_ec (code), 1722 GNUNET_JSON_pack_data_auto ("h_denom_pub", 1723 &denom_details->h_key))); 1724 return; 1725 } 1726 1727 /* Age restriction successfully verified! 1728 * Calculate the hash of the age commitment. */ 1729 TALER_age_commitment_hash (&dc->age_commitment, 1730 &dc->cdd.h_age_commitment); 1731 TALER_age_commitment_free (&dc->age_commitment); 1732 } 1733 else if (is_age_restricted_denom && 1734 dc->no_h_age_commitment) 1735 { 1736 /* The contract did not ask for a minimum_age but the client paid 1737 * with a coin that has age restriction enabled. We lack the hash 1738 * of the age commitment in this case in order to verify the coin 1739 * and to deposit it with the exchange. */ 1740 GNUNET_break_op (0); 1741 resume_pay_with_response ( 1742 pc, 1743 MHD_HTTP_BAD_REQUEST, 1744 TALER_MHD_MAKE_JSON_PACK ( 1745 TALER_JSON_pack_ec ( 1746 TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_AGE_COMMITMENT_HASH_MISSING), 1747 GNUNET_JSON_pack_data_auto ("h_denom_pub", 1748 &denom_details->h_key))); 1749 return; 1750 } 1751 } 1752 1753 do_batch_deposits (eg); 1754 } 1755 1756 1757 static void 1758 force_keys (struct ExchangeGroup *eg) 1759 { 1760 struct PayContext *pc = eg->pc; 1761 1762 eg->tried_force_keys = true; 1763 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 1764 "Forcing /keys download (once)\n"); 1765 eg->fo = TMH_EXCHANGES_keys4exchange ( 1766 eg->exchange_url, 1767 true, 1768 &process_pay_with_keys, 1769 eg); 1770 if (NULL == eg->fo) 1771 { 1772 GNUNET_break_op (0); 1773 resume_pay_with_error (pc, 1774 TALER_EC_MERCHANT_GENERIC_EXCHANGE_UNTRUSTED, 1775 eg->exchange_url); 1776 return; 1777 } 1778 pc->batch_deposits.pending_at_eg++; 1779 } 1780 1781 1782 /** 1783 * Handle a timeout for the processing of the pay request. 1784 * 1785 * @param cls our `struct PayContext` 1786 */ 1787 static void 1788 handle_pay_timeout (void *cls) 1789 { 1790 struct PayContext *pc = cls; 1791 1792 pc->batch_deposits.timeout_task = NULL; 1793 GNUNET_assert (GNUNET_YES == pc->suspended); 1794 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 1795 "Resuming pay with error after timeout\n"); 1796 resume_pay_with_error (pc, 1797 TALER_EC_MERCHANT_GENERIC_EXCHANGE_TIMEOUT, 1798 NULL); 1799 } 1800 1801 1802 /** 1803 * Compute the timeout for a /pay request based on the number of coins 1804 * involved. 1805 * 1806 * @param num_coins number of coins 1807 * @returns timeout for the /pay request 1808 */ 1809 static struct GNUNET_TIME_Relative 1810 get_pay_timeout (unsigned int num_coins) 1811 { 1812 struct GNUNET_TIME_Relative t; 1813 1814 /* FIXME-Performance-Optimization: Do some benchmarking to come up with a 1815 * better timeout. We've increased this value so the wallet integration 1816 * test passes again on my (Florian) machine. 1817 */ 1818 t = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 1819 15 * (1 + (num_coins / 5))); 1820 1821 return t; 1822 } 1823 1824 1825 /** 1826 * Start batch deposits for all exchanges involved 1827 * in this payment. 1828 * 1829 * @param[in,out] pc payment context we are processing 1830 */ 1831 static void 1832 phase_batch_deposits (struct PayContext *pc) 1833 { 1834 for (unsigned int i = 0; i<pc->parse_pay.num_exchanges; i++) 1835 { 1836 struct ExchangeGroup *eg = pc->parse_pay.egs[i]; 1837 bool have_coins = false; 1838 1839 for (size_t j = 0; j<pc->parse_pay.coins_cnt; j++) 1840 { 1841 struct DepositConfirmation *dc = &pc->parse_pay.dc[j]; 1842 1843 if (0 != strcmp (eg->exchange_url, 1844 dc->exchange_url)) 1845 continue; 1846 if (dc->found_in_db) 1847 continue; 1848 have_coins = true; 1849 break; 1850 } 1851 if (! have_coins) 1852 continue; /* no coins left to deposit at this exchange */ 1853 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 1854 "Getting /keys for %s\n", 1855 eg->exchange_url); 1856 eg->fo = TMH_EXCHANGES_keys4exchange ( 1857 eg->exchange_url, 1858 false, 1859 &process_pay_with_keys, 1860 eg); 1861 if (NULL == eg->fo) 1862 { 1863 GNUNET_break_op (0); 1864 pay_end (pc, 1865 TALER_MHD_reply_with_error ( 1866 pc->connection, 1867 MHD_HTTP_BAD_REQUEST, 1868 TALER_EC_MERCHANT_GENERIC_EXCHANGE_UNTRUSTED, 1869 eg->exchange_url)); 1870 return; 1871 } 1872 pc->batch_deposits.pending_at_eg++; 1873 } 1874 if (0 == pc->batch_deposits.pending_at_eg) 1875 { 1876 pc->phase = PP_COMPUTE_MONEY_POTS; 1877 pay_resume (pc); 1878 return; 1879 } 1880 /* Suspend while we interact with the exchange */ 1881 MHD_suspend_connection (pc->connection); 1882 pc->suspended = GNUNET_YES; 1883 GNUNET_assert (NULL == pc->batch_deposits.timeout_task); 1884 pc->batch_deposits.timeout_task 1885 = GNUNET_SCHEDULER_add_delayed (get_pay_timeout (pc->parse_pay.coins_cnt), 1886 &handle_pay_timeout, 1887 pc); 1888 } 1889 1890 1891 /** 1892 * Build JSON array of blindly signed token envelopes, 1893 * to be used in the response to the wallet. 1894 * 1895 * @param[in,out] pc payment context to use 1896 */ 1897 static json_t * 1898 build_token_sigs (struct PayContext *pc) 1899 { 1900 json_t *token_sigs; 1901 1902 if (0 == pc->output_tokens_len) 1903 return NULL; 1904 token_sigs = json_array (); 1905 GNUNET_assert (NULL != token_sigs); 1906 for (unsigned int i = 0; i < pc->output_tokens_len; i++) 1907 { 1908 GNUNET_assert (0 == 1909 json_array_append_new ( 1910 token_sigs, 1911 GNUNET_JSON_PACK ( 1912 GNUNET_JSON_pack_blinded_sig ( 1913 "blind_sig", 1914 pc->output_tokens[i].sig.signature) 1915 ))); 1916 } 1917 return token_sigs; 1918 } 1919 1920 1921 /** 1922 * Generate response (payment successful) 1923 * 1924 * @param[in,out] pc payment context where the payment was successful 1925 */ 1926 static void 1927 phase_success_response (struct PayContext *pc) 1928 { 1929 struct TALER_MerchantSignatureP sig; 1930 char *pos_confirmation; 1931 1932 /* Sign on our end (as the payment did go through, even if it may 1933 have been refunded already) */ 1934 TALER_merchant_pay_sign (&pc->check_contract.h_contract_terms, 1935 &pc->hc->instance->merchant_priv, 1936 &sig); 1937 /* Build the response */ 1938 pos_confirmation = (NULL == pc->check_contract.pos_key) 1939 ? NULL 1940 : TALER_build_pos_confirmation ( 1941 pc->check_contract.pos_key, 1942 pc->check_contract.pos_alg, 1943 &pc->validate_tokens.brutto, 1944 pc->check_contract.contract_terms->pc->timestamp); 1945 pay_end (pc, 1946 TALER_MHD_REPLY_JSON_PACK ( 1947 pc->connection, 1948 MHD_HTTP_OK, 1949 GNUNET_JSON_pack_allow_null ( 1950 GNUNET_JSON_pack_string ("pos_confirmation", 1951 pos_confirmation)), 1952 GNUNET_JSON_pack_allow_null ( 1953 GNUNET_JSON_pack_array_steal ("token_sigs", 1954 build_token_sigs (pc))), 1955 GNUNET_JSON_pack_data_auto ("sig", 1956 &sig))); 1957 GNUNET_free (pos_confirmation); 1958 } 1959 1960 1961 /** 1962 * Use database to notify other clients about the 1963 * payment being completed. 1964 * 1965 * @param[in,out] pc context to trigger notification for 1966 */ 1967 static void 1968 phase_payment_notification (struct PayContext *pc) 1969 { 1970 { 1971 struct TMH_OrderPayEventP pay_eh = { 1972 .header.size = htons (sizeof (pay_eh)), 1973 .header.type = htons (TALER_DBEVENT_MERCHANT_ORDER_PAID), 1974 .merchant_pub = pc->hc->instance->merchant_pub 1975 }; 1976 1977 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 1978 "Notifying clients about payment of order %s\n", 1979 pc->order_id); 1980 GNUNET_CRYPTO_hash (pc->order_id, 1981 strlen (pc->order_id), 1982 &pay_eh.h_order_id); 1983 TALER_MERCHANTDB_event_notify (TMH_db, 1984 &pay_eh.header, 1985 NULL, 1986 0); 1987 } 1988 { 1989 struct TMH_OrderPayEventP pay_eh = { 1990 .header.size = htons (sizeof (pay_eh)), 1991 .header.type = htons (TALER_DBEVENT_MERCHANT_ORDER_STATUS_CHANGED), 1992 .merchant_pub = pc->hc->instance->merchant_pub 1993 }; 1994 1995 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 1996 "Notifying clients about status change of order %s\n", 1997 pc->order_id); 1998 GNUNET_CRYPTO_hash (pc->order_id, 1999 strlen (pc->order_id), 2000 &pay_eh.h_order_id); 2001 TALER_MERCHANTDB_event_notify (TMH_db, 2002 &pay_eh.header, 2003 NULL, 2004 0); 2005 } 2006 if ( (NULL != pc->parse_pay.session_id) && 2007 (NULL != pc->check_contract.contract_terms->pc->base->fulfillment_url) ) 2008 { 2009 struct TMH_SessionEventP session_eh = { 2010 .header.size = htons (sizeof (session_eh)), 2011 .header.type = htons (TALER_DBEVENT_MERCHANT_SESSION_CAPTURED), 2012 .merchant_pub = pc->hc->instance->merchant_pub 2013 }; 2014 2015 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 2016 "Notifying clients about session change to %s for %s\n", 2017 pc->parse_pay.session_id, 2018 pc->check_contract.contract_terms->pc->base->fulfillment_url); 2019 GNUNET_CRYPTO_hash (pc->parse_pay.session_id, 2020 strlen (pc->parse_pay.session_id), 2021 &session_eh.h_session_id); 2022 GNUNET_CRYPTO_hash ( 2023 pc->check_contract.contract_terms->pc->base->fulfillment_url, 2024 strlen (pc->check_contract.contract_terms->pc->base->fulfillment_url), 2025 &session_eh.h_fulfillment_url); 2026 TALER_MERCHANTDB_event_notify (TMH_db, 2027 &session_eh.header, 2028 NULL, 2029 0); 2030 } 2031 pc->phase = PP_SUCCESS_RESPONSE; 2032 } 2033 2034 2035 /** 2036 * Phase to write all outputs to our database so we do 2037 * not re-request them in case the client re-plays the 2038 * request. 2039 * 2040 * @param[in,out] pc payment context 2041 */ 2042 static void 2043 phase_final_output_token_processing (struct PayContext *pc) 2044 { 2045 if (0 == pc->output_tokens_len) 2046 { 2047 pc->phase++; 2048 return; 2049 } 2050 for (unsigned int retry = 0; retry < MAX_RETRIES; retry++) 2051 { 2052 enum GNUNET_DB_QueryStatus qs; 2053 2054 TALER_MERCHANTDB_preflight (TMH_db); 2055 if (GNUNET_OK != 2056 TALER_MERCHANTDB_start (TMH_db, 2057 "insert_order_blinded_sigs")) 2058 { 2059 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 2060 "start insert_order_blinded_sigs_failed"); 2061 pc->phase++; 2062 return; 2063 } 2064 if (pc->parse_wallet_data.num_bkps > 0) 2065 { 2066 qs = TALER_MERCHANTDB_update_donau_instance_receipts_amount ( 2067 TMH_db, 2068 &pc->parse_wallet_data.donau_instance_serial, 2069 &pc->parse_wallet_data.charity_receipts_to_date); 2070 switch (qs) 2071 { 2072 case GNUNET_DB_STATUS_HARD_ERROR: 2073 TALER_MERCHANTDB_rollback (TMH_db); 2074 GNUNET_break (0); 2075 return; 2076 case GNUNET_DB_STATUS_SOFT_ERROR: 2077 TALER_MERCHANTDB_rollback (TMH_db); 2078 continue; 2079 case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS: 2080 /* weird for an update */ 2081 GNUNET_break (0); 2082 break; 2083 case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT: 2084 break; 2085 } 2086 } 2087 for (unsigned int i = 0; 2088 i < pc->output_tokens_len; 2089 i++) 2090 { 2091 qs = TALER_MERCHANTDB_insert_order_blinded_sigs ( 2092 TMH_db, 2093 pc->order_id, 2094 i, 2095 &pc->output_tokens[i].h_issue.hash, 2096 pc->output_tokens[i].sig.signature); 2097 2098 switch (qs) 2099 { 2100 case GNUNET_DB_STATUS_HARD_ERROR: 2101 TALER_MERCHANTDB_rollback (TMH_db); 2102 pc->phase++; 2103 return; 2104 case GNUNET_DB_STATUS_SOFT_ERROR: 2105 TALER_MERCHANTDB_rollback (TMH_db); 2106 goto OUTER; 2107 case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS: 2108 /* weird for an update */ 2109 GNUNET_break (0); 2110 break; 2111 case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT: 2112 break; 2113 } 2114 } /* for i */ 2115 qs = TALER_MERCHANTDB_commit (TMH_db); 2116 switch (qs) 2117 { 2118 case GNUNET_DB_STATUS_HARD_ERROR: 2119 TALER_MERCHANTDB_rollback (TMH_db); 2120 pc->phase++; 2121 return; 2122 case GNUNET_DB_STATUS_SOFT_ERROR: 2123 TALER_MERCHANTDB_rollback (TMH_db); 2124 continue; 2125 case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS: 2126 pc->phase++; 2127 return; /* success */ 2128 case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT: 2129 pc->phase++; 2130 return; /* success */ 2131 } 2132 GNUNET_break (0); 2133 pc->phase++; 2134 return; /* strange */ 2135 OUTER: 2136 } /* for retry */ 2137 TALER_MERCHANTDB_rollback (TMH_db); 2138 pc->phase++; 2139 /* We continue anyway, as there is not much we can 2140 do here: the Donau *did* issue us the receipts; 2141 also, we'll eventually ask the Donau for the 2142 balance and get the correct one. Plus, we were 2143 paid by the client, so it's technically all still 2144 OK. If the request fails anyway, the wallet will 2145 most likely replay the request and then hopefully 2146 we will succeed the next time */ 2147 } 2148 2149 2150 /** 2151 * Add donation receipt outputs to the output_tokens. 2152 * 2153 * Note that under the current (odd, bad) libdonau 2154 * API *we* are responsible for freeing blinded_sigs, 2155 * so we truly own that array! 2156 * 2157 * @param[in,out] pc payment context 2158 * @param num_blinded_sigs number of signatures received 2159 * @param blinded_sigs blinded signatures from Donau 2160 * @return #GNUNET_OK on success, 2161 * #GNUNET_SYSERR on failure (state machine was 2162 * in that case already advanced) 2163 */ 2164 static enum GNUNET_GenericReturnValue 2165 add_donation_receipt_outputs ( 2166 struct PayContext *pc, 2167 size_t num_blinded_sigs, 2168 struct DONAU_BlindedDonationUnitSignature *blinded_sigs) 2169 { 2170 int donau_output_index = pc->validate_tokens.donau_output_index; 2171 2172 GNUNET_assert (pc->parse_wallet_data.num_bkps == 2173 num_blinded_sigs); 2174 2175 GNUNET_assert (donau_output_index >= 0); 2176 2177 for (unsigned int i = 0; i<pc->output_tokens_len; i++) 2178 { 2179 struct SignedOutputToken *sot 2180 = &pc->output_tokens[i]; 2181 2182 /* Only look at actual donau tokens. */ 2183 if (sot->output_index != donau_output_index) 2184 continue; 2185 2186 sot->sig.signature = GNUNET_CRYPTO_blind_sig_incref (blinded_sigs[i]. 2187 blinded_sig); 2188 sot->h_issue.hash = pc->parse_wallet_data.bkps[i].h_donation_unit_pub.hash; 2189 } 2190 return GNUNET_OK; 2191 } 2192 2193 2194 /** 2195 * Callback to handle the result of a batch issue request. 2196 * 2197 * @param cls our `struct PayContext` 2198 * @param resp the response from Donau 2199 */ 2200 static void 2201 merchant_donau_issue_receipt_cb ( 2202 void *cls, 2203 const struct DONAU_BatchIssueResponse *resp) 2204 { 2205 struct PayContext *pc = cls; 2206 /* Donau replies asynchronously, so we expect the PayContext 2207 * to be suspended. */ 2208 GNUNET_assert (GNUNET_YES == pc->suspended); 2209 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 2210 "Donau responded with status=%u, ec=%u", 2211 resp->hr.http_status, 2212 resp->hr.ec); 2213 switch (resp->hr.http_status) 2214 { 2215 case 0: 2216 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 2217 "Donau batch issue request from merchant-httpd failed (http_status==0)"); 2218 resume_pay_with_error (pc, 2219 TALER_EC_MERCHANT_GENERIC_DONAU_INVALID_RESPONSE, 2220 resp->hr.hint); 2221 return; 2222 case MHD_HTTP_OK: 2223 case MHD_HTTP_CREATED: 2224 if (TALER_EC_NONE != resp->hr.ec) 2225 { 2226 /* Most probably, it is just some small flaw from 2227 * donau so no point in failing, yet we have to display it */ 2228 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 2229 "Donau signalled error %u despite HTTP %u", 2230 resp->hr.ec, 2231 resp->hr.http_status); 2232 } 2233 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 2234 "Donau accepted donation receipts with total_issued=%s", 2235 TALER_amount2s (&resp->details.ok.issued_amount)); 2236 if (GNUNET_OK != 2237 add_donation_receipt_outputs (pc, 2238 resp->details.ok.num_blinded_sigs, 2239 resp->details.ok.blinded_sigs)) 2240 return; /* state machine was already advanced */ 2241 pc->phase = PP_FINAL_OUTPUT_TOKEN_PROCESSING; 2242 pay_resume (pc); 2243 return; 2244 2245 case MHD_HTTP_BAD_REQUEST: 2246 case MHD_HTTP_FORBIDDEN: 2247 case MHD_HTTP_NOT_FOUND: 2248 case MHD_HTTP_INTERNAL_SERVER_ERROR: 2249 default: /* make sure that everything except 200/201 will end up here*/ 2250 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 2251 "Donau replied with HTTP %u (ec=%u)", 2252 resp->hr.http_status, 2253 resp->hr.ec); 2254 resume_pay_with_error (pc, 2255 TALER_EC_MERCHANT_GENERIC_DONAU_INVALID_RESPONSE, 2256 resp->hr.hint); 2257 return; 2258 } 2259 } 2260 2261 2262 /** 2263 * Parse a bkp encoded in JSON. 2264 * 2265 * @param[out] bkp where to return the result 2266 * @param bkp_key_obj json to parse 2267 * @return #GNUNET_OK if all is fine, #GNUNET_SYSERR if @a bkp_key_obj 2268 * is malformed. 2269 */ 2270 static enum GNUNET_GenericReturnValue 2271 merchant_parse_json_bkp (struct DONAU_BlindedUniqueDonorIdentifierKeyPair *bkp, 2272 const json_t *bkp_key_obj) 2273 { 2274 struct GNUNET_JSON_Specification spec[] = { 2275 GNUNET_JSON_spec_fixed_auto ("h_donation_unit_pub", 2276 &bkp->h_donation_unit_pub), 2277 DONAU_JSON_spec_blinded_donation_identifier ("blinded_udi", 2278 &bkp->blinded_udi), 2279 GNUNET_JSON_spec_end () 2280 }; 2281 2282 if (GNUNET_OK != 2283 GNUNET_JSON_parse (bkp_key_obj, 2284 spec, 2285 NULL, 2286 NULL)) 2287 { 2288 GNUNET_break_op (0); 2289 return GNUNET_SYSERR; 2290 } 2291 return GNUNET_OK; 2292 } 2293 2294 2295 /** 2296 * Generate a donation signature for the bkp and charity. 2297 * 2298 * @param[in,out] pc payment context containing the charity and bkps 2299 */ 2300 static void 2301 phase_request_donation_receipt (struct PayContext *pc) 2302 { 2303 if ( (NULL == pc->parse_wallet_data.donau.donau_url) || 2304 (0 == pc->parse_wallet_data.num_bkps) ) 2305 { 2306 pc->phase++; 2307 return; 2308 } 2309 pc->donau_receipt.birh = 2310 DONAU_charity_issue_receipt ( 2311 TMH_curl_ctx, 2312 pc->parse_wallet_data.donau.donau_url, 2313 &pc->parse_wallet_data.charity_priv, 2314 pc->parse_wallet_data.charity_id, 2315 pc->parse_wallet_data.donau.donation_year, 2316 pc->parse_wallet_data.num_bkps, 2317 pc->parse_wallet_data.bkps, 2318 &merchant_donau_issue_receipt_cb, 2319 pc); 2320 if (NULL == pc->donau_receipt.birh) 2321 { 2322 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 2323 "Failed to create Donau receipt request"); 2324 pay_end (pc, 2325 TALER_MHD_reply_with_error (pc->connection, 2326 MHD_HTTP_INTERNAL_SERVER_ERROR, 2327 TALER_EC_GENERIC_CLIENT_INTERNAL_ERROR, 2328 "Donau request creation error")); 2329 return; 2330 } 2331 MHD_suspend_connection (pc->connection); 2332 pc->suspended = GNUNET_YES; 2333 } 2334 2335 2336 /** 2337 * Increment the money pot @a pot_id in @a pc by @a increment. 2338 * 2339 * @param[in,out] pc context to update 2340 * @param pot_id money pot to increment 2341 * @param increment amount to add 2342 */ 2343 static void 2344 increment_pot (struct PayContext *pc, 2345 uint64_t pot_id, 2346 const struct TALER_Amount *increment) 2347 { 2348 for (unsigned int i = 0; i<pc->compute_money_pots.num_pots; i++) 2349 { 2350 if (pot_id == pc->compute_money_pots.pots[i]) 2351 { 2352 struct TALER_Amount *p; 2353 2354 p = &pc->compute_money_pots.increments[i]; 2355 GNUNET_assert (0 <= 2356 TALER_amount_add (p, 2357 p, 2358 increment)); 2359 return; 2360 } 2361 } 2362 GNUNET_array_append (pc->compute_money_pots.pots, 2363 pc->compute_money_pots.num_pots, 2364 pot_id); 2365 pc->compute_money_pots.num_pots--; /* do not increment twice... */ 2366 GNUNET_array_append (pc->compute_money_pots.increments, 2367 pc->compute_money_pots.num_pots, 2368 *increment); 2369 } 2370 2371 2372 /** 2373 * Compute the total changes to money pots in preparation 2374 * for the #PP_PAY_TRANSACTION phase. 2375 * 2376 * @param[in,out] pc payment context to transact 2377 */ 2378 static void 2379 phase_compute_money_pots (struct PayContext *pc) 2380 { 2381 const struct TALER_MERCHANT_Contract *contract 2382 = pc->check_contract.contract_terms; 2383 struct TALER_Amount assigned; 2384 2385 if (0 == pc->parse_pay.coins_cnt) 2386 { 2387 /* Did not pay with any coins, so no currency/amount involved, 2388 hence no money pot update possible. */ 2389 pc->phase++; 2390 return; 2391 } 2392 2393 if (pc->compute_money_pots.pots_computed) 2394 { 2395 pc->phase++; 2396 return; 2397 } 2398 /* reset, in case this phase is run a 2nd time */ 2399 GNUNET_free (pc->compute_money_pots.pots); 2400 GNUNET_free (pc->compute_money_pots.increments); 2401 pc->compute_money_pots.num_pots = 0; 2402 2403 GNUNET_assert (GNUNET_OK == 2404 TALER_amount_set_zero (pc->parse_pay.dc[0].cdd.amount.currency, 2405 &assigned)); 2406 GNUNET_assert (NULL != contract); 2407 for (size_t i = 0; i<contract->pc->products_len; i++) 2408 { 2409 const struct TALER_MERCHANT_ProductSold *product 2410 = &contract->pc->products[i]; 2411 const struct TALER_Amount *price = NULL; 2412 2413 /* find price in the right currency */ 2414 for (unsigned int j = 0; j<product->prices_length; j++) 2415 { 2416 if (GNUNET_OK == 2417 TALER_amount_cmp_currency (&assigned, 2418 &product->prices[j])) 2419 { 2420 price = &product->prices[j]; 2421 break; 2422 } 2423 } 2424 if (NULL == price) 2425 { 2426 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 2427 "Product `%s' has no price given in `%s'.\n", 2428 product->product_id, 2429 assigned.currency); 2430 continue; 2431 } 2432 if (0 != product->product_money_pot) 2433 { 2434 GNUNET_assert (0 <= 2435 TALER_amount_add (&assigned, 2436 &assigned, 2437 price)); 2438 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 2439 "Contributing to product money pot %llu increment of %s\n", 2440 (unsigned long long) product->product_money_pot, 2441 TALER_amount2s (price)); 2442 increment_pot (pc, 2443 product->product_money_pot, 2444 price); 2445 } 2446 } 2447 2448 { 2449 /* Compute what is left from the order total and account for that. 2450 Also sanity-check and handle the case where the overall order 2451 is below that of the sum of the products. */ 2452 struct TALER_Amount left; 2453 2454 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 2455 "Order brutto is %s\n", 2456 TALER_amount2s (&pc->validate_tokens.brutto)); 2457 if (0 > 2458 TALER_amount_subtract (&left, 2459 &pc->validate_tokens.brutto, 2460 &assigned)) 2461 { 2462 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 2463 "Total order brutto amount below sum from products, skipping per-product money pots\n"); 2464 GNUNET_free (pc->compute_money_pots.pots); 2465 GNUNET_free (pc->compute_money_pots.increments); 2466 pc->compute_money_pots.num_pots = 0; 2467 left = pc->validate_tokens.brutto; 2468 } 2469 2470 if ( (! TALER_amount_is_zero (&left)) && 2471 (0 != contract->pc->base->default_money_pot) ) 2472 { 2473 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 2474 "Computing money pot %llu increment as %s\n", 2475 (unsigned long long) contract->pc->base->default_money_pot, 2476 TALER_amount2s (&left)); 2477 increment_pot (pc, 2478 contract->pc->base->default_money_pot, 2479 &left); 2480 } 2481 } 2482 pc->compute_money_pots.pots_computed = true; 2483 pc->phase++; 2484 } 2485 2486 2487 /** 2488 * Function called with information about a coin that was deposited. 2489 * 2490 * @param cls closure 2491 * @param exchange_url exchange where @a coin_pub was deposited 2492 * @param coin_pub public key of the coin 2493 * @param amount_with_fee amount the exchange will deposit for this coin 2494 * @param deposit_fee fee the exchange will charge for this coin 2495 * @param refund_fee fee the exchange will charge for refunding this coin 2496 */ 2497 static void 2498 check_coin_paid (void *cls, 2499 const char *exchange_url, 2500 const struct TALER_CoinSpendPublicKeyP *coin_pub, 2501 const struct TALER_Amount *amount_with_fee, 2502 const struct TALER_Amount *deposit_fee, 2503 const struct TALER_Amount *refund_fee) 2504 { 2505 struct PayContext *pc = cls; 2506 2507 for (size_t i = 0; i<pc->parse_pay.coins_cnt; i++) 2508 { 2509 struct DepositConfirmation *dc = &pc->parse_pay.dc[i]; 2510 2511 if (dc->found_in_db) 2512 continue; /* processed earlier, skip "expensive" memcmp() */ 2513 /* Get matching coin from results*/ 2514 if ( (0 != GNUNET_memcmp (coin_pub, 2515 &dc->cdd.coin_pub)) || 2516 (0 != 2517 strcmp (exchange_url, 2518 dc->exchange_url)) || 2519 (GNUNET_OK != 2520 TALER_amount_cmp_currency (amount_with_fee, 2521 &dc->cdd.amount)) || 2522 (0 != TALER_amount_cmp (amount_with_fee, 2523 &dc->cdd.amount)) ) 2524 continue; /* does not match, skip */ 2525 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 2526 "Deposit of coin `%s' already in our DB.\n", 2527 TALER_B2S (coin_pub)); 2528 if ( (GNUNET_OK != 2529 TALER_amount_cmp_currency (&pc->pay_transaction.total_paid, 2530 amount_with_fee)) || 2531 (GNUNET_OK != 2532 TALER_amount_cmp_currency (&pc->pay_transaction.total_fees_paid, 2533 deposit_fee)) ) 2534 { 2535 GNUNET_break_op (0); 2536 pc->pay_transaction.deposit_currency_mismatch = true; 2537 break; 2538 } 2539 GNUNET_assert (0 <= 2540 TALER_amount_add (&pc->pay_transaction.total_paid, 2541 &pc->pay_transaction.total_paid, 2542 amount_with_fee)); 2543 GNUNET_assert (0 <= 2544 TALER_amount_add (&pc->pay_transaction.total_fees_paid, 2545 &pc->pay_transaction.total_fees_paid, 2546 deposit_fee)); 2547 dc->deposit_fee = *deposit_fee; 2548 dc->refund_fee = *refund_fee; 2549 dc->cdd.amount = *amount_with_fee; 2550 dc->found_in_db = true; 2551 pc->pay_transaction.pending--; 2552 } 2553 } 2554 2555 2556 /** 2557 * Function called with information about a refund. Check if this coin was 2558 * claimed by the wallet for the transaction, and if so add the refunded 2559 * amount to the pc's "total_refunded" amount. 2560 * 2561 * @param cls closure with a `struct PayContext` 2562 * @param coin_pub public coin from which the refund comes from 2563 * @param refund_amount refund amount which is being taken from @a coin_pub 2564 */ 2565 static void 2566 check_coin_refunded (void *cls, 2567 const struct TALER_CoinSpendPublicKeyP *coin_pub, 2568 const struct TALER_Amount *refund_amount) 2569 { 2570 struct PayContext *pc = cls; 2571 2572 /* We look at refunds here that apply to the coins 2573 that the customer is currently trying to pay us with. 2574 2575 Such refunds are not "normal" refunds, but abort-pay refunds, which are 2576 given in the case that the wallet aborts the payment. 2577 In the case the wallet then decides to complete the payment *after* doing 2578 an abort-pay refund (an unusual but possible case), we need 2579 to make sure that existing refunds are accounted for. */ 2580 2581 for (size_t i = 0; i<pc->parse_pay.coins_cnt; i++) 2582 { 2583 struct DepositConfirmation *dc = &pc->parse_pay.dc[i]; 2584 2585 /* Get matching coins from results. */ 2586 if (0 != GNUNET_memcmp (coin_pub, 2587 &dc->cdd.coin_pub)) 2588 continue; 2589 if (GNUNET_OK != 2590 TALER_amount_cmp_currency (&pc->pay_transaction.total_refunded, 2591 refund_amount)) 2592 { 2593 GNUNET_break (0); 2594 pc->pay_transaction.refund_currency_mismatch = true; 2595 break; 2596 } 2597 GNUNET_assert (0 <= 2598 TALER_amount_add (&pc->pay_transaction.total_refunded, 2599 &pc->pay_transaction.total_refunded, 2600 refund_amount)); 2601 break; 2602 } 2603 } 2604 2605 2606 /** 2607 * Check whether the amount paid is sufficient to cover the price. 2608 * 2609 * @param pc payment context to check 2610 * @return true if the payment is sufficient, false if it is 2611 * insufficient 2612 */ 2613 static bool 2614 check_payment_sufficient (struct PayContext *pc) 2615 { 2616 struct TALER_Amount acc_fee; 2617 struct TALER_Amount acc_amount; 2618 struct TALER_Amount final_amount; 2619 struct TALER_Amount total_wire_fee; 2620 struct TALER_Amount total_needed; 2621 2622 if (0 == pc->parse_pay.coins_cnt) 2623 return TALER_amount_is_zero (&pc->validate_tokens.brutto); 2624 GNUNET_assert (GNUNET_OK == 2625 TALER_amount_set_zero (pc->validate_tokens.brutto.currency, 2626 &total_wire_fee)); 2627 for (unsigned int i = 0; i < pc->parse_pay.num_exchanges; i++) 2628 { 2629 if (GNUNET_OK != 2630 TALER_amount_cmp_currency (&total_wire_fee, 2631 &pc->parse_pay.egs[i]->wire_fee)) 2632 { 2633 GNUNET_break_op (0); 2634 pay_end (pc, 2635 TALER_MHD_reply_with_error (pc->connection, 2636 MHD_HTTP_BAD_REQUEST, 2637 TALER_EC_GENERIC_CURRENCY_MISMATCH, 2638 total_wire_fee.currency)); 2639 return false; 2640 } 2641 if (0 > 2642 TALER_amount_add (&total_wire_fee, 2643 &total_wire_fee, 2644 &pc->parse_pay.egs[i]->wire_fee)) 2645 { 2646 GNUNET_break (0); 2647 pay_end (pc, 2648 TALER_MHD_reply_with_error ( 2649 pc->connection, 2650 MHD_HTTP_INTERNAL_SERVER_ERROR, 2651 TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_EXCHANGE_WIRE_FEE_ADDITION_FAILED, 2652 "could not add exchange wire fee to total")); 2653 return false; 2654 } 2655 } 2656 2657 /** 2658 * This loops calculates what are the deposit fee / total 2659 * amount with fee / and wire fee, for all the coins. 2660 */ 2661 GNUNET_assert (GNUNET_OK == 2662 TALER_amount_set_zero (pc->validate_tokens.brutto.currency, 2663 &acc_fee)); 2664 GNUNET_assert (GNUNET_OK == 2665 TALER_amount_set_zero (pc->validate_tokens.brutto.currency, 2666 &acc_amount)); 2667 for (size_t i = 0; i<pc->parse_pay.coins_cnt; i++) 2668 { 2669 struct DepositConfirmation *dc = &pc->parse_pay.dc[i]; 2670 2671 GNUNET_assert (dc->found_in_db); 2672 if ( (GNUNET_OK != 2673 TALER_amount_cmp_currency (&acc_fee, 2674 &dc->deposit_fee)) || 2675 (GNUNET_OK != 2676 TALER_amount_cmp_currency (&acc_amount, 2677 &dc->cdd.amount)) ) 2678 { 2679 GNUNET_break_op (0); 2680 pay_end (pc, 2681 TALER_MHD_reply_with_error ( 2682 pc->connection, 2683 MHD_HTTP_BAD_REQUEST, 2684 TALER_EC_GENERIC_CURRENCY_MISMATCH, 2685 dc->deposit_fee.currency)); 2686 return false; 2687 } 2688 if ( (0 > 2689 TALER_amount_add (&acc_fee, 2690 &dc->deposit_fee, 2691 &acc_fee)) || 2692 (0 > 2693 TALER_amount_add (&acc_amount, 2694 &dc->cdd.amount, 2695 &acc_amount)) ) 2696 { 2697 GNUNET_break (0); 2698 /* Overflow in these amounts? Very strange. */ 2699 pay_end (pc, 2700 TALER_MHD_reply_with_error ( 2701 pc->connection, 2702 MHD_HTTP_INTERNAL_SERVER_ERROR, 2703 TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_AMOUNT_OVERFLOW, 2704 "Overflow adding up amounts")); 2705 return false; 2706 } 2707 if (1 == 2708 TALER_amount_cmp (&dc->deposit_fee, 2709 &dc->cdd.amount)) 2710 { 2711 GNUNET_break_op (0); 2712 pay_end (pc, 2713 TALER_MHD_reply_with_error ( 2714 pc->connection, 2715 MHD_HTTP_BAD_REQUEST, 2716 TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_FEES_EXCEED_PAYMENT, 2717 "Deposit fees exceed coin's contribution")); 2718 return false; 2719 } 2720 } /* end deposit loop */ 2721 2722 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 2723 "Amount received from wallet: %s\n", 2724 TALER_amount2s (&acc_amount)); 2725 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 2726 "Deposit fee for all coins: %s\n", 2727 TALER_amount2s (&acc_fee)); 2728 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 2729 "Total wire fee: %s\n", 2730 TALER_amount2s (&total_wire_fee)); 2731 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 2732 "Deposit fee limit for merchant: %s\n", 2733 TALER_amount2s (&pc->validate_tokens.max_fee)); 2734 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 2735 "Total refunded amount: %s\n", 2736 TALER_amount2s (&pc->pay_transaction.total_refunded)); 2737 2738 /* Now compare exchange wire fee compared to what we are willing to pay */ 2739 if (GNUNET_YES != 2740 TALER_amount_cmp_currency (&total_wire_fee, 2741 &acc_fee)) 2742 { 2743 GNUNET_break (0); 2744 pay_end (pc, 2745 TALER_MHD_reply_with_error ( 2746 pc->connection, 2747 MHD_HTTP_BAD_REQUEST, 2748 TALER_EC_GENERIC_CURRENCY_MISMATCH, 2749 total_wire_fee.currency)); 2750 return false; 2751 } 2752 2753 /* add wire fee to the total fees */ 2754 if (0 > 2755 TALER_amount_add (&acc_fee, 2756 &acc_fee, 2757 &total_wire_fee)) 2758 { 2759 GNUNET_break (0); 2760 pay_end (pc, 2761 TALER_MHD_reply_with_error ( 2762 pc->connection, 2763 MHD_HTTP_INTERNAL_SERVER_ERROR, 2764 TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_AMOUNT_OVERFLOW, 2765 "Overflow adding up amounts")); 2766 return false; 2767 } 2768 if (-1 == TALER_amount_cmp (&pc->validate_tokens.max_fee, 2769 &acc_fee)) 2770 { 2771 /** 2772 * Sum of fees of *all* the different exchanges of all the coins are 2773 * higher than the fixed limit that the merchant is willing to pay. The 2774 * difference must be paid by the customer. 2775 */ 2776 struct TALER_Amount excess_fee; 2777 2778 /* compute fee amount to be covered by customer */ 2779 GNUNET_assert (TALER_AAR_RESULT_POSITIVE == 2780 TALER_amount_subtract (&excess_fee, 2781 &acc_fee, 2782 &pc->validate_tokens.max_fee)); 2783 /* add that to the total */ 2784 if (0 > 2785 TALER_amount_add (&total_needed, 2786 &excess_fee, 2787 &pc->validate_tokens.brutto)) 2788 { 2789 GNUNET_break (0); 2790 pay_end (pc, 2791 TALER_MHD_reply_with_error ( 2792 pc->connection, 2793 MHD_HTTP_INTERNAL_SERVER_ERROR, 2794 TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_AMOUNT_OVERFLOW, 2795 "Overflow adding up amounts")); 2796 return false; 2797 } 2798 } 2799 else 2800 { 2801 /* Fees are fully covered by the merchant, all we require 2802 is that the total payment is not below the contract's amount */ 2803 total_needed = pc->validate_tokens.brutto; 2804 } 2805 2806 /* Do not count refunds towards the payment */ 2807 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 2808 "Subtracting total refunds from paid amount: %s\n", 2809 TALER_amount2s (&pc->pay_transaction.total_refunded)); 2810 if (0 > 2811 TALER_amount_subtract (&final_amount, 2812 &acc_amount, 2813 &pc->pay_transaction.total_refunded)) 2814 { 2815 GNUNET_break (0); 2816 pay_end (pc, 2817 TALER_MHD_reply_with_error ( 2818 pc->connection, 2819 MHD_HTTP_INTERNAL_SERVER_ERROR, 2820 TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_REFUNDS_EXCEED_PAYMENTS, 2821 "refunded amount exceeds total payments")); 2822 return false; 2823 } 2824 2825 if (-1 == TALER_amount_cmp (&final_amount, 2826 &total_needed)) 2827 { 2828 /* acc_amount < total_needed */ 2829 if (-1 < TALER_amount_cmp (&acc_amount, 2830 &total_needed)) 2831 { 2832 GNUNET_break_op (0); 2833 pay_end (pc, 2834 TALER_MHD_reply_with_error ( 2835 pc->connection, 2836 MHD_HTTP_PAYMENT_REQUIRED, 2837 TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_REFUNDED, 2838 "contract not paid up due to refunds")); 2839 return false; 2840 } 2841 if (-1 < TALER_amount_cmp (&acc_amount, 2842 &pc->validate_tokens.brutto)) 2843 { 2844 GNUNET_break_op (0); 2845 pay_end (pc, 2846 TALER_MHD_reply_with_error ( 2847 pc->connection, 2848 MHD_HTTP_BAD_REQUEST, 2849 TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_INSUFFICIENT_DUE_TO_FEES, 2850 "contract not paid up due to fees (client may have calculated them badly)")); 2851 return false; 2852 } 2853 GNUNET_break_op (0); 2854 pay_end (pc, 2855 TALER_MHD_reply_with_error ( 2856 pc->connection, 2857 MHD_HTTP_BAD_REQUEST, 2858 TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_PAYMENT_INSUFFICIENT, 2859 "payment insufficient")); 2860 return false; 2861 } 2862 return true; 2863 } 2864 2865 2866 /** 2867 * Execute the DB transaction. If required (from 2868 * soft/serialization errors), the transaction can be 2869 * restarted here. 2870 * 2871 * @param[in,out] pc payment context to transact 2872 */ 2873 static void 2874 phase_execute_pay_transaction (struct PayContext *pc) 2875 { 2876 struct TMH_HandlerContext *hc = pc->hc; 2877 const char *instance_id = hc->instance->settings.id; 2878 2879 if (pc->batch_deposits.got_451) 2880 { 2881 pc->phase = PP_FAIL_LEGAL_REASONS; 2882 return; 2883 } 2884 /* Avoid re-trying transactions on soft errors forever! */ 2885 if (pc->pay_transaction.retry_counter++ > MAX_RETRIES) 2886 { 2887 GNUNET_break (0); 2888 pay_end (pc, 2889 TALER_MHD_reply_with_error (pc->connection, 2890 MHD_HTTP_INTERNAL_SERVER_ERROR, 2891 TALER_EC_GENERIC_DB_SOFT_FAILURE, 2892 NULL)); 2893 return; 2894 } 2895 2896 /* Initialize some amount accumulators 2897 (used in check_coin_paid(), check_coin_refunded() 2898 and check_payment_sufficient()). */ 2899 GNUNET_break (GNUNET_OK == 2900 TALER_amount_set_zero (pc->validate_tokens.brutto.currency, 2901 &pc->pay_transaction.total_paid)); 2902 GNUNET_break (GNUNET_OK == 2903 TALER_amount_set_zero (pc->validate_tokens.brutto.currency, 2904 &pc->pay_transaction.total_fees_paid)); 2905 GNUNET_break (GNUNET_OK == 2906 TALER_amount_set_zero (pc->validate_tokens.brutto.currency, 2907 &pc->pay_transaction.total_refunded)); 2908 for (size_t i = 0; i<pc->parse_pay.coins_cnt; i++) 2909 pc->parse_pay.dc[i].found_in_db = false; 2910 pc->pay_transaction.pending = pc->parse_pay.coins_cnt; 2911 2912 /* First, try to see if we have all we need already done */ 2913 TALER_MERCHANTDB_preflight (TMH_db); 2914 if (GNUNET_OK != 2915 TALER_MERCHANTDB_start (TMH_db, 2916 "run pay")) 2917 { 2918 GNUNET_break (0); 2919 pay_end (pc, 2920 TALER_MHD_reply_with_error (pc->connection, 2921 MHD_HTTP_INTERNAL_SERVER_ERROR, 2922 TALER_EC_GENERIC_DB_START_FAILED, 2923 NULL)); 2924 return; 2925 } 2926 2927 for (size_t i = 0; i<pc->parse_pay.tokens_cnt; i++) 2928 { 2929 struct TokenUseConfirmation *tuc = &pc->parse_pay.tokens[i]; 2930 enum GNUNET_DB_QueryStatus qs; 2931 2932 /* Insert used token into database, the unique constraint will 2933 case an error if this token was used before. */ 2934 qs = TALER_MERCHANTDB_insert_spent_token (TMH_db, 2935 &pc->check_contract.h_contract_terms, 2936 &tuc->h_issue, 2937 &tuc->pub, 2938 &tuc->sig, 2939 &tuc->unblinded_sig); 2940 2941 switch (qs) 2942 { 2943 case GNUNET_DB_STATUS_SOFT_ERROR: 2944 TALER_MERCHANTDB_rollback (TMH_db); 2945 return; /* do it again */ 2946 case GNUNET_DB_STATUS_HARD_ERROR: 2947 /* Always report on hard error as well to enable diagnostics */ 2948 TALER_MERCHANTDB_rollback (TMH_db); 2949 pay_end (pc, 2950 TALER_MHD_reply_with_error (pc->connection, 2951 MHD_HTTP_INTERNAL_SERVER_ERROR, 2952 TALER_EC_GENERIC_DB_STORE_FAILED, 2953 "insert used token")); 2954 return; 2955 case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS: 2956 /* UNIQUE constraint violation, meaning this token was already used. */ 2957 TALER_MERCHANTDB_rollback (TMH_db); 2958 pay_end (pc, 2959 TALER_MHD_reply_with_error (pc->connection, 2960 MHD_HTTP_CONFLICT, 2961 TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_TOKEN_INVALID, 2962 NULL)); 2963 return; 2964 case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT: 2965 /* Good, proceed! */ 2966 break; 2967 } 2968 } /* for all tokens */ 2969 2970 { 2971 enum GNUNET_DB_QueryStatus qs; 2972 2973 /* Check if some of these coins already succeeded for _this_ contract. */ 2974 qs = TALER_MERCHANTDB_lookup_deposits (TMH_db, 2975 instance_id, 2976 &pc->check_contract.h_contract_terms, 2977 &check_coin_paid, 2978 pc); 2979 if (0 > qs) 2980 { 2981 TALER_MERCHANTDB_rollback (TMH_db); 2982 if (GNUNET_DB_STATUS_SOFT_ERROR == qs) 2983 return; /* do it again */ 2984 /* Always report on hard error as well to enable diagnostics */ 2985 GNUNET_break (GNUNET_DB_STATUS_HARD_ERROR == qs); 2986 pay_end (pc, 2987 TALER_MHD_reply_with_error (pc->connection, 2988 MHD_HTTP_INTERNAL_SERVER_ERROR, 2989 TALER_EC_GENERIC_DB_FETCH_FAILED, 2990 "lookup deposits")); 2991 return; 2992 } 2993 if (pc->pay_transaction.deposit_currency_mismatch) 2994 { 2995 TALER_MERCHANTDB_rollback (TMH_db); 2996 GNUNET_break_op (0); 2997 pay_end (pc, 2998 TALER_MHD_reply_with_error ( 2999 pc->connection, 3000 MHD_HTTP_BAD_REQUEST, 3001 TALER_EC_MERCHANT_GENERIC_CURRENCY_MISMATCH, 3002 pc->validate_tokens.brutto.currency)); 3003 return; 3004 } 3005 } 3006 3007 { 3008 enum GNUNET_DB_QueryStatus qs; 3009 3010 /* Check if we refunded some of the coins */ 3011 qs = TALER_MERCHANTDB_lookup_refunds (TMH_db, 3012 instance_id, 3013 &pc->check_contract.h_contract_terms, 3014 &check_coin_refunded, 3015 pc); 3016 if (0 > qs) 3017 { 3018 TALER_MERCHANTDB_rollback (TMH_db); 3019 if (GNUNET_DB_STATUS_SOFT_ERROR == qs) 3020 return; /* do it again */ 3021 /* Always report on hard error as well to enable diagnostics */ 3022 GNUNET_break (GNUNET_DB_STATUS_HARD_ERROR == qs); 3023 pay_end (pc, 3024 TALER_MHD_reply_with_error (pc->connection, 3025 MHD_HTTP_INTERNAL_SERVER_ERROR, 3026 TALER_EC_GENERIC_DB_FETCH_FAILED, 3027 "lookup refunds")); 3028 return; 3029 } 3030 if (pc->pay_transaction.refund_currency_mismatch) 3031 { 3032 TALER_MERCHANTDB_rollback (TMH_db); 3033 pay_end (pc, 3034 TALER_MHD_reply_with_error (pc->connection, 3035 MHD_HTTP_INTERNAL_SERVER_ERROR, 3036 TALER_EC_GENERIC_DB_FETCH_FAILED, 3037 "refund currency in database does not match order currency")); 3038 return; 3039 } 3040 } 3041 3042 /* Check if there are coins that still need to be processed */ 3043 if (0 != pc->pay_transaction.pending) 3044 { 3045 /* we made no DB changes, so we can just rollback */ 3046 TALER_MERCHANTDB_rollback (TMH_db); 3047 /* Ok, we need to first go to the network to process more coins. 3048 We that interaction in *tiny* transactions (hence the rollback 3049 above). */ 3050 pc->phase = PP_BATCH_DEPOSITS; 3051 return; 3052 } 3053 3054 /* 0 == pc->pay_transaction.pending: all coins processed, let's see if that was enough */ 3055 if (! check_payment_sufficient (pc)) 3056 { 3057 /* check_payment_sufficient() will have queued an error already. 3058 We need to still abort the transaction. */ 3059 TALER_MERCHANTDB_rollback (TMH_db); 3060 return; 3061 } 3062 /* Payment succeeded, save in database */ 3063 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 3064 "Order `%s' (%s) was fully paid\n", 3065 pc->order_id, 3066 GNUNET_h2s (&pc->check_contract.h_contract_terms.hash)); 3067 { 3068 enum GNUNET_DB_QueryStatus qs; 3069 3070 qs = TALER_MERCHANTDB_mark_contract_paid (TMH_db, 3071 instance_id, 3072 &pc->check_contract.h_contract_terms, 3073 pc->parse_pay.session_id, 3074 pc->parse_wallet_data.choice_index); 3075 if (qs < 0) 3076 { 3077 TALER_MERCHANTDB_rollback (TMH_db); 3078 if (GNUNET_DB_STATUS_SOFT_ERROR == qs) 3079 return; /* do it again */ 3080 GNUNET_break (0); 3081 pay_end (pc, 3082 TALER_MHD_reply_with_error (pc->connection, 3083 MHD_HTTP_INTERNAL_SERVER_ERROR, 3084 TALER_EC_GENERIC_DB_STORE_FAILED, 3085 "mark contract paid")); 3086 return; 3087 } 3088 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 3089 "Marked contract paid returned %d\n", 3090 (int) qs); 3091 3092 if ( (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT == qs) && 3093 (0 < pc->compute_money_pots.num_pots) ) 3094 { 3095 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 3096 "Incrementing %u money pots by %s\n", 3097 pc->compute_money_pots.num_pots, 3098 TALER_amount2s (&pc->compute_money_pots.increments[0])); 3099 qs = TALER_MERCHANTDB_increment_money_pots (TMH_db, 3100 instance_id, 3101 pc->compute_money_pots.num_pots, 3102 pc->compute_money_pots.pots, 3103 pc->compute_money_pots.increments); 3104 switch (qs) 3105 { 3106 case GNUNET_DB_STATUS_SOFT_ERROR: 3107 TALER_MERCHANTDB_rollback (TMH_db); 3108 return; /* do it again */ 3109 case GNUNET_DB_STATUS_HARD_ERROR: 3110 /* Always report on hard error as well to enable diagnostics */ 3111 TALER_MERCHANTDB_rollback (TMH_db); 3112 pay_end (pc, 3113 TALER_MHD_reply_with_error (pc->connection, 3114 MHD_HTTP_INTERNAL_SERVER_ERROR, 3115 TALER_EC_GENERIC_DB_STORE_FAILED, 3116 "increment_money_pots")); 3117 return; 3118 case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS: 3119 /* strange */ 3120 GNUNET_break (0); 3121 break; 3122 case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT: 3123 /* Good, proceed! */ 3124 break; 3125 } 3126 3127 } 3128 3129 3130 } 3131 3132 3133 { 3134 const struct TALER_MERCHANT_ContractChoice *choice = 3135 &pc->check_contract.contract_terms->pc->details.v1 3136 .choices[pc->parse_wallet_data.choice_index]; 3137 3138 for (size_t i = 0; i<pc->output_tokens_len; i++) 3139 { 3140 unsigned int output_index; 3141 enum TALER_MERCHANT_ContractOutputType type; 3142 3143 output_index = pc->output_tokens[i].output_index; 3144 GNUNET_assert (output_index < choice->outputs_len); 3145 type = choice->outputs[output_index].type; 3146 3147 switch (type) 3148 { 3149 case TALER_MERCHANT_CONTRACT_OUTPUT_TYPE_INVALID: 3150 /* Well, good luck getting here */ 3151 GNUNET_break (0); 3152 pay_end (pc, 3153 TALER_MHD_reply_with_error (pc->connection, 3154 MHD_HTTP_INTERNAL_SERVER_ERROR, 3155 TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE, 3156 "invalid output type")); 3157 break; 3158 case TALER_MERCHANT_CONTRACT_OUTPUT_TYPE_DONATION_RECEIPT: 3159 /* We skip output tokens of donation receipts here, as they are handled in the 3160 * phase_final_output_token_processing() callback from donau */ 3161 break; 3162 case TALER_MERCHANT_CONTRACT_OUTPUT_TYPE_TOKEN: 3163 struct SignedOutputToken *output = 3164 &pc->output_tokens[i]; 3165 enum GNUNET_DB_QueryStatus qs; 3166 3167 qs = TALER_MERCHANTDB_insert_issued_token (TMH_db, 3168 &pc->check_contract.h_contract_terms, 3169 &output->h_issue, 3170 &output->sig); 3171 switch (qs) 3172 { 3173 case GNUNET_DB_STATUS_HARD_ERROR: 3174 TALER_MERCHANTDB_rollback (TMH_db); 3175 GNUNET_break (GNUNET_DB_STATUS_HARD_ERROR == qs); 3176 pay_end (pc, 3177 TALER_MHD_reply_with_error (pc->connection, 3178 MHD_HTTP_INTERNAL_SERVER_ERROR, 3179 TALER_EC_GENERIC_DB_STORE_FAILED, 3180 "insert output token")); 3181 return; 3182 case GNUNET_DB_STATUS_SOFT_ERROR: 3183 /* Serialization failure, retry */ 3184 TALER_MERCHANTDB_rollback (TMH_db); 3185 return; 3186 case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS: 3187 /* UNIQUE constraint violation, meaning this token was already used. */ 3188 TALER_MERCHANTDB_rollback (TMH_db); 3189 pay_end (pc, 3190 TALER_MHD_reply_with_error (pc->connection, 3191 MHD_HTTP_INTERNAL_SERVER_ERROR, 3192 TALER_EC_GENERIC_DB_STORE_FAILED, 3193 "duplicate output token")); 3194 return; 3195 case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT: 3196 break; 3197 } 3198 break; 3199 } 3200 } 3201 } 3202 3203 TMH_notify_order_change ( 3204 hc->instance, 3205 TMH_OSF_CLAIMED | TMH_OSF_PAID, 3206 pc->check_contract.contract_terms->pc->timestamp, 3207 pc->check_contract.order_serial); 3208 { 3209 enum GNUNET_DB_QueryStatus qs; 3210 json_t *jhook; 3211 3212 jhook = GNUNET_JSON_PACK ( 3213 GNUNET_JSON_pack_object_incref ("contract_terms", 3214 pc->check_contract.contract_terms_json), 3215 GNUNET_JSON_pack_string ("order_id", 3216 pc->order_id) 3217 ); 3218 GNUNET_assert (NULL != jhook); 3219 qs = TMH_trigger_webhook (pc->hc->instance->settings.id, 3220 "pay", 3221 jhook); 3222 json_decref (jhook); 3223 if (qs < 0) 3224 { 3225 TALER_MERCHANTDB_rollback (TMH_db); 3226 if (GNUNET_DB_STATUS_SOFT_ERROR == qs) 3227 return; /* do it again */ 3228 GNUNET_break (0); 3229 pay_end (pc, 3230 TALER_MHD_reply_with_error (pc->connection, 3231 MHD_HTTP_INTERNAL_SERVER_ERROR, 3232 TALER_EC_GENERIC_DB_STORE_FAILED, 3233 "failed to trigger webhooks")); 3234 return; 3235 } 3236 } 3237 { 3238 enum GNUNET_DB_QueryStatus qs; 3239 3240 /* Now commit! */ 3241 qs = TALER_MERCHANTDB_commit (TMH_db); 3242 if (0 > qs) 3243 { 3244 /* commit failed */ 3245 TALER_MERCHANTDB_rollback (TMH_db); 3246 if (GNUNET_DB_STATUS_SOFT_ERROR == qs) 3247 return; /* do it again */ 3248 GNUNET_break (0); 3249 pay_end (pc, 3250 TALER_MHD_reply_with_error (pc->connection, 3251 MHD_HTTP_INTERNAL_SERVER_ERROR, 3252 TALER_EC_GENERIC_DB_COMMIT_FAILED, 3253 NULL)); 3254 return; 3255 } 3256 } 3257 pc->phase++; 3258 } 3259 3260 3261 /** 3262 * Ensures that the expected number of tokens for a @e key 3263 * are provided as inputs and have valid signatures. 3264 * 3265 * @param[in,out] pc payment context we are processing 3266 * @param family family the tokens should be from 3267 * @param index number of the input we are handling 3268 * @param expected_num number of tokens expected 3269 * @return #GNUNET_YES on success 3270 */ 3271 static enum GNUNET_GenericReturnValue 3272 find_valid_input_tokens ( 3273 struct PayContext *pc, 3274 const struct TALER_MERCHANT_ContractTokenFamily *family, 3275 unsigned int index, 3276 unsigned int expected_num) 3277 { 3278 unsigned int num_validated = 0; 3279 struct GNUNET_TIME_Timestamp now 3280 = GNUNET_TIME_timestamp_get (); 3281 const struct TALER_MERCHANT_ContractTokenFamilyKey *kig = NULL; 3282 3283 for (unsigned int j = 0; j < expected_num; j++) 3284 { 3285 struct TokenUseConfirmation *tuc 3286 = &pc->parse_pay.tokens[index + j]; 3287 const struct TALER_MERCHANT_ContractTokenFamilyKey *key = NULL; 3288 3289 for (unsigned int i = 0; i<family->keys_len; i++) 3290 { 3291 const struct TALER_MERCHANT_ContractTokenFamilyKey *ki 3292 = &family->keys[i]; 3293 3294 if (0 == 3295 GNUNET_memcmp (&ki->pub.public_key->pub_key_hash, 3296 &tuc->h_issue.hash)) 3297 { 3298 if (GNUNET_TIME_timestamp_cmp (ki->valid_after, 3299 >, 3300 now) || 3301 GNUNET_TIME_timestamp_cmp (ki->valid_before, 3302 <=, 3303 now)) 3304 { 3305 /* We have a match, but not in the current validity period */ 3306 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 3307 "Public key %s currently not valid\n", 3308 GNUNET_h2s (&ki->pub.public_key->pub_key_hash)); 3309 kig = ki; 3310 continue; 3311 } 3312 key = ki; 3313 break; 3314 } 3315 } 3316 if (NULL == key) 3317 { 3318 if (NULL != kig) 3319 { 3320 char start_str[128]; 3321 char end_str[128]; 3322 char emsg[350]; 3323 3324 GNUNET_snprintf (start_str, 3325 sizeof (start_str), 3326 "%s", 3327 GNUNET_STRINGS_timestamp_to_string (kig->valid_after)); 3328 GNUNET_snprintf (end_str, 3329 sizeof (end_str), 3330 "%s", 3331 GNUNET_STRINGS_timestamp_to_string (kig->valid_before)) 3332 ; 3333 /* FIXME: use more specific EC */ 3334 GNUNET_snprintf (emsg, 3335 sizeof (emsg), 3336 "Token is only valid from %s to %s", 3337 start_str, 3338 end_str); 3339 pay_end (pc, 3340 TALER_MHD_reply_with_error ( 3341 pc->connection, 3342 MHD_HTTP_GONE, 3343 TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_OFFER_EXPIRED, 3344 emsg)); 3345 return GNUNET_NO; 3346 } 3347 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 3348 "Input token supplied for public key %s that is not acceptable\n", 3349 GNUNET_h2s (&tuc->h_issue.hash)); 3350 GNUNET_break_op (0); 3351 pay_end (pc, 3352 TALER_MHD_reply_with_error ( 3353 pc->connection, 3354 MHD_HTTP_BAD_REQUEST, 3355 TALER_EC_MERCHANT_GENERIC_TOKEN_KEY_UNKNOWN, 3356 NULL)); 3357 return GNUNET_NO; 3358 } 3359 if (GNUNET_OK != 3360 TALER_token_issue_verify (&tuc->pub, 3361 &key->pub, 3362 &tuc->unblinded_sig)) 3363 { 3364 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 3365 "Input token for public key with valid_after " 3366 "`%s' has invalid issue signature\n", 3367 GNUNET_TIME_timestamp2s (key->valid_after)); 3368 GNUNET_break (0); 3369 pay_end (pc, 3370 TALER_MHD_reply_with_error ( 3371 pc->connection, 3372 MHD_HTTP_BAD_REQUEST, 3373 TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_TOKEN_ISSUE_SIG_INVALID, 3374 NULL)); 3375 return GNUNET_NO; 3376 } 3377 3378 if (GNUNET_OK != 3379 TALER_wallet_token_use_verify (&pc->check_contract.h_contract_terms, 3380 &pc->parse_wallet_data.h_wallet_data, 3381 &tuc->pub, 3382 &tuc->sig)) 3383 { 3384 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 3385 "Input token for public key with valid_before " 3386 "`%s' has invalid use signature\n", 3387 GNUNET_TIME_timestamp2s (key->valid_before)); 3388 GNUNET_break (0); 3389 pay_end (pc, 3390 TALER_MHD_reply_with_error ( 3391 pc->connection, 3392 MHD_HTTP_BAD_REQUEST, 3393 TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_TOKEN_USE_SIG_INVALID, 3394 NULL)); 3395 return GNUNET_NO; 3396 } 3397 3398 num_validated++; 3399 } 3400 3401 if (num_validated != expected_num) 3402 { 3403 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 3404 "Expected %d tokens for family %s, but found %d\n", 3405 expected_num, 3406 family->slug, 3407 num_validated); 3408 GNUNET_break (0); 3409 pay_end (pc, 3410 TALER_MHD_reply_with_error ( 3411 pc->connection, 3412 MHD_HTTP_BAD_REQUEST, 3413 TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_TOKEN_COUNT_MISMATCH, 3414 NULL)); 3415 return GNUNET_NO; 3416 } 3417 return GNUNET_YES; 3418 } 3419 3420 3421 /** 3422 * Check if an output token of the given @a tfk is mandatory, or if 3423 * wallets are allowed to simply not support it and still proceed. 3424 * 3425 * @param tfk token family kind to check 3426 * @return true if such outputs are mandatory and wallets must supply 3427 * the corresponding blinded input 3428 */ 3429 /* FIXME: this function belongs into a lower-level lib! */ 3430 static bool 3431 test_tfk_mandatory (enum TALER_MERCHANTDB_TokenFamilyKind tfk) 3432 { 3433 switch (tfk) 3434 { 3435 case TALER_MERCHANTDB_TFK_Discount: 3436 return false; 3437 case TALER_MERCHANTDB_TFK_Subscription: 3438 return true; 3439 } 3440 GNUNET_break (0); 3441 return false; 3442 } 3443 3444 3445 /** 3446 * Sign the tokens provided by the wallet for a particular @a key. 3447 * 3448 * @param[in,out] pc reference for payment we are processing 3449 * @param key token family data 3450 * @param priv private key to use to sign with 3451 * @param mandatory true if the token must exist, if false 3452 * and the client did not provide an envelope, that's OK and 3453 * we just also skimp on the signature 3454 * @param index offset in the token envelope array (from other families) 3455 * @param expected_num number of tokens of this type that we should create 3456 * @return #GNUNET_NO on failure 3457 * #GNUNET_OK on success 3458 */ 3459 static enum GNUNET_GenericReturnValue 3460 sign_token_envelopes ( 3461 struct PayContext *pc, 3462 const struct TALER_MERCHANT_ContractTokenFamilyKey *key, 3463 const struct TALER_TokenIssuePrivateKey *priv, 3464 bool mandatory, 3465 unsigned int index, 3466 unsigned int expected_num) 3467 { 3468 unsigned int num_signed = 0; 3469 3470 for (unsigned int j = 0; j<expected_num; j++) 3471 { 3472 unsigned int pos = index + j; 3473 const struct TokenEnvelope *env 3474 = &pc->parse_wallet_data.token_envelopes[pos]; 3475 struct SignedOutputToken *output 3476 = &pc->output_tokens[pos]; 3477 3478 if ( (pos >= pc->parse_wallet_data.token_envelopes_cnt) || 3479 (pos >= pc->output_tokens_len) ) 3480 { 3481 GNUNET_assert (0); /* this should not happen */ 3482 return GNUNET_NO; 3483 } 3484 if (NULL == env->blinded_token.blinded_pub) 3485 { 3486 if (! mandatory) 3487 continue; 3488 3489 /* mandatory token families require a token envelope. */ 3490 GNUNET_break_op (0); 3491 pay_end (pc, 3492 TALER_MHD_reply_with_error ( 3493 pc->connection, 3494 MHD_HTTP_BAD_REQUEST, 3495 TALER_EC_GENERIC_PARAMETER_MALFORMED, 3496 "Token envelope for mandatory token family missing")); 3497 return GNUNET_NO; 3498 } 3499 TALER_token_issue_sign (priv, 3500 &env->blinded_token, 3501 &output->sig); 3502 output->h_issue.hash 3503 = key->pub.public_key->pub_key_hash; 3504 num_signed++; 3505 } 3506 3507 if (mandatory && 3508 (num_signed != expected_num) ) 3509 { 3510 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 3511 "Expected %d token envelopes for public key with valid_after " 3512 "'%s', but found %d\n", 3513 expected_num, 3514 GNUNET_TIME_timestamp2s (key->valid_after), 3515 num_signed); 3516 GNUNET_break (0); 3517 pay_end (pc, 3518 TALER_MHD_reply_with_error ( 3519 pc->connection, 3520 MHD_HTTP_BAD_REQUEST, 3521 TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_TOKEN_ENVELOPE_COUNT_MISMATCH, 3522 NULL)); 3523 return GNUNET_NO; 3524 } 3525 3526 return GNUNET_OK; 3527 } 3528 3529 3530 /** 3531 * Find the family entry for the family of the given @a slug 3532 * in @a pc. 3533 * 3534 * @param[in] pc payment context to search 3535 * @param slug slug to search for 3536 * @return NULL if @a slug was not found 3537 */ 3538 static const struct TALER_MERCHANT_ContractTokenFamily * 3539 find_family (const struct PayContext *pc, 3540 const char *slug) 3541 { 3542 for (unsigned int i = 0; 3543 i < pc->check_contract.contract_terms->pc->details.v1.token_authorities_len; 3544 i++) 3545 { 3546 const struct TALER_MERCHANT_ContractTokenFamily *tfi 3547 = &pc->check_contract.contract_terms->pc->details.v1.token_authorities[i]; 3548 3549 if (0 == strcmp (tfi->slug, 3550 slug)) 3551 { 3552 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 3553 "Token family %s found with %u keys\n", 3554 slug, 3555 tfi->keys_len); 3556 return tfi; 3557 } 3558 } 3559 return NULL; 3560 } 3561 3562 3563 /** 3564 * Handle contract output of type TALER_MERCHANT_CONTRACT_OUTPUT_TYPE_TOKEN. 3565 * Looks up the token family, loads the matching private key, 3566 * and signs the corresponding token envelopes from the wallet. 3567 * 3568 * @param pc context for the pay request 3569 * @param output contract output we need to process 3570 * @param output_index index of this output in the contract's outputs array 3571 * @return #GNUNET_OK on success, #GNUNET_NO if an error was encountered 3572 */ 3573 static enum GNUNET_GenericReturnValue 3574 handle_output_token (struct PayContext *pc, 3575 const struct TALER_MERCHANT_ContractOutput *output, 3576 unsigned int output_index) 3577 { 3578 const struct TALER_MERCHANT_ContractTokenFamily *family; 3579 struct TALER_MERCHANT_ContractTokenFamilyKey *key; 3580 struct TALER_MERCHANTDB_TokenFamilyKeyDetails details; 3581 enum GNUNET_DB_QueryStatus qs; 3582 bool mandatory; 3583 3584 /* Locate token family in the contract. 3585 This should ever fail as this invariant should 3586 have been checked when the contract was created. */ 3587 family = find_family (pc, 3588 output->details.token.token_family_slug); 3589 if (NULL == family) 3590 { 3591 /* This "should never happen", so treat it as an internal error */ 3592 GNUNET_break (0); 3593 pay_end (pc, 3594 TALER_MHD_reply_with_error ( 3595 pc->connection, 3596 MHD_HTTP_INTERNAL_SERVER_ERROR, 3597 TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE, 3598 "token family not found in order")); 3599 return GNUNET_SYSERR; 3600 } 3601 3602 /* Check the key_index field from the output. */ 3603 if (output->details.token.key_index >= family->keys_len) 3604 { 3605 /* Also "should never happen", contract was presumably validated on insert */ 3606 GNUNET_break (0); 3607 pay_end (pc, 3608 TALER_MHD_reply_with_error ( 3609 pc->connection, 3610 MHD_HTTP_INTERNAL_SERVER_ERROR, 3611 TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE, 3612 "key index invalid for token family")); 3613 return GNUNET_SYSERR; 3614 } 3615 3616 /* Pick the correct key inside that family. */ 3617 key = &family->keys[output->details.token.key_index]; 3618 3619 /* Fetch the private key from the DB for the merchant instance and 3620 * this particular family/time interval. */ 3621 qs = TALER_MERCHANTDB_lookup_token_family_key ( 3622 TMH_db, 3623 pc->hc->instance->settings.id, 3624 family->slug, 3625 pc->check_contract.contract_terms->pc->timestamp, 3626 pc->check_contract.contract_terms->pc->pay_deadline, 3627 &details); 3628 switch (qs) 3629 { 3630 case GNUNET_DB_STATUS_HARD_ERROR: 3631 case GNUNET_DB_STATUS_SOFT_ERROR: 3632 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 3633 "Database error looking up token-family key for %s\n", 3634 family->slug); 3635 GNUNET_break (0); 3636 pay_end (pc, 3637 TALER_MHD_reply_with_error ( 3638 pc->connection, 3639 MHD_HTTP_INTERNAL_SERVER_ERROR, 3640 TALER_EC_GENERIC_DB_FETCH_FAILED, 3641 NULL)); 3642 return GNUNET_NO; 3643 case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS: 3644 GNUNET_log ( 3645 GNUNET_ERROR_TYPE_ERROR, 3646 "Token-family key for %s not found at [%llu,%llu]\n", 3647 family->slug, 3648 (unsigned long long) 3649 pc->check_contract.contract_terms->pc->timestamp.abs_time.abs_value_us, 3650 (unsigned long long) 3651 pc->check_contract.contract_terms->pc->pay_deadline.abs_time.abs_value_us 3652 ); 3653 GNUNET_break (0); 3654 pay_end (pc, 3655 TALER_MHD_reply_with_error ( 3656 pc->connection, 3657 MHD_HTTP_NOT_FOUND, 3658 TALER_EC_MERCHANT_GENERIC_TOKEN_KEY_UNKNOWN, 3659 family->slug)); 3660 return GNUNET_NO; 3661 3662 case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT: 3663 break; 3664 } 3665 GNUNET_assert (NULL != details.priv.private_key); 3666 GNUNET_free (details.token_family.slug); 3667 GNUNET_free (details.token_family.name); 3668 GNUNET_free (details.token_family.description); 3669 json_decref (details.token_family.description_i18n); 3670 GNUNET_CRYPTO_blind_sign_pub_decref (details.pub.public_key); 3671 GNUNET_free (details.token_family.cipher_spec); 3672 3673 /* Depending on the token family, decide if the token envelope 3674 * is mandatory or optional. (Simplified logic here: adapt as needed.) */ 3675 mandatory = test_tfk_mandatory (details.token_family.kind); 3676 /* Actually sign the number of token envelopes specified in 'count'. 3677 * 'output_index' is the offset into the parse_wallet_data arrays. */ 3678 if (GNUNET_OK != 3679 sign_token_envelopes (pc, 3680 key, 3681 &details.priv, 3682 mandatory, 3683 output_index, 3684 output->details.token.count)) 3685 { 3686 /* sign_token_envelopes() already queued up an error via pay_end() */ 3687 GNUNET_break_op (0); 3688 return GNUNET_NO; 3689 } 3690 GNUNET_CRYPTO_blind_sign_priv_decref (details.priv.private_key); 3691 return GNUNET_OK; 3692 } 3693 3694 3695 /** 3696 * Handle checks for contract output of type TALER_MERCHANT_CONTRACT_OUTPUT_TYPE_DONATION_RECEIPT. 3697 * For now, this does nothing and simply returns #GNUNET_OK. 3698 * 3699 * @param pc context for the pay request 3700 * @param output the contract output describing the donation receipt requirement 3701 * @return #GNUNET_OK on success, 3702 * #GNUNET_NO if an error was already queued 3703 */ 3704 static enum GNUNET_GenericReturnValue 3705 handle_output_donation_receipt ( 3706 struct PayContext *pc, 3707 const struct TALER_MERCHANT_ContractOutput *output) 3708 { 3709 enum GNUNET_GenericReturnValue ret; 3710 3711 ret = DONAU_get_donation_amount_from_bkps ( 3712 pc->parse_wallet_data.donau_keys, 3713 pc->parse_wallet_data.bkps, 3714 pc->parse_wallet_data.num_bkps, 3715 pc->parse_wallet_data.donau.donation_year, 3716 &pc->parse_wallet_data.donation_amount); 3717 switch (ret) 3718 { 3719 case GNUNET_SYSERR: 3720 GNUNET_break (0); 3721 pay_end (pc, 3722 TALER_MHD_reply_with_error ( 3723 pc->connection, 3724 MHD_HTTP_INTERNAL_SERVER_ERROR, 3725 TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE, 3726 NULL)); 3727 return GNUNET_NO; 3728 case GNUNET_NO: 3729 GNUNET_break_op (0); 3730 pay_end (pc, 3731 TALER_MHD_reply_with_error ( 3732 pc->connection, 3733 MHD_HTTP_BAD_REQUEST, 3734 TALER_EC_GENERIC_PARAMETER_MALFORMED, 3735 "inconsistent bkps / donau keys")); 3736 return GNUNET_NO; 3737 case GNUNET_OK: 3738 break; 3739 } 3740 3741 if (GNUNET_OK != 3742 TALER_amount_cmp_currency (&pc->parse_wallet_data.donation_amount, 3743 &output->details.donation_receipt.amount)) 3744 { 3745 GNUNET_break_op (0); 3746 pay_end (pc, 3747 TALER_MHD_reply_with_error ( 3748 pc->connection, 3749 MHD_HTTP_BAD_REQUEST, 3750 TALER_EC_GENERIC_CURRENCY_MISMATCH, 3751 output->details.donation_receipt.amount.currency)); 3752 return GNUNET_NO; 3753 } 3754 3755 if (0 != 3756 TALER_amount_cmp (&pc->parse_wallet_data.donation_amount, 3757 &output->details.donation_receipt.amount)) 3758 { 3759 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 3760 "Wallet amount: %s\n", 3761 TALER_amount2s (&pc->parse_wallet_data.donation_amount)); 3762 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 3763 "Donation receipt amount: %s\n", 3764 TALER_amount2s (&output->details.donation_receipt.amount)); 3765 GNUNET_break_op (0); 3766 pay_end (pc, 3767 TALER_MHD_reply_with_error ( 3768 pc->connection, 3769 MHD_HTTP_CONFLICT, 3770 TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_DONATION_AMOUNT_MISMATCH, 3771 "donation amount mismatch")); 3772 return GNUNET_NO; 3773 } 3774 { 3775 struct TALER_Amount receipts_to_date; 3776 3777 if (0 > 3778 TALER_amount_add (&receipts_to_date, 3779 &pc->parse_wallet_data.charity_receipts_to_date, 3780 &pc->parse_wallet_data.donation_amount)) 3781 { 3782 GNUNET_break (0); 3783 pay_end (pc, 3784 TALER_MHD_reply_with_error (pc->connection, 3785 MHD_HTTP_INTERNAL_SERVER_ERROR, 3786 TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_AMOUNT_OVERFLOW, 3787 "adding donation amount")); 3788 return GNUNET_NO; 3789 } 3790 3791 if (1 == 3792 TALER_amount_cmp (&receipts_to_date, 3793 &pc->parse_wallet_data.charity_max_per_year)) 3794 { 3795 GNUNET_break_op (0); 3796 pay_end (pc, 3797 TALER_MHD_reply_with_error (pc->connection, 3798 MHD_HTTP_CONFLICT, 3799 TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_DONATION_AMOUNT_MISMATCH, 3800 "donation limit exceeded")); 3801 return GNUNET_NO; 3802 } 3803 pc->parse_wallet_data.charity_receipts_to_date = receipts_to_date; 3804 } 3805 return GNUNET_OK; 3806 } 3807 3808 3809 /** 3810 * Count tokens produced by an output. 3811 * 3812 * @param pc pay context 3813 * @param output output to consider 3814 * @returns number of output tokens 3815 */ 3816 static unsigned int 3817 count_output_tokens (const struct PayContext *pc, 3818 const struct TALER_MERCHANT_ContractOutput *output) 3819 { 3820 switch (output->type) 3821 { 3822 case TALER_MERCHANT_CONTRACT_OUTPUT_TYPE_INVALID: 3823 GNUNET_assert (0); 3824 break; 3825 case TALER_MERCHANT_CONTRACT_OUTPUT_TYPE_TOKEN: 3826 return output->details.token.count; 3827 case TALER_MERCHANT_CONTRACT_OUTPUT_TYPE_DONATION_RECEIPT: 3828 return pc->parse_wallet_data.num_bkps; 3829 } 3830 /* Not reached. */ 3831 GNUNET_assert (0); 3832 } 3833 3834 3835 /** 3836 * Validate tokens and token envelopes. First, we check if all tokens listed 3837 * in the 'inputs' array of the selected choice are present in the 'tokens' 3838 * array of the request. Then, we validate the signatures of each provided 3839 * token. 3840 * 3841 * @param[in,out] pc context we use to handle the payment 3842 */ 3843 static void 3844 phase_validate_tokens (struct PayContext *pc) 3845 { 3846 /* We haven't seen a donau output yet. */ 3847 pc->validate_tokens.donau_output_index = -1; 3848 3849 switch (pc->check_contract.contract_terms->pc->base->version) 3850 { 3851 case TALER_MERCHANT_CONTRACT_VERSION_0: 3852 /* No tokens to validate */ 3853 pc->phase = PP_COMPUTE_MONEY_POTS; 3854 pc->validate_tokens.max_fee 3855 = pc->check_contract.contract_terms->pc->details.v0.max_fee; 3856 pc->validate_tokens.brutto 3857 = pc->check_contract.contract_terms->pc->details.v0.brutto; 3858 break; 3859 case TALER_MERCHANT_CONTRACT_VERSION_1: 3860 { 3861 const struct TALER_MERCHANT_ContractChoice *selected 3862 = &pc->check_contract.contract_terms->pc->details.v1.choices[ 3863 pc->parse_wallet_data.choice_index]; 3864 unsigned int output_off; 3865 unsigned int cnt; 3866 3867 pc->validate_tokens.max_fee = selected->max_fee; 3868 pc->validate_tokens.brutto = selected->amount; 3869 3870 for (unsigned int i = 0; i<selected->inputs_len; i++) 3871 { 3872 const struct TALER_MERCHANT_ContractInput *input 3873 = &selected->inputs[i]; 3874 const struct TALER_MERCHANT_ContractTokenFamily *family; 3875 3876 switch (input->type) 3877 { 3878 case TALER_MERCHANT_CONTRACT_INPUT_TYPE_INVALID: 3879 GNUNET_break (0); 3880 pay_end (pc, 3881 TALER_MHD_reply_with_error ( 3882 pc->connection, 3883 MHD_HTTP_BAD_REQUEST, 3884 TALER_EC_GENERIC_PARAMETER_MALFORMED, 3885 "input token type not valid")); 3886 return; 3887 #if FUTURE 3888 case TALER_MERCHANT_CONTRACT_INPUT_TYPE_COIN: 3889 GNUNET_break (0); 3890 pay_end (pc, 3891 TALER_MHD_reply_with_error ( 3892 pc->connection, 3893 MHD_HTTP_NOT_IMPLEMENTED, 3894 TALER_EC_MERCHANT_GENERIC_FEATURE_NOT_AVAILABLE, 3895 "token type not yet supported")); 3896 return; 3897 #endif 3898 case TALER_MERCHANT_CONTRACT_INPUT_TYPE_TOKEN: 3899 family = find_family (pc, 3900 input->details.token.token_family_slug); 3901 if (NULL == family) 3902 { 3903 /* this should never happen, since the choices and 3904 token families are validated on insert. */ 3905 GNUNET_break (0); 3906 pay_end (pc, 3907 TALER_MHD_reply_with_error ( 3908 pc->connection, 3909 MHD_HTTP_INTERNAL_SERVER_ERROR, 3910 TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE, 3911 "token family not found in order")); 3912 return; 3913 } 3914 if (GNUNET_NO == 3915 find_valid_input_tokens (pc, 3916 family, 3917 i, 3918 input->details.token.count)) 3919 { 3920 /* Error is already scheduled from find_valid_input_token. */ 3921 return; 3922 } 3923 } 3924 } 3925 3926 /* calculate pc->output_tokens_len */ 3927 output_off = 0; 3928 for (unsigned int i = 0; i<selected->outputs_len; i++) 3929 { 3930 const struct TALER_MERCHANT_ContractOutput *output 3931 = &selected->outputs[i]; 3932 3933 switch (output->type) 3934 { 3935 case TALER_MERCHANT_CONTRACT_OUTPUT_TYPE_INVALID: 3936 GNUNET_assert (0); 3937 break; 3938 case TALER_MERCHANT_CONTRACT_OUTPUT_TYPE_TOKEN: 3939 cnt = output->details.token.count; 3940 if (output_off + cnt < output_off) 3941 { 3942 GNUNET_break_op (0); 3943 pay_end (pc, 3944 TALER_MHD_reply_with_error ( 3945 pc->connection, 3946 MHD_HTTP_BAD_REQUEST, 3947 TALER_EC_GENERIC_PARAMETER_MALFORMED, 3948 "output token counter overflow")); 3949 return; 3950 } 3951 output_off += cnt; 3952 break; 3953 case TALER_MERCHANT_CONTRACT_OUTPUT_TYPE_DONATION_RECEIPT: 3954 /* check that this output type appears at most once */ 3955 if (pc->validate_tokens.donau_output_index >= 0) 3956 { 3957 /* This should have been prevented when the 3958 contract was initially created */ 3959 GNUNET_break (0); 3960 pay_end (pc, 3961 TALER_MHD_reply_with_error ( 3962 pc->connection, 3963 MHD_HTTP_INTERNAL_SERVER_ERROR, 3964 TALER_EC_GENERIC_DB_INVARIANT_FAILURE, 3965 "two donau output sets in same contract")); 3966 return; 3967 } 3968 pc->validate_tokens.donau_output_index = i; 3969 if (output_off + pc->parse_wallet_data.num_bkps < output_off) 3970 { 3971 GNUNET_break_op (0); 3972 pay_end (pc, 3973 TALER_MHD_reply_with_error ( 3974 pc->connection, 3975 MHD_HTTP_BAD_REQUEST, 3976 TALER_EC_GENERIC_PARAMETER_MALFORMED, 3977 "output token counter overflow")); 3978 return; 3979 } 3980 output_off += pc->parse_wallet_data.num_bkps; 3981 break; 3982 } 3983 } 3984 3985 3986 pc->output_tokens_len = output_off; 3987 pc->output_tokens 3988 = GNUNET_new_array (pc->output_tokens_len, 3989 struct SignedOutputToken); 3990 3991 /* calculate pc->output_tokens[].output_index */ 3992 output_off = 0; 3993 for (unsigned int i = 0; i<selected->outputs_len; i++) 3994 { 3995 const struct TALER_MERCHANT_ContractOutput *output 3996 = &selected->outputs[i]; 3997 cnt = count_output_tokens (pc, 3998 output); 3999 for (unsigned int j = 0; j<cnt; j++) 4000 pc->output_tokens[output_off + j].output_index = i; 4001 output_off += cnt; 4002 } 4003 4004 /* compute non-donau outputs */ 4005 output_off = 0; 4006 for (unsigned int i = 0; i<selected->outputs_len; i++) 4007 { 4008 const struct TALER_MERCHANT_ContractOutput *output 4009 = &selected->outputs[i]; 4010 4011 switch (output->type) 4012 { 4013 case TALER_MERCHANT_CONTRACT_OUTPUT_TYPE_INVALID: 4014 GNUNET_assert (0); 4015 break; 4016 case TALER_MERCHANT_CONTRACT_OUTPUT_TYPE_TOKEN: 4017 cnt = output->details.token.count; 4018 GNUNET_assert (output_off + cnt 4019 <= pc->output_tokens_len); 4020 if (GNUNET_OK != 4021 handle_output_token (pc, 4022 output, 4023 output_off)) 4024 { 4025 /* Error is already scheduled from handle_output_token. */ 4026 return; 4027 } 4028 output_off += cnt; 4029 break; 4030 case TALER_MERCHANT_CONTRACT_OUTPUT_TYPE_DONATION_RECEIPT: 4031 if ( (0 != pc->parse_wallet_data.num_bkps) && 4032 (GNUNET_OK != 4033 handle_output_donation_receipt (pc, 4034 output)) ) 4035 { 4036 /* Error is already scheduled from handle_output_donation_receipt. */ 4037 return; 4038 } 4039 output_off += pc->parse_wallet_data.num_bkps; 4040 continue; 4041 } /* switch on output token */ 4042 } /* for all output token types */ 4043 } /* case contract v1 */ 4044 break; 4045 } /* switch on contract type */ 4046 4047 for (size_t i = 0; i<pc->parse_pay.coins_cnt; i++) 4048 { 4049 const struct DepositConfirmation *dc = &pc->parse_pay.dc[i]; 4050 4051 if (GNUNET_OK != 4052 TALER_amount_cmp_currency (&dc->cdd.amount, 4053 &pc->validate_tokens.brutto)) 4054 { 4055 GNUNET_break_op (0); 4056 pay_end (pc, 4057 TALER_MHD_reply_with_error ( 4058 pc->connection, 4059 MHD_HTTP_CONFLICT, 4060 TALER_EC_MERCHANT_GENERIC_CURRENCY_MISMATCH, 4061 pc->validate_tokens.brutto.currency)); 4062 return; 4063 } 4064 } 4065 4066 pc->phase = PP_COMPUTE_MONEY_POTS; 4067 } 4068 4069 4070 /** 4071 * Function called with information about a coin that was deposited. 4072 * Checks if this coin is in our list of deposits as well. 4073 * 4074 * @param cls closure with our `struct PayContext *` 4075 * @param deposit_serial which deposit operation is this about 4076 * @param exchange_url URL of the exchange that issued the coin 4077 * @param h_wire hash of merchant's wire details 4078 * @param deposit_timestamp when was the deposit made 4079 * @param amount_with_fee amount the exchange will deposit for this coin 4080 * @param deposit_fee fee the exchange will charge for this coin 4081 * @param coin_pub public key of the coin 4082 */ 4083 static void 4084 deposit_paid_check ( 4085 void *cls, 4086 uint64_t deposit_serial, 4087 const char *exchange_url, 4088 const struct TALER_MerchantWireHashP *h_wire, 4089 struct GNUNET_TIME_Timestamp deposit_timestamp, 4090 const struct TALER_Amount *amount_with_fee, 4091 const struct TALER_Amount *deposit_fee, 4092 const struct TALER_CoinSpendPublicKeyP *coin_pub) 4093 { 4094 struct PayContext *pc = cls; 4095 4096 for (size_t i = 0; i<pc->parse_pay.coins_cnt; i++) 4097 { 4098 struct DepositConfirmation *dci = &pc->parse_pay.dc[i]; 4099 4100 if ( (0 == 4101 GNUNET_memcmp (&dci->cdd.coin_pub, 4102 coin_pub)) && 4103 (0 == 4104 strcmp (dci->exchange_url, 4105 exchange_url)) && 4106 (GNUNET_YES == 4107 TALER_amount_cmp_currency (&dci->cdd.amount, 4108 amount_with_fee)) && 4109 (0 == 4110 TALER_amount_cmp (&dci->cdd.amount, 4111 amount_with_fee)) ) 4112 { 4113 dci->matched_in_db = true; 4114 break; 4115 } 4116 } 4117 } 4118 4119 4120 /** 4121 * Function called with information about a token that was spent. 4122 * FIXME: Replace this with a more specific function for this cb 4123 * 4124 * @param cls closure with `struct PayContext *` 4125 * @param spent_token_serial "serial" of the spent token unused 4126 * @param h_contract_terms hash of the contract terms unused 4127 * @param h_issue_pub hash of the token issue public key unused 4128 * @param use_pub public key of the token 4129 * @param use_sig signature of the token 4130 * @param issue_sig signature of the token issue 4131 */ 4132 static void 4133 input_tokens_paid_check ( 4134 void *cls, 4135 uint64_t spent_token_serial, 4136 const struct TALER_PrivateContractHashP *h_contract_terms, 4137 const struct TALER_TokenIssuePublicKeyHashP *h_issue_pub, 4138 const struct TALER_TokenUsePublicKeyP *use_pub, 4139 const struct TALER_TokenUseSignatureP *use_sig, 4140 const struct TALER_TokenIssueSignature *issue_sig) 4141 { 4142 struct PayContext *pc = cls; 4143 4144 for (size_t i = 0; i<pc->parse_pay.tokens_cnt; i++) 4145 { 4146 struct TokenUseConfirmation *tuc = &pc->parse_pay.tokens[i]; 4147 4148 if ( (0 == 4149 GNUNET_memcmp (&tuc->pub, 4150 use_pub)) && 4151 (0 == 4152 GNUNET_memcmp (&tuc->sig, 4153 use_sig)) && 4154 (0 == 4155 GNUNET_memcmp (&tuc->unblinded_sig, 4156 issue_sig)) ) 4157 { 4158 tuc->found_in_db = true; 4159 break; 4160 } 4161 } 4162 } 4163 4164 4165 /** 4166 * Small helper function to append an output token signature from db 4167 * 4168 * @param cls closure with `struct PayContext *` 4169 * @param h_issue hash of the token 4170 * @param sig signature of the token 4171 */ 4172 static void 4173 append_output_token_sig (void *cls, 4174 struct GNUNET_HashCode *h_issue, 4175 struct GNUNET_CRYPTO_BlindedSignature *sig) 4176 { 4177 struct PayContext *pc = cls; 4178 struct TALER_MERCHANT_ContractChoice *choice; 4179 const struct TALER_MERCHANT_ContractOutput *output; 4180 struct SignedOutputToken out; 4181 unsigned int cnt; 4182 4183 memset (&out, 4184 0, 4185 sizeof (out)); 4186 GNUNET_assert (TALER_MERCHANT_CONTRACT_VERSION_1 == 4187 pc->check_contract.contract_terms->pc->base->version); 4188 choice = &pc->check_contract.contract_terms->pc->details.v1 4189 .choices[pc->parse_wallet_data.choice_index]; 4190 output = &choice->outputs[pc->output_index_gen]; 4191 cnt = count_output_tokens (pc, 4192 output); 4193 out.output_index = pc->output_index_gen; 4194 out.h_issue.hash = *h_issue; 4195 out.sig.signature = sig; 4196 GNUNET_CRYPTO_blind_sig_incref (sig); 4197 GNUNET_array_append (pc->output_tokens, 4198 pc->output_tokens_len, 4199 out); 4200 /* Go to next output once we've output all tokens for the current one. */ 4201 pc->output_token_cnt++; 4202 if (pc->output_token_cnt >= cnt) 4203 { 4204 pc->output_token_cnt = 0; 4205 pc->output_index_gen++; 4206 } 4207 } 4208 4209 4210 /** 4211 * Handle case where contract was already paid. Either decides 4212 * the payment is idempotent, or refunds the excess payment. 4213 * 4214 * @param[in,out] pc context we use to handle the payment 4215 */ 4216 static void 4217 phase_contract_paid (struct PayContext *pc) 4218 { 4219 json_t *refunds; 4220 bool unmatched = false; 4221 4222 { 4223 enum GNUNET_DB_QueryStatus qs; 4224 4225 qs = TALER_MERCHANTDB_lookup_deposits_by_order (TMH_db, 4226 pc->check_contract.order_serial, 4227 &deposit_paid_check, 4228 pc); 4229 /* Since orders with choices can have a price of zero, 4230 0 is also a valid query state */ 4231 if (qs < 0) 4232 { 4233 GNUNET_break (0); 4234 pay_end (pc, 4235 TALER_MHD_reply_with_error ( 4236 pc->connection, 4237 MHD_HTTP_INTERNAL_SERVER_ERROR, 4238 TALER_EC_GENERIC_DB_FETCH_FAILED, 4239 "lookup_deposits_by_order")); 4240 return; 4241 } 4242 } 4243 for (size_t i = 0; 4244 i<pc->parse_pay.coins_cnt && ! unmatched; 4245 i++) 4246 { 4247 struct DepositConfirmation *dci = &pc->parse_pay.dc[i]; 4248 4249 if (! dci->matched_in_db) 4250 unmatched = true; 4251 } 4252 /* Check if provided input tokens match token in the database */ 4253 { 4254 enum GNUNET_DB_QueryStatus qs; 4255 4256 /* FIXME-Optimization: Maybe use h_contract instead of order_serial here? */ 4257 qs = TALER_MERCHANTDB_lookup_spent_tokens_by_order (TMH_db, 4258 pc->check_contract.order_serial, 4259 &input_tokens_paid_check, 4260 pc); 4261 4262 if (qs < 0) 4263 { 4264 GNUNET_break (0); 4265 pay_end (pc, 4266 TALER_MHD_reply_with_error ( 4267 pc->connection, 4268 MHD_HTTP_INTERNAL_SERVER_ERROR, 4269 TALER_EC_GENERIC_DB_FETCH_FAILED, 4270 "lookup_spent_tokens_by_order")); 4271 return; 4272 } 4273 } 4274 for (size_t i = 0; i<pc->parse_pay.tokens_cnt && ! unmatched; i++) 4275 { 4276 struct TokenUseConfirmation *tuc = &pc->parse_pay.tokens[i]; 4277 4278 if (! tuc->found_in_db) 4279 unmatched = true; 4280 } 4281 4282 /* In this part we are fetching token_sigs related output */ 4283 if (! unmatched) 4284 { 4285 /* Everything fine, idempotent request, generate response immediately */ 4286 enum GNUNET_DB_QueryStatus qs; 4287 4288 pc->output_index_gen = 0; 4289 qs = TALER_MERCHANTDB_select_order_blinded_sigs ( 4290 TMH_db, 4291 pc->order_id, 4292 &append_output_token_sig, 4293 pc); 4294 if (0 > qs) 4295 { 4296 GNUNET_break (0); 4297 pay_end (pc, 4298 TALER_MHD_reply_with_error ( 4299 pc->connection, 4300 MHD_HTTP_INTERNAL_SERVER_ERROR, 4301 TALER_EC_GENERIC_DB_FETCH_FAILED, 4302 "select_order_blinded_sigs")); 4303 return; 4304 } 4305 4306 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 4307 "Idempotent pay request for order `%s', signing again\n", 4308 pc->order_id); 4309 pc->phase = PP_SUCCESS_RESPONSE; 4310 return; 4311 } 4312 /* Conflict, double-payment detected! */ 4313 /* FIXME-#8674: What should we do with input tokens? 4314 Currently there is no refund for tokens. */ 4315 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 4316 "Client attempted to pay extra for already paid order `%s'\n", 4317 pc->order_id); 4318 refunds = json_array (); 4319 GNUNET_assert (NULL != refunds); 4320 for (size_t i = 0; i<pc->parse_pay.coins_cnt; i++) 4321 { 4322 struct DepositConfirmation *dci = &pc->parse_pay.dc[i]; 4323 struct TALER_MerchantSignatureP merchant_sig; 4324 4325 if (dci->matched_in_db) 4326 continue; 4327 TALER_merchant_refund_sign (&dci->cdd.coin_pub, 4328 &pc->check_contract.h_contract_terms, 4329 0, /* rtransaction id */ 4330 &dci->cdd.amount, 4331 &pc->hc->instance->merchant_priv, 4332 &merchant_sig); 4333 GNUNET_assert ( 4334 0 == 4335 json_array_append_new ( 4336 refunds, 4337 GNUNET_JSON_PACK ( 4338 GNUNET_JSON_pack_data_auto ( 4339 "coin_pub", 4340 &dci->cdd.coin_pub), 4341 GNUNET_JSON_pack_data_auto ( 4342 "merchant_sig", 4343 &merchant_sig), 4344 TALER_JSON_pack_amount ("amount", 4345 &dci->cdd.amount), 4346 GNUNET_JSON_pack_uint64 ("rtransaction_id", 4347 0)))); 4348 } 4349 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 4350 "Generating JSON response with code %d\n", 4351 (int) TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_ALREADY_PAID); 4352 pay_end (pc, 4353 TALER_MHD_REPLY_JSON_PACK ( 4354 pc->connection, 4355 MHD_HTTP_CONFLICT, 4356 TALER_MHD_PACK_EC ( 4357 TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_ALREADY_PAID), 4358 GNUNET_JSON_pack_array_steal ("refunds", 4359 refunds))); 4360 } 4361 4362 4363 /** 4364 * Check the database state for the given order. 4365 * Schedules an error response in the connection on failure. 4366 * 4367 * @param[in,out] pc context we use to handle the payment 4368 */ 4369 static void 4370 phase_check_contract (struct PayContext *pc) 4371 { 4372 /* obtain contract terms */ 4373 enum GNUNET_DB_QueryStatus qs; 4374 bool paid = false; 4375 4376 if (NULL != pc->check_contract.contract_terms_json) 4377 { 4378 json_decref (pc->check_contract.contract_terms_json); 4379 pc->check_contract.contract_terms_json = NULL; 4380 } 4381 if (NULL != pc->check_contract.contract_terms) 4382 { 4383 TALER_MERCHANT_contract_free (pc->check_contract.contract_terms); 4384 pc->check_contract.contract_terms = NULL; 4385 } 4386 qs = TALER_MERCHANTDB_lookup_contract_terms2 ( 4387 TMH_db, 4388 pc->hc->instance->settings.id, 4389 pc->order_id, 4390 &pc->check_contract.contract_terms_json, 4391 &pc->check_contract.order_serial, 4392 &paid, 4393 NULL, 4394 &pc->check_contract.pos_key, 4395 &pc->check_contract.pos_alg); 4396 if (0 > qs) 4397 { 4398 /* single, read-only SQL statements should never cause 4399 serialization problems */ 4400 GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR != qs); 4401 /* Always report on hard error to enable diagnostics */ 4402 GNUNET_break (GNUNET_DB_STATUS_HARD_ERROR == qs); 4403 pay_end (pc, 4404 TALER_MHD_reply_with_error ( 4405 pc->connection, 4406 MHD_HTTP_INTERNAL_SERVER_ERROR, 4407 TALER_EC_GENERIC_DB_FETCH_FAILED, 4408 "contract terms")); 4409 return; 4410 } 4411 if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs) 4412 { 4413 pay_end (pc, 4414 TALER_MHD_reply_with_error ( 4415 pc->connection, 4416 MHD_HTTP_NOT_FOUND, 4417 TALER_EC_MERCHANT_GENERIC_ORDER_UNKNOWN, 4418 pc->order_id)); 4419 return; 4420 } 4421 /* hash contract (needed later) */ 4422 #if DEBUG 4423 json_dumpf (pc->check_contract.contract_terms_json, 4424 stderr, 4425 JSON_INDENT (2)); 4426 #endif 4427 if (GNUNET_OK != 4428 TALER_JSON_contract_hash (pc->check_contract.contract_terms_json, 4429 &pc->check_contract.h_contract_terms)) 4430 { 4431 GNUNET_break (0); 4432 pay_end (pc, 4433 TALER_MHD_reply_with_error ( 4434 pc->connection, 4435 MHD_HTTP_INTERNAL_SERVER_ERROR, 4436 TALER_EC_GENERIC_FAILED_COMPUTE_JSON_HASH, 4437 NULL)); 4438 return; 4439 } 4440 4441 /* Parse the contract terms even for paid orders, 4442 as later phases need it. */ 4443 4444 pc->check_contract.contract_terms = TALER_MERCHANT_contract_parse ( 4445 pc->check_contract.contract_terms_json); 4446 4447 if (NULL == pc->check_contract.contract_terms) 4448 { 4449 /* invalid contract */ 4450 GNUNET_break (0); 4451 pay_end (pc, 4452 TALER_MHD_reply_with_error ( 4453 pc->connection, 4454 MHD_HTTP_INTERNAL_SERVER_ERROR, 4455 TALER_EC_MERCHANT_GENERIC_DB_CONTRACT_CONTENT_INVALID, 4456 pc->order_id)); 4457 return; 4458 } 4459 4460 if (paid) 4461 { 4462 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 4463 "Order `%s' paid, checking for double-payment\n", 4464 pc->order_id); 4465 pc->phase = PP_CONTRACT_PAID; 4466 return; 4467 } 4468 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 4469 "Handling payment for order `%s' with contract hash `%s'\n", 4470 pc->order_id, 4471 GNUNET_h2s (&pc->check_contract.h_contract_terms.hash)); 4472 4473 /* Check fundamentals */ 4474 { 4475 switch (pc->check_contract.contract_terms->pc->base->version) 4476 { 4477 case TALER_MERCHANT_CONTRACT_VERSION_0: 4478 { 4479 if (pc->parse_wallet_data.choice_index > 0) 4480 { 4481 GNUNET_break (0); 4482 pay_end (pc, 4483 TALER_MHD_reply_with_error ( 4484 pc->connection, 4485 MHD_HTTP_BAD_REQUEST, 4486 TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_CHOICE_INDEX_OUT_OF_BOUNDS, 4487 "contract terms v0 has no choices")); 4488 return; 4489 } 4490 } 4491 break; 4492 case TALER_MERCHANT_CONTRACT_VERSION_1: 4493 { 4494 if (pc->parse_wallet_data.choice_index < 0) 4495 { 4496 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 4497 "Order `%s' has non-empty choices array but" 4498 "request is missing 'choice_index' field\n", 4499 pc->order_id); 4500 GNUNET_break (0); 4501 pay_end (pc, 4502 TALER_MHD_reply_with_error ( 4503 pc->connection, 4504 MHD_HTTP_BAD_REQUEST, 4505 TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_CHOICE_INDEX_MISSING, 4506 NULL)); 4507 return; 4508 } 4509 if (pc->parse_wallet_data.choice_index >= 4510 pc->check_contract.contract_terms->pc->details.v1.choices_len) 4511 { 4512 GNUNET_log ( 4513 GNUNET_ERROR_TYPE_INFO, 4514 "Order `%s' has choices array with %u elements but " 4515 "request has 'choice_index' field with value %d\n", 4516 pc->order_id, 4517 pc->check_contract.contract_terms->pc->details.v1.choices_len, 4518 pc->parse_wallet_data.choice_index); 4519 GNUNET_break (0); 4520 pay_end (pc, 4521 TALER_MHD_reply_with_error ( 4522 pc->connection, 4523 MHD_HTTP_BAD_REQUEST, 4524 TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_CHOICE_INDEX_OUT_OF_BOUNDS, 4525 NULL)); 4526 return; 4527 } 4528 } 4529 break; 4530 default: 4531 GNUNET_break (0); 4532 pay_end (pc, 4533 TALER_MHD_reply_with_error ( 4534 pc->connection, 4535 MHD_HTTP_INTERNAL_SERVER_ERROR, 4536 TALER_EC_GENERIC_DB_FETCH_FAILED, 4537 "contract 'version' in database not supported by this backend") 4538 ); 4539 return; 4540 } 4541 } 4542 4543 if (GNUNET_TIME_timestamp_cmp ( 4544 pc->check_contract.contract_terms->pc->wire_deadline, 4545 <, 4546 pc->check_contract.contract_terms->pc->refund_deadline)) 4547 { 4548 /* This should already have been checked when creating the order! */ 4549 GNUNET_break (0); 4550 pay_end (pc, 4551 TALER_MHD_reply_with_error ( 4552 pc->connection, 4553 MHD_HTTP_INTERNAL_SERVER_ERROR, 4554 TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_REFUND_DEADLINE_PAST_WIRE_TRANSFER_DEADLINE, 4555 NULL)); 4556 return; 4557 } 4558 if (GNUNET_TIME_absolute_is_past ( 4559 pc->check_contract.contract_terms->pc->pay_deadline.abs_time)) 4560 { 4561 /* too late */ 4562 pay_end (pc, 4563 TALER_MHD_reply_with_error ( 4564 pc->connection, 4565 MHD_HTTP_GONE, 4566 TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_OFFER_EXPIRED, 4567 NULL)); 4568 return; 4569 } 4570 4571 /* Make sure wire method (still) exists for this instance */ 4572 { 4573 struct TMH_WireMethod *wm; 4574 4575 wm = pc->hc->instance->wm_head; 4576 while (0 != 4577 GNUNET_memcmp ( 4578 &pc->check_contract.contract_terms->pc->h_wire, 4579 &wm->h_wire)) 4580 wm = wm->next; 4581 if (NULL == wm) 4582 { 4583 GNUNET_break (0); 4584 pay_end (pc, 4585 TALER_MHD_reply_with_error ( 4586 pc->connection, 4587 MHD_HTTP_INTERNAL_SERVER_ERROR, 4588 TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_WIRE_HASH_UNKNOWN, 4589 NULL)); 4590 return; 4591 } 4592 pc->check_contract.wm = wm; 4593 } 4594 pc->phase = PP_VALIDATE_TOKENS; 4595 } 4596 4597 4598 /** 4599 * Try to parse the wallet_data object of the pay request into 4600 * the given context. Schedules an error response in the connection 4601 * on failure. 4602 * 4603 * @param[in,out] pc context we use to handle the payment 4604 */ 4605 static void 4606 phase_parse_wallet_data (struct PayContext *pc) 4607 { 4608 const json_t *tokens_evs; 4609 const json_t *donau_obj; 4610 4611 struct GNUNET_JSON_Specification spec[] = { 4612 GNUNET_JSON_spec_mark_optional ( 4613 GNUNET_JSON_spec_int16 ("choice_index", 4614 &pc->parse_wallet_data.choice_index), 4615 NULL), 4616 GNUNET_JSON_spec_mark_optional ( 4617 GNUNET_JSON_spec_array_const ("tokens_evs", 4618 &tokens_evs), 4619 NULL), 4620 GNUNET_JSON_spec_mark_optional ( 4621 GNUNET_JSON_spec_object_const ("donau", 4622 &donau_obj), 4623 NULL), 4624 GNUNET_JSON_spec_end () 4625 }; 4626 4627 pc->parse_wallet_data.choice_index = -1; 4628 if (NULL == pc->parse_pay.wallet_data) 4629 { 4630 pc->phase = PP_CHECK_CONTRACT; 4631 return; 4632 } 4633 { 4634 enum GNUNET_GenericReturnValue res; 4635 4636 res = TALER_MHD_parse_json_data (pc->connection, 4637 pc->parse_pay.wallet_data, 4638 spec); 4639 if (GNUNET_YES != res) 4640 { 4641 GNUNET_break_op (0); 4642 pay_end (pc, 4643 (GNUNET_NO == res) 4644 ? MHD_YES 4645 : MHD_NO); 4646 return; 4647 } 4648 } 4649 4650 pc->parse_wallet_data.token_envelopes_cnt 4651 = json_array_size (tokens_evs); 4652 if (pc->parse_wallet_data.token_envelopes_cnt > 4653 MAX_TOKEN_ALLOWED_OUTPUTS) 4654 { 4655 GNUNET_break_op (0); 4656 pay_end (pc, 4657 TALER_MHD_reply_with_error ( 4658 pc->connection, 4659 MHD_HTTP_BAD_REQUEST, 4660 TALER_EC_GENERIC_PARAMETER_MALFORMED, 4661 "'tokens_evs' array too long")); 4662 return; 4663 } 4664 pc->parse_wallet_data.token_envelopes 4665 = GNUNET_new_array (pc->parse_wallet_data.token_envelopes_cnt, 4666 struct TokenEnvelope); 4667 4668 { 4669 unsigned int tokens_ev_index; 4670 json_t *token_ev; 4671 4672 json_array_foreach (tokens_evs, 4673 tokens_ev_index, 4674 token_ev) 4675 { 4676 struct TokenEnvelope *ev 4677 = &pc->parse_wallet_data.token_envelopes[tokens_ev_index]; 4678 struct GNUNET_JSON_Specification ispec[] = { 4679 TALER_JSON_spec_token_envelope (NULL, 4680 &ev->blinded_token), 4681 GNUNET_JSON_spec_end () 4682 }; 4683 enum GNUNET_GenericReturnValue res; 4684 4685 if (json_is_null (token_ev)) 4686 continue; 4687 res = TALER_MHD_parse_json_data (pc->connection, 4688 token_ev, 4689 ispec); 4690 if (GNUNET_YES != res) 4691 { 4692 GNUNET_break_op (0); 4693 pay_end (pc, 4694 (GNUNET_NO == res) 4695 ? MHD_YES 4696 : MHD_NO); 4697 return; 4698 } 4699 4700 for (unsigned int j = 0; j<tokens_ev_index; j++) 4701 { 4702 if (0 == 4703 GNUNET_memcmp (ev->blinded_token.blinded_pub, 4704 pc->parse_wallet_data.token_envelopes[j]. 4705 blinded_token.blinded_pub)) 4706 { 4707 GNUNET_break_op (0); 4708 pay_end (pc, 4709 TALER_MHD_reply_with_error ( 4710 pc->connection, 4711 MHD_HTTP_BAD_REQUEST, 4712 TALER_EC_GENERIC_PARAMETER_MALFORMED, 4713 "duplicate token envelope in list")); 4714 return; 4715 } 4716 } 4717 } 4718 } 4719 4720 if (NULL != donau_obj) 4721 { 4722 const char *donau_url_tmp; 4723 const json_t *budikeypairs; 4724 json_t *donau_keys_json; 4725 4726 /* Fetching and checking that all 3 are present in some way */ 4727 struct GNUNET_JSON_Specification dspec[] = { 4728 GNUNET_JSON_spec_string ("url", 4729 &donau_url_tmp), 4730 GNUNET_JSON_spec_uint64 ("year", 4731 &pc->parse_wallet_data.donau.donation_year), 4732 GNUNET_JSON_spec_array_const ("budikeypairs", 4733 &budikeypairs), 4734 GNUNET_JSON_spec_end () 4735 }; 4736 enum GNUNET_GenericReturnValue res; 4737 4738 res = TALER_MHD_parse_json_data (pc->connection, 4739 donau_obj, 4740 dspec); 4741 if (GNUNET_YES != res) 4742 { 4743 GNUNET_break_op (0); 4744 pay_end (pc, 4745 (GNUNET_NO == res) 4746 ? MHD_YES 4747 : MHD_NO); 4748 return; 4749 } 4750 4751 /* Check if the needed data is present for the given donau URL */ 4752 { 4753 enum GNUNET_DB_QueryStatus qs; 4754 4755 qs = TALER_MERCHANTDB_lookup_order_charity ( 4756 TMH_db, 4757 pc->hc->instance->settings.id, 4758 donau_url_tmp, 4759 &pc->parse_wallet_data.charity_id, 4760 &pc->parse_wallet_data.charity_priv, 4761 &pc->parse_wallet_data.charity_max_per_year, 4762 &pc->parse_wallet_data.charity_receipts_to_date, 4763 &donau_keys_json, 4764 &pc->parse_wallet_data.donau_instance_serial); 4765 4766 switch (qs) 4767 { 4768 case GNUNET_DB_STATUS_HARD_ERROR: 4769 case GNUNET_DB_STATUS_SOFT_ERROR: 4770 TALER_MERCHANTDB_rollback (TMH_db); 4771 pay_end (pc, 4772 TALER_MHD_reply_with_error ( 4773 pc->connection, 4774 MHD_HTTP_INTERNAL_SERVER_ERROR, 4775 TALER_EC_GENERIC_DB_FETCH_FAILED, 4776 "lookup_order_charity")); 4777 return; 4778 case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS: 4779 TALER_MERCHANTDB_rollback (TMH_db); 4780 pay_end (pc, 4781 TALER_MHD_reply_with_error ( 4782 pc->connection, 4783 MHD_HTTP_NOT_FOUND, 4784 TALER_EC_MERCHANT_GENERIC_DONAU_CHARITY_UNKNOWN, 4785 donau_url_tmp)); 4786 return; 4787 case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT: 4788 pc->parse_wallet_data.donau.donau_url = 4789 GNUNET_strdup (donau_url_tmp); 4790 break; 4791 } 4792 } 4793 4794 { 4795 pc->parse_wallet_data.donau_keys = 4796 DONAU_keys_from_json (donau_keys_json); 4797 json_decref (donau_keys_json); 4798 if (NULL == pc->parse_wallet_data.donau_keys) 4799 { 4800 GNUNET_break_op (0); 4801 pay_end (pc, 4802 TALER_MHD_reply_with_error (pc->connection, 4803 MHD_HTTP_BAD_REQUEST, 4804 TALER_EC_GENERIC_PARAMETER_MALFORMED, 4805 "Invalid donau_keys")); 4806 return; 4807 } 4808 } 4809 4810 /* Stage to parse the budikeypairs from json to struct */ 4811 if (0 != json_array_size (budikeypairs)) 4812 { 4813 size_t num_bkps = json_array_size (budikeypairs); 4814 struct DONAU_BlindedUniqueDonorIdentifierKeyPair *bkps = 4815 GNUNET_new_array (num_bkps, 4816 struct DONAU_BlindedUniqueDonorIdentifierKeyPair); 4817 4818 /* Change to json for each*/ 4819 for (size_t i = 0; i < num_bkps; i++) 4820 { 4821 const json_t *bkp_obj = json_array_get (budikeypairs, 4822 i); 4823 if (GNUNET_SYSERR == 4824 merchant_parse_json_bkp (&bkps[i], 4825 bkp_obj)) 4826 { 4827 GNUNET_break_op (0); 4828 for (size_t j = 0; j < i; j++) 4829 GNUNET_CRYPTO_blinded_message_decref ( 4830 bkps[j].blinded_udi.blinded_message); 4831 GNUNET_free (bkps); 4832 pay_end (pc, 4833 TALER_MHD_reply_with_error (pc->connection, 4834 MHD_HTTP_BAD_REQUEST, 4835 TALER_EC_GENERIC_PARAMETER_MALFORMED, 4836 "Failed to parse budikeypairs")); 4837 return; 4838 } 4839 } 4840 4841 pc->parse_wallet_data.num_bkps = num_bkps; 4842 pc->parse_wallet_data.bkps = bkps; 4843 } 4844 } 4845 TALER_json_hash (pc->parse_pay.wallet_data, 4846 &pc->parse_wallet_data.h_wallet_data); 4847 4848 pc->phase = PP_CHECK_CONTRACT; 4849 } 4850 4851 4852 /** 4853 * Try to parse the pay request into the given pay context. 4854 * Schedules an error response in the connection on failure. 4855 * 4856 * @param[in,out] pc context we use to handle the payment 4857 */ 4858 static void 4859 phase_parse_pay (struct PayContext *pc) 4860 { 4861 const char *session_id = NULL; 4862 const json_t *coins; 4863 const json_t *tokens; 4864 struct GNUNET_JSON_Specification spec[] = { 4865 GNUNET_JSON_spec_array_const ("coins", 4866 &coins), 4867 GNUNET_JSON_spec_mark_optional ( 4868 GNUNET_JSON_spec_string ("session_id", 4869 &session_id), 4870 NULL), 4871 GNUNET_JSON_spec_mark_optional ( 4872 GNUNET_JSON_spec_object_const ("wallet_data", 4873 &pc->parse_pay.wallet_data), 4874 NULL), 4875 GNUNET_JSON_spec_mark_optional ( 4876 GNUNET_JSON_spec_array_const ("tokens", 4877 &tokens), 4878 NULL), 4879 GNUNET_JSON_spec_end () 4880 }; 4881 4882 #if DEBUG 4883 { 4884 char *dump = json_dumps (pc->hc->request_body, 4885 JSON_INDENT (2) 4886 | JSON_ENCODE_ANY 4887 | JSON_SORT_KEYS); 4888 4889 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 4890 "POST /orders/%s/pay – request body follows:\n%s\n", 4891 pc->order_id, 4892 dump); 4893 4894 free (dump); 4895 4896 } 4897 #endif /* DEBUG */ 4898 4899 GNUNET_assert (PP_PARSE_PAY == pc->phase); 4900 { 4901 enum GNUNET_GenericReturnValue res; 4902 4903 res = TALER_MHD_parse_json_data (pc->connection, 4904 pc->hc->request_body, 4905 spec); 4906 if (GNUNET_YES != res) 4907 { 4908 GNUNET_break_op (0); 4909 pay_end (pc, 4910 (GNUNET_NO == res) 4911 ? MHD_YES 4912 : MHD_NO); 4913 return; 4914 } 4915 } 4916 4917 /* copy session ID (if set) */ 4918 if (NULL != session_id) 4919 { 4920 pc->parse_pay.session_id = GNUNET_strdup (session_id); 4921 } 4922 else 4923 { 4924 /* use empty string as default if client didn't specify it */ 4925 pc->parse_pay.session_id = GNUNET_strdup (""); 4926 } 4927 4928 pc->parse_pay.coins_cnt = json_array_size (coins); 4929 if (pc->parse_pay.coins_cnt > MAX_COIN_ALLOWED_COINS) 4930 { 4931 GNUNET_break_op (0); 4932 pay_end (pc, 4933 TALER_MHD_reply_with_error ( 4934 pc->connection, 4935 MHD_HTTP_BAD_REQUEST, 4936 TALER_EC_GENERIC_PARAMETER_MALFORMED, 4937 "'coins' array too long")); 4938 return; 4939 } 4940 /* note: 1 coin = 1 deposit confirmation expected */ 4941 pc->parse_pay.dc = GNUNET_new_array (pc->parse_pay.coins_cnt, 4942 struct DepositConfirmation); 4943 4944 /* This loop populates the array 'dc' in 'pc' */ 4945 { 4946 unsigned int coins_index; 4947 json_t *coin; 4948 4949 json_array_foreach (coins, coins_index, coin) 4950 { 4951 struct DepositConfirmation *dc = &pc->parse_pay.dc[coins_index]; 4952 const char *exchange_url; 4953 struct GNUNET_JSON_Specification ispec[] = { 4954 GNUNET_JSON_spec_fixed_auto ("coin_sig", 4955 &dc->cdd.coin_sig), 4956 GNUNET_JSON_spec_fixed_auto ("coin_pub", 4957 &dc->cdd.coin_pub), 4958 TALER_JSON_spec_denom_sig ("ub_sig", 4959 &dc->cdd.denom_sig), 4960 GNUNET_JSON_spec_fixed_auto ("h_denom", 4961 &dc->cdd.h_denom_pub), 4962 TALER_JSON_spec_amount_any ("contribution", 4963 &dc->cdd.amount), 4964 TALER_JSON_spec_web_url ("exchange_url", 4965 &exchange_url), 4966 /* if a minimum age was required, the minimum_age_sig and 4967 * age_commitment must be provided */ 4968 GNUNET_JSON_spec_mark_optional ( 4969 GNUNET_JSON_spec_fixed_auto ("minimum_age_sig", 4970 &dc->minimum_age_sig), 4971 &dc->no_minimum_age_sig), 4972 GNUNET_JSON_spec_mark_optional ( 4973 TALER_JSON_spec_age_commitment ("age_commitment", 4974 &dc->age_commitment), 4975 &dc->no_age_commitment), 4976 /* if minimum age was not required, but coin with age restriction set 4977 * was used, h_age_commitment must be provided. */ 4978 GNUNET_JSON_spec_mark_optional ( 4979 GNUNET_JSON_spec_fixed_auto ("h_age_commitment", 4980 &dc->cdd.h_age_commitment), 4981 &dc->no_h_age_commitment), 4982 GNUNET_JSON_spec_end () 4983 }; 4984 enum GNUNET_GenericReturnValue res; 4985 struct ExchangeGroup *eg = NULL; 4986 4987 res = TALER_MHD_parse_json_data (pc->connection, 4988 coin, 4989 ispec); 4990 if (GNUNET_YES != res) 4991 { 4992 GNUNET_break_op (0); 4993 pay_end (pc, 4994 (GNUNET_NO == res) 4995 ? MHD_YES 4996 : MHD_NO); 4997 return; 4998 } 4999 for (unsigned int j = 0; j<coins_index; j++) 5000 { 5001 if (0 == 5002 GNUNET_memcmp (&dc->cdd.coin_pub, 5003 &pc->parse_pay.dc[j].cdd.coin_pub)) 5004 { 5005 GNUNET_break_op (0); 5006 pay_end (pc, 5007 TALER_MHD_reply_with_error (pc->connection, 5008 MHD_HTTP_BAD_REQUEST, 5009 TALER_EC_GENERIC_PARAMETER_MALFORMED, 5010 "duplicate coin in list")); 5011 return; 5012 } 5013 } 5014 5015 dc->exchange_url = GNUNET_strdup (exchange_url); 5016 dc->index = coins_index; 5017 dc->pc = pc; 5018 5019 /* Check the consistency of the (potential) age restriction 5020 * information. */ 5021 if (dc->no_age_commitment != dc->no_minimum_age_sig) 5022 { 5023 GNUNET_break_op (0); 5024 pay_end (pc, 5025 TALER_MHD_reply_with_error ( 5026 pc->connection, 5027 MHD_HTTP_BAD_REQUEST, 5028 TALER_EC_GENERIC_PARAMETER_MALFORMED, 5029 "inconsistent: 'age_commitment' vs. 'minimum_age_sig'" 5030 )); 5031 return; 5032 } 5033 5034 /* Setup exchange group */ 5035 for (unsigned int i = 0; i<pc->parse_pay.num_exchanges; i++) 5036 { 5037 if (0 == 5038 strcmp (pc->parse_pay.egs[i]->exchange_url, 5039 exchange_url)) 5040 { 5041 eg = pc->parse_pay.egs[i]; 5042 break; 5043 } 5044 } 5045 if (NULL == eg) 5046 { 5047 eg = GNUNET_new (struct ExchangeGroup); 5048 eg->pc = pc; 5049 eg->exchange_url = dc->exchange_url; 5050 eg->total = dc->cdd.amount; 5051 GNUNET_array_append (pc->parse_pay.egs, 5052 pc->parse_pay.num_exchanges, 5053 eg); 5054 } 5055 else 5056 { 5057 if (0 > 5058 TALER_amount_add (&eg->total, 5059 &eg->total, 5060 &dc->cdd.amount)) 5061 { 5062 GNUNET_break_op (0); 5063 pay_end (pc, 5064 TALER_MHD_reply_with_error ( 5065 pc->connection, 5066 MHD_HTTP_INTERNAL_SERVER_ERROR, 5067 TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_AMOUNT_OVERFLOW, 5068 "Overflow adding up amounts")); 5069 return; 5070 } 5071 } 5072 } 5073 } 5074 5075 pc->parse_pay.tokens_cnt = json_array_size (tokens); 5076 if (pc->parse_pay.tokens_cnt > MAX_TOKEN_ALLOWED_INPUTS) 5077 { 5078 GNUNET_break_op (0); 5079 pay_end (pc, 5080 TALER_MHD_reply_with_error ( 5081 pc->connection, 5082 MHD_HTTP_BAD_REQUEST, 5083 TALER_EC_GENERIC_PARAMETER_MALFORMED, 5084 "'tokens' array too long")); 5085 return; 5086 } 5087 5088 pc->parse_pay.tokens = GNUNET_new_array (pc->parse_pay.tokens_cnt, 5089 struct TokenUseConfirmation); 5090 5091 /* This loop populates the array 'tokens' in 'pc' */ 5092 { 5093 unsigned int tokens_index; 5094 json_t *token; 5095 5096 json_array_foreach (tokens, tokens_index, token) 5097 { 5098 struct TokenUseConfirmation *tuc = &pc->parse_pay.tokens[tokens_index]; 5099 struct GNUNET_JSON_Specification ispec[] = { 5100 GNUNET_JSON_spec_fixed_auto ("token_sig", 5101 &tuc->sig), 5102 GNUNET_JSON_spec_fixed_auto ("token_pub", 5103 &tuc->pub), 5104 GNUNET_JSON_spec_fixed_auto ("h_issue", 5105 &tuc->h_issue), 5106 TALER_JSON_spec_token_issue_sig ("ub_sig", 5107 &tuc->unblinded_sig), 5108 GNUNET_JSON_spec_end () 5109 }; 5110 enum GNUNET_GenericReturnValue res; 5111 5112 res = TALER_MHD_parse_json_data (pc->connection, 5113 token, 5114 ispec); 5115 if (GNUNET_YES != res) 5116 { 5117 GNUNET_break_op (0); 5118 pay_end (pc, 5119 (GNUNET_NO == res) 5120 ? MHD_YES 5121 : MHD_NO); 5122 return; 5123 } 5124 5125 for (unsigned int j = 0; j<tokens_index; j++) 5126 { 5127 if (0 == 5128 GNUNET_memcmp (&tuc->pub, 5129 &pc->parse_pay.tokens[j].pub)) 5130 { 5131 GNUNET_break_op (0); 5132 pay_end (pc, 5133 TALER_MHD_reply_with_error (pc->connection, 5134 MHD_HTTP_BAD_REQUEST, 5135 TALER_EC_GENERIC_PARAMETER_MALFORMED, 5136 "duplicate token in list")); 5137 return; 5138 } 5139 } 5140 } 5141 } 5142 5143 pc->phase = PP_PARSE_WALLET_DATA; 5144 } 5145 5146 5147 /** 5148 * Custom cleanup routine for a `struct PayContext`. 5149 * 5150 * @param cls the `struct PayContext` to clean up. 5151 */ 5152 static void 5153 pay_context_cleanup (void *cls) 5154 { 5155 struct PayContext *pc = cls; 5156 5157 if (NULL != pc->batch_deposits.timeout_task) 5158 { 5159 GNUNET_SCHEDULER_cancel (pc->batch_deposits.timeout_task); 5160 pc->batch_deposits.timeout_task = NULL; 5161 } 5162 if (NULL != pc->check_contract.contract_terms_json) 5163 { 5164 json_decref (pc->check_contract.contract_terms_json); 5165 pc->check_contract.contract_terms_json = NULL; 5166 } 5167 for (unsigned int i = 0; i<pc->parse_pay.coins_cnt; i++) 5168 { 5169 struct DepositConfirmation *dc = &pc->parse_pay.dc[i]; 5170 5171 TALER_denom_sig_free (&dc->cdd.denom_sig); 5172 GNUNET_free (dc->exchange_url); 5173 } 5174 GNUNET_free (pc->parse_pay.dc); 5175 for (unsigned int i = 0; i<pc->parse_pay.tokens_cnt; i++) 5176 { 5177 struct TokenUseConfirmation *tuc = &pc->parse_pay.tokens[i]; 5178 5179 TALER_token_issue_sig_free (&tuc->unblinded_sig); 5180 } 5181 GNUNET_free (pc->parse_pay.tokens); 5182 for (unsigned int i = 0; i<pc->parse_pay.num_exchanges; i++) 5183 { 5184 struct ExchangeGroup *eg = pc->parse_pay.egs[i]; 5185 5186 if (NULL != eg->fo) 5187 TMH_EXCHANGES_keys4exchange_cancel (eg->fo); 5188 if (NULL != eg->bdh) 5189 TALER_EXCHANGE_post_batch_deposit_cancel (eg->bdh); 5190 if (NULL != eg->keys) 5191 TALER_EXCHANGE_keys_decref (eg->keys); 5192 GNUNET_free (eg); 5193 } 5194 GNUNET_free (pc->parse_pay.egs); 5195 if (NULL != pc->check_contract.contract_terms) 5196 { 5197 TALER_MERCHANT_contract_free (pc->check_contract.contract_terms); 5198 pc->check_contract.contract_terms = NULL; 5199 } 5200 if (NULL != pc->response) 5201 { 5202 MHD_destroy_response (pc->response); 5203 pc->response = NULL; 5204 } 5205 GNUNET_free (pc->parse_pay.session_id); 5206 GNUNET_CONTAINER_DLL_remove (pc_head, 5207 pc_tail, 5208 pc); 5209 GNUNET_free (pc->check_contract.pos_key); 5210 GNUNET_free (pc->compute_money_pots.pots); 5211 GNUNET_free (pc->compute_money_pots.increments); 5212 if (NULL != pc->parse_wallet_data.bkps) 5213 { 5214 for (size_t i = 0; i < pc->parse_wallet_data.num_bkps; i++) 5215 GNUNET_CRYPTO_blinded_message_decref ( 5216 pc->parse_wallet_data.bkps[i].blinded_udi.blinded_message); 5217 GNUNET_array_grow (pc->parse_wallet_data.bkps, 5218 pc->parse_wallet_data.num_bkps, 5219 0); 5220 } 5221 if (NULL != pc->parse_wallet_data.donau_keys) 5222 { 5223 DONAU_keys_decref (pc->parse_wallet_data.donau_keys); 5224 pc->parse_wallet_data.donau_keys = NULL; 5225 } 5226 GNUNET_free (pc->parse_wallet_data.donau.donau_url); 5227 for (unsigned int i = 0; i<pc->parse_wallet_data.token_envelopes_cnt; i++) 5228 { 5229 struct TokenEnvelope *ev 5230 = &pc->parse_wallet_data.token_envelopes[i]; 5231 5232 GNUNET_CRYPTO_blinded_message_decref (ev->blinded_token.blinded_pub); 5233 } 5234 GNUNET_free (pc->parse_wallet_data.token_envelopes); 5235 if (NULL != pc->output_tokens) 5236 { 5237 for (unsigned int i = 0; i<pc->output_tokens_len; i++) 5238 if (NULL != pc->output_tokens[i].sig.signature) 5239 GNUNET_CRYPTO_blinded_sig_decref (pc->output_tokens[i].sig.signature); 5240 GNUNET_free (pc->output_tokens); 5241 pc->output_tokens = NULL; 5242 } 5243 GNUNET_free (pc); 5244 } 5245 5246 5247 enum MHD_Result 5248 TMH_post_orders_ID_pay (const struct TMH_RequestHandler *rh, 5249 struct MHD_Connection *connection, 5250 struct TMH_HandlerContext *hc) 5251 { 5252 struct PayContext *pc = hc->ctx; 5253 5254 GNUNET_assert (NULL != hc->infix); 5255 if (NULL == pc) 5256 { 5257 pc = GNUNET_new (struct PayContext); 5258 pc->connection = connection; 5259 pc->hc = hc; 5260 pc->order_id = hc->infix; 5261 hc->ctx = pc; 5262 hc->cc = &pay_context_cleanup; 5263 GNUNET_CONTAINER_DLL_insert (pc_head, 5264 pc_tail, 5265 pc); 5266 } 5267 while (1) 5268 { 5269 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 5270 "Processing /pay in phase %d\n", 5271 (int) pc->phase); 5272 switch (pc->phase) 5273 { 5274 case PP_PARSE_PAY: 5275 phase_parse_pay (pc); 5276 break; 5277 case PP_PARSE_WALLET_DATA: 5278 phase_parse_wallet_data (pc); 5279 break; 5280 case PP_CHECK_CONTRACT: 5281 phase_check_contract (pc); 5282 break; 5283 case PP_VALIDATE_TOKENS: 5284 phase_validate_tokens (pc); 5285 break; 5286 case PP_CONTRACT_PAID: 5287 phase_contract_paid (pc); 5288 break; 5289 case PP_COMPUTE_MONEY_POTS: 5290 phase_compute_money_pots (pc); 5291 break; 5292 case PP_PAY_TRANSACTION: 5293 phase_execute_pay_transaction (pc); 5294 break; 5295 case PP_REQUEST_DONATION_RECEIPT: 5296 phase_request_donation_receipt (pc); 5297 break; 5298 case PP_FINAL_OUTPUT_TOKEN_PROCESSING: 5299 phase_final_output_token_processing (pc); 5300 break; 5301 case PP_PAYMENT_NOTIFICATION: 5302 phase_payment_notification (pc); 5303 break; 5304 case PP_SUCCESS_RESPONSE: 5305 phase_success_response (pc); 5306 break; 5307 case PP_BATCH_DEPOSITS: 5308 phase_batch_deposits (pc); 5309 break; 5310 case PP_RETURN_RESPONSE: 5311 phase_return_response (pc); 5312 break; 5313 case PP_FAIL_LEGAL_REASONS: 5314 phase_fail_for_legal_reasons (pc); 5315 break; 5316 case PP_END_YES: 5317 return MHD_YES; 5318 case PP_END_NO: 5319 return MHD_NO; 5320 default: 5321 /* should not be reachable */ 5322 GNUNET_assert (0); 5323 return MHD_NO; 5324 } 5325 switch (pc->suspended) 5326 { 5327 case GNUNET_SYSERR: 5328 /* during shutdown, we don't generate any more replies */ 5329 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 5330 "Processing /pay ends due to shutdown in phase %d\n", 5331 (int) pc->phase); 5332 return MHD_NO; 5333 case GNUNET_NO: 5334 /* continue to next phase */ 5335 break; 5336 case GNUNET_YES: 5337 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 5338 "Processing /pay suspended in phase %d\n", 5339 (int) pc->phase); 5340 return MHD_YES; 5341 } 5342 } 5343 /* impossible to get here */ 5344 GNUNET_assert (0); 5345 return MHD_YES; 5346 } 5347 5348 5349 /* end of taler-merchant-httpd_post-orders-ORDER_ID-pay.c */