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