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