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