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