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