merchant_api_post-orders-ORDER_ID-pay.c (36872B)
1 /* 2 This file is part of TALER 3 Copyright (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 Lesser General Public License as 7 published by the Free Software Foundation; either version 2.1, 8 or (at your option) any later version. 9 10 TALER is distributed in the hope that it will be useful, 11 but WITHOUT ANY WARRANTY; without even the implied warranty of 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 GNU Lesser General Public License for more details. 14 15 You should have received a copy of the GNU Lesser General 16 Public License along with TALER; see the file COPYING.LGPL. 17 If not, see <http://www.gnu.org/licenses/> 18 */ 19 /** 20 * @file src/lib/merchant_api_post-orders-ORDER_ID-pay.c 21 * @brief Implementation of the POST /orders/$ORDER_ID/pay request 22 * @author Christian Grothoff 23 * @author Marcello Stanisci 24 */ 25 #include "platform.h" 26 #include <curl/curl.h> 27 #include <jansson.h> 28 #include <microhttpd.h> /* just for HTTP status codes */ 29 #include <gnunet/gnunet_util_lib.h> 30 #include <gnunet/gnunet_curl_lib.h> 31 #include <taler/merchant/post-orders-ORDER_ID-pay.h> 32 #include "merchant_api_curl_defaults.h" 33 #include "merchant_api_common.h" 34 #include <taler/taler_json_lib.h> 35 #include <taler/taler_curl_lib.h> 36 #include <taler/taler_signatures.h> 37 #include <donau/donau_service.h> 38 #include <donau/donau_json_lib.h> 39 40 /** 41 * Maximum number of exchange base URLs we accept in an (untrusted) 42 * response before considering it malformed. Bounds the stack VLA used 43 * to parse the array. 44 */ 45 #define MAX_EXCHANGE_BASE_URLS 1024 46 47 /** 48 * Handle for a POST /orders/$ORDER_ID/pay operation. 49 */ 50 struct TALER_MERCHANT_PostOrdersPayHandle 51 { 52 /** 53 * Base URL of the merchant backend. 54 */ 55 char *base_url; 56 57 /** 58 * The full URL for this request. 59 */ 60 char *url; 61 62 /** 63 * Handle for the request. 64 */ 65 struct GNUNET_CURL_Job *job; 66 67 /** 68 * Function to call with the result. 69 */ 70 TALER_MERCHANT_PostOrdersPayCallback cb; 71 72 /** 73 * Closure for @a cb. 74 */ 75 TALER_MERCHANT_POST_ORDERS_PAY_RESULT_CLOSURE *cb_cls; 76 77 /** 78 * Reference to the execution context. 79 */ 80 struct GNUNET_CURL_Context *ctx; 81 82 /** 83 * Minor context that holds body and headers. 84 */ 85 struct TALER_CURL_PostContext post_ctx; 86 87 /** 88 * Order identifier. 89 */ 90 char *order_id; 91 92 /** 93 * The coins we are paying with (frontend mode, already signed). 94 */ 95 struct TALER_MERCHANT_PostOrdersPayPaidCoin *paid_coins; 96 97 /** 98 * Number of @e paid_coins. 99 */ 100 unsigned int num_paid_coins; 101 102 /** 103 * Hash of the contract terms (wallet mode). 104 */ 105 struct TALER_PrivateContractHashP h_contract_terms; 106 107 /** 108 * Public key of the merchant (wallet mode). 109 */ 110 struct TALER_MerchantPublicKeyP merchant_pub; 111 112 /** 113 * Merchant signature (wallet mode). 114 */ 115 struct TALER_MerchantSignatureP merchant_sig; 116 117 /** 118 * Total payment amount (wallet mode). 119 */ 120 struct TALER_Amount amount; 121 122 /** 123 * Maximum fee (wallet mode). 124 */ 125 struct TALER_Amount max_fee; 126 127 /** 128 * Contract timestamp (wallet mode). 129 */ 130 struct GNUNET_TIME_Timestamp timestamp; 131 132 /** 133 * Refund deadline (wallet mode). 134 */ 135 struct GNUNET_TIME_Timestamp refund_deadline; 136 137 /** 138 * Payment deadline (wallet mode). 139 */ 140 struct GNUNET_TIME_Timestamp pay_deadline; 141 142 /** 143 * Hash of merchant wire details (wallet mode). 144 */ 145 struct TALER_MerchantWireHashP h_wire; 146 147 /** 148 * Choice index (wallet mode). 149 */ 150 int choice_index; 151 152 /** 153 * Coins with private keys (wallet mode). 154 */ 155 struct TALER_MERCHANT_PostOrdersPayCoin *coins; 156 157 /** 158 * Number of @e coins (wallet mode). 159 */ 160 unsigned int num_coins; 161 162 /** 163 * Optional session identifier. 164 */ 165 char *session_id; 166 167 /** 168 * Optional wallet data (JSON). 169 */ 170 json_t *wallet_data; 171 172 /** 173 * Used tokens (public form, frontend mode). 174 */ 175 struct TALER_MERCHANT_PostOrdersPayUsedToken *used_tokens; 176 177 /** 178 * Number of @e used_tokens. 179 */ 180 unsigned int num_used_tokens; 181 182 /** 183 * Use tokens (private form, wallet mode). 184 */ 185 struct TALER_MERCHANT_PostOrdersPayUseToken *use_tokens; 186 187 /** 188 * Number of @e use_tokens. 189 */ 190 unsigned int num_use_tokens; 191 192 /** 193 * Output tokens (wallet mode). 194 */ 195 struct TALER_MERCHANT_PostOrdersPayOutputToken *output_tokens; 196 197 /** 198 * Number of @e output_tokens. 199 */ 200 unsigned int num_output_tokens; 201 202 /** 203 * Output tokens as JSON array (frontend mode). 204 */ 205 json_t *output_tokens_json; 206 207 /** 208 * Base URL of the selected donau for donation receipts. 209 */ 210 char *donau_url; 211 212 /** 213 * Tax year used for the donau. 214 */ 215 unsigned int donau_year; 216 217 /** 218 * Array of blinded donation receipts. 219 */ 220 struct DONAU_BlindedUniqueDonorIdentifierKeyPair *donau_bkps; 221 222 /** 223 * Length of the @e donau_bkps array. 224 */ 225 size_t num_donau_bkps; 226 227 /** 228 * Set to true if this is the wallet mode (private keys available). 229 */ 230 bool am_wallet; 231 }; 232 233 234 /** 235 * Parse blindly signed output tokens from JSON response. 236 * 237 * @param token_sigs the JSON array with the token signatures, can be NULL 238 * @param[out] tokens where to store the parsed tokens 239 * @param[out] num_tokens where to store the length of the @a tokens array 240 * @return #GNUNET_YES on success 241 */ 242 static enum GNUNET_GenericReturnValue 243 parse_tokens (const json_t *token_sigs, 244 struct TALER_MERCHANT_PostOrdersPayOutputToken **tokens, 245 unsigned int *num_tokens) 246 { 247 GNUNET_array_grow (*tokens, 248 *num_tokens, 249 json_array_size (token_sigs)); 250 251 for (unsigned int i = 0; i < (*num_tokens); i++) 252 { 253 struct TALER_MERCHANT_PostOrdersPayOutputToken *token = &(*tokens)[i]; 254 struct GNUNET_JSON_Specification spec[] = { 255 TALER_JSON_spec_blinded_token_issue_sig ("blind_sig", 256 &token->blinded_sig), 257 GNUNET_JSON_spec_end () 258 }; 259 const json_t *jtoken 260 = json_array_get (token_sigs, 261 i); 262 263 if (NULL == jtoken) 264 { 265 GNUNET_break (0); 266 return GNUNET_SYSERR; 267 } 268 if (GNUNET_OK != 269 GNUNET_JSON_parse (jtoken, 270 spec, 271 NULL, NULL)) 272 { 273 GNUNET_break (0); 274 return GNUNET_SYSERR; 275 } 276 } 277 278 return GNUNET_YES; 279 } 280 281 282 /** 283 * Function called when we're done processing the 284 * HTTP POST /orders/$ORDER_ID/pay request. 285 * 286 * @param cls the `struct TALER_MERCHANT_PostOrdersPayHandle` 287 * @param response_code HTTP response code, 0 on error 288 * @param response response body, NULL if not in JSON 289 */ 290 static void 291 handle_pay_finished (void *cls, 292 long response_code, 293 const void *response) 294 { 295 struct TALER_MERCHANT_PostOrdersPayHandle *poph = cls; 296 const json_t *json = response; 297 struct TALER_MERCHANT_PostOrdersPayResponse pr = { 298 .hr.http_status = (unsigned int) response_code, 299 .hr.reply = json 300 }; 301 302 poph->job = NULL; 303 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 304 "POST /orders/$ID/pay completed with response code %u\n", 305 (unsigned int) response_code); 306 switch (response_code) 307 { 308 case 0: 309 pr.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE; 310 break; 311 case MHD_HTTP_OK: 312 if (poph->am_wallet) 313 { 314 const json_t *token_sigs = NULL; 315 struct GNUNET_JSON_Specification spec[] = { 316 GNUNET_JSON_spec_fixed_auto ("sig", 317 &pr.details.ok.merchant_sig), 318 GNUNET_JSON_spec_mark_optional ( 319 GNUNET_JSON_spec_string ("pos_confirmation", 320 &pr.details.ok.pos_confirmation), 321 NULL), 322 GNUNET_JSON_spec_mark_optional ( 323 GNUNET_JSON_spec_array_const ("token_sigs", 324 &token_sigs), 325 NULL), 326 GNUNET_JSON_spec_end () 327 }; 328 329 if (GNUNET_OK != 330 GNUNET_JSON_parse (json, 331 spec, 332 NULL, NULL)) 333 { 334 GNUNET_break_op (0); 335 pr.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE; 336 pr.hr.http_status = 0; 337 pr.hr.hint = "sig field missing in response"; 338 break; 339 } 340 341 if (GNUNET_OK != 342 parse_tokens (token_sigs, 343 &pr.details.ok.tokens, 344 &pr.details.ok.num_tokens)) 345 { 346 GNUNET_break_op (0); 347 pr.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE; 348 pr.hr.http_status = 0; 349 pr.hr.hint = "failed to parse token_sigs field in response"; 350 break; 351 } 352 353 if (GNUNET_OK != 354 TALER_merchant_pay_verify (&poph->h_contract_terms, 355 &poph->merchant_pub, 356 &pr.details.ok.merchant_sig)) 357 { 358 GNUNET_break_op (0); 359 pr.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE; 360 pr.hr.http_status = 0; 361 pr.hr.hint = "signature invalid"; 362 } 363 } 364 break; 365 case MHD_HTTP_BAD_REQUEST: 366 pr.hr.ec = TALER_JSON_get_error_code (json); 367 pr.hr.hint = TALER_JSON_get_error_hint (json); 368 break; 369 case MHD_HTTP_PAYMENT_REQUIRED: 370 pr.hr.ec = TALER_JSON_get_error_code (json); 371 pr.hr.hint = TALER_JSON_get_error_hint (json); 372 break; 373 case MHD_HTTP_FORBIDDEN: 374 pr.hr.ec = TALER_JSON_get_error_code (json); 375 pr.hr.hint = TALER_JSON_get_error_hint (json); 376 break; 377 case MHD_HTTP_NOT_FOUND: 378 pr.hr.ec = TALER_JSON_get_error_code (json); 379 pr.hr.hint = TALER_JSON_get_error_hint (json); 380 break; 381 case MHD_HTTP_REQUEST_TIMEOUT: 382 pr.hr.ec = TALER_JSON_get_error_code (json); 383 pr.hr.hint = TALER_JSON_get_error_hint (json); 384 break; 385 case MHD_HTTP_CONFLICT: 386 TALER_MERCHANT_parse_error_details_ (json, 387 MHD_HTTP_CONFLICT, 388 &pr.hr); 389 { 390 const char *eu = json_string_value ( 391 json_object_get (json, "exchange_url")); 392 393 pr.details.conflict.exchange_url = eu; 394 pr.details.conflict.exchange_ec = pr.hr.exchange_code; 395 pr.details.conflict.exchange_http_status 396 = pr.hr.exchange_http_status; 397 } 398 break; 399 case MHD_HTTP_GONE: 400 TALER_MERCHANT_parse_error_details_ (json, 401 response_code, 402 &pr.hr); 403 break; 404 case MHD_HTTP_PRECONDITION_FAILED: 405 TALER_MERCHANT_parse_error_details_ (json, 406 response_code, 407 &pr.hr); 408 break; 409 case MHD_HTTP_UNAVAILABLE_FOR_LEGAL_REASONS: 410 { 411 json_t *ebus = json_object_get (json, 412 "exchange_base_urls"); 413 if (NULL == ebus) 414 { 415 GNUNET_break_op (0); 416 pr.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE; 417 pr.hr.http_status = 0; 418 pr.hr.hint 419 = "failed to parse exchange_base_urls field in response"; 420 break; 421 } 422 { 423 size_t alen = json_array_size (ebus); 424 425 if (alen > MAX_EXCHANGE_BASE_URLS) 426 { 427 /* Bound the stack VLA below by an untrusted response. */ 428 GNUNET_break_op (0); 429 pr.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE; 430 pr.hr.http_status = 0; 431 pr.hr.hint = "too many exchange_base_urls in response"; 432 break; 433 } 434 { 435 const char *ebua[GNUNET_NZL (alen)]; 436 size_t idx; 437 json_t *jebu; 438 bool ok = true; 439 440 json_array_foreach (ebus, idx, jebu) 441 { 442 ebua[idx] = json_string_value (jebu); 443 if (NULL == ebua[idx]) 444 { 445 GNUNET_break_op (0); 446 pr.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE; 447 pr.hr.http_status = 0; 448 pr.hr.hint 449 = "non-string value in exchange_base_urls in response"; 450 ok = false; 451 break; 452 } 453 } 454 if (! ok) 455 break; 456 pr.details.unavailable_for_legal_reasons.num_exchanges 457 = (unsigned int) alen; 458 pr.details.unavailable_for_legal_reasons.exchanges 459 = ebua; 460 poph->cb (poph->cb_cls, 461 &pr); 462 TALER_MERCHANT_post_orders_pay_cancel (poph); 463 return; 464 } 465 } 466 } 467 break; 468 case MHD_HTTP_INTERNAL_SERVER_ERROR: 469 TALER_MERCHANT_parse_error_details_ (json, 470 response_code, 471 &pr.hr); 472 break; 473 case MHD_HTTP_NOT_IMPLEMENTED: 474 TALER_MERCHANT_parse_error_details_ (json, 475 response_code, 476 &pr.hr); 477 break; 478 case MHD_HTTP_BAD_GATEWAY: 479 TALER_MERCHANT_parse_error_details_ (json, 480 response_code, 481 &pr.hr); 482 { 483 const char *eu = json_string_value ( 484 json_object_get (json, "exchange_url")); 485 486 pr.details.bad_gateway.exchange_url = eu; 487 pr.details.bad_gateway.exchange_ec = pr.hr.exchange_code; 488 pr.details.bad_gateway.exchange_http_status 489 = pr.hr.exchange_http_status; 490 } 491 break; 492 case MHD_HTTP_GATEWAY_TIMEOUT: 493 TALER_MERCHANT_parse_error_details_ (json, 494 response_code, 495 &pr.hr); 496 break; 497 default: 498 TALER_MERCHANT_parse_error_details_ (json, 499 response_code, 500 &pr.hr); 501 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 502 "Unexpected response code %u/%d\n", 503 (unsigned int) response_code, 504 (int) pr.hr.ec); 505 GNUNET_break_op (0); 506 break; 507 } 508 poph->cb (poph->cb_cls, 509 &pr); 510 if (poph->am_wallet && 511 (MHD_HTTP_OK == response_code) ) 512 { 513 for (unsigned int i = 0; i < pr.details.ok.num_tokens; i++) 514 { 515 struct GNUNET_CRYPTO_BlindedSignature *bs 516 = pr.details.ok.tokens[i].blinded_sig.signature; 517 518 if (NULL != bs) 519 GNUNET_CRYPTO_blinded_sig_decref (bs); 520 } 521 GNUNET_array_grow (pr.details.ok.tokens, 522 pr.details.ok.num_tokens, 523 0); 524 } 525 TALER_MERCHANT_post_orders_pay_cancel (poph); 526 } 527 528 529 struct TALER_MERCHANT_PostOrdersPayHandle * 530 TALER_MERCHANT_post_orders_pay_frontend_create ( 531 struct GNUNET_CURL_Context *ctx, 532 const char *url, 533 const char *order_id, 534 unsigned int num_coins, 535 const struct TALER_MERCHANT_PostOrdersPayPaidCoin coins[static num_coins]) 536 { 537 struct TALER_MERCHANT_PostOrdersPayHandle *poph; 538 539 poph = GNUNET_new (struct TALER_MERCHANT_PostOrdersPayHandle); 540 poph->ctx = ctx; 541 poph->base_url = GNUNET_strdup (url); 542 poph->order_id = GNUNET_strdup (order_id); 543 poph->am_wallet = false; 544 poph->num_paid_coins = num_coins; 545 poph->paid_coins = GNUNET_new_array ( 546 num_coins, 547 struct TALER_MERCHANT_PostOrdersPayPaidCoin); 548 for (unsigned int i = 0; i < num_coins; i++) 549 { 550 struct TALER_MERCHANT_PostOrdersPayPaidCoin *dst = &poph->paid_coins[i]; 551 const struct TALER_MERCHANT_PostOrdersPayPaidCoin *src = &coins[i]; 552 553 *dst = *src; 554 /* deep copy fields that need it */ 555 TALER_denom_pub_copy (&dst->denom_pub, 556 &src->denom_pub); 557 TALER_denom_sig_copy (&dst->denom_sig, 558 &src->denom_sig); 559 dst->exchange_url = GNUNET_strdup (src->exchange_url); 560 } 561 return poph; 562 } 563 564 565 struct TALER_MERCHANT_PostOrdersPayHandle * 566 TALER_MERCHANT_post_orders_pay_create ( 567 struct GNUNET_CURL_Context *ctx, 568 const char *url, 569 const char *order_id, 570 const struct TALER_PrivateContractHashP *h_contract_terms, 571 const struct TALER_Amount *amount, 572 const struct TALER_Amount *max_fee, 573 const struct TALER_MerchantPublicKeyP *merchant_pub, 574 const struct TALER_MerchantSignatureP *merchant_sig, 575 struct GNUNET_TIME_Timestamp timestamp, 576 struct GNUNET_TIME_Timestamp refund_deadline, 577 struct GNUNET_TIME_Timestamp pay_deadline, 578 const struct TALER_MerchantWireHashP *h_wire, 579 unsigned int num_coins, 580 const struct TALER_MERCHANT_PostOrdersPayCoin coins[static num_coins]) 581 { 582 struct TALER_MERCHANT_PostOrdersPayHandle *poph; 583 584 if (GNUNET_YES != 585 TALER_amount_cmp_currency (amount, 586 max_fee)) 587 { 588 GNUNET_break (0); 589 return NULL; 590 } 591 592 poph = GNUNET_new (struct TALER_MERCHANT_PostOrdersPayHandle); 593 poph->ctx = ctx; 594 poph->base_url = GNUNET_strdup (url); 595 poph->order_id = GNUNET_strdup (order_id); 596 poph->am_wallet = true; 597 poph->h_contract_terms = *h_contract_terms; 598 poph->choice_index = -1; 599 poph->amount = *amount; 600 poph->max_fee = *max_fee; 601 poph->merchant_pub = *merchant_pub; 602 poph->merchant_sig = *merchant_sig; 603 poph->timestamp = timestamp; 604 poph->refund_deadline = refund_deadline; 605 poph->pay_deadline = pay_deadline; 606 poph->h_wire = *h_wire; 607 poph->num_coins = num_coins; 608 poph->coins = GNUNET_new_array (num_coins, 609 struct TALER_MERCHANT_PostOrdersPayCoin); 610 for (unsigned int i = 0; i < num_coins; i++) 611 { 612 struct TALER_MERCHANT_PostOrdersPayCoin *dst = &poph->coins[i]; 613 const struct TALER_MERCHANT_PostOrdersPayCoin *src = &coins[i]; 614 615 *dst = *src; 616 TALER_denom_pub_copy (&dst->denom_pub, 617 &src->denom_pub); 618 TALER_denom_sig_copy (&dst->denom_sig, 619 &src->denom_sig); 620 dst->exchange_url = GNUNET_strdup (src->exchange_url); 621 } 622 return poph; 623 } 624 625 626 enum GNUNET_GenericReturnValue 627 TALER_MERCHANT_post_orders_pay_set_options_ ( 628 struct TALER_MERCHANT_PostOrdersPayHandle *poph, 629 unsigned int num_options, 630 const struct TALER_MERCHANT_PostOrdersPayOptionValue *options) 631 { 632 for (unsigned int i = 0; i < num_options; i++) 633 { 634 switch (options[i].option) 635 { 636 case TALER_MERCHANT_POST_ORDERS_PAY_OPTION_END: 637 return GNUNET_OK; 638 case TALER_MERCHANT_POST_ORDERS_PAY_OPTION_SESSION_ID: 639 GNUNET_free (poph->session_id); 640 if (NULL != options[i].details.session_id) 641 poph->session_id = GNUNET_strdup (options[i].details.session_id); 642 break; 643 case TALER_MERCHANT_POST_ORDERS_PAY_OPTION_WALLET_DATA: 644 json_decref (poph->wallet_data); 645 poph->wallet_data = NULL; 646 if (NULL != options[i].details.wallet_data) 647 poph->wallet_data = json_incref ( 648 (json_t *) options[i].details.wallet_data); 649 break; 650 case TALER_MERCHANT_POST_ORDERS_PAY_OPTION_USED_TOKENS: 651 GNUNET_free (poph->used_tokens); 652 poph->num_used_tokens = options[i].details.used_tokens.num; 653 if (0 < poph->num_used_tokens) 654 { 655 poph->used_tokens = GNUNET_new_array ( 656 poph->num_used_tokens, 657 struct TALER_MERCHANT_PostOrdersPayUsedToken); 658 GNUNET_memcpy (poph->used_tokens, 659 options[i].details.used_tokens.tokens, 660 poph->num_used_tokens 661 * sizeof (struct TALER_MERCHANT_PostOrdersPayUsedToken)); 662 } 663 break; 664 case TALER_MERCHANT_POST_ORDERS_PAY_OPTION_USE_TOKENS: 665 GNUNET_free (poph->use_tokens); 666 poph->num_use_tokens = options[i].details.use_tokens.num; 667 if (0 < poph->num_use_tokens) 668 { 669 poph->use_tokens = GNUNET_new_array ( 670 poph->num_use_tokens, 671 struct TALER_MERCHANT_PostOrdersPayUseToken); 672 GNUNET_memcpy (poph->use_tokens, 673 options[i].details.use_tokens.tokens, 674 poph->num_use_tokens 675 * sizeof (struct TALER_MERCHANT_PostOrdersPayUseToken)); 676 } 677 break; 678 case TALER_MERCHANT_POST_ORDERS_PAY_OPTION_OUTPUT_TOKENS: 679 GNUNET_free (poph->output_tokens); 680 poph->num_output_tokens = options[i].details.output_tokens.num; 681 if (0 < poph->num_output_tokens) 682 { 683 poph->output_tokens = GNUNET_new_array ( 684 poph->num_output_tokens, 685 struct TALER_MERCHANT_PostOrdersPayOutputToken); 686 GNUNET_memcpy ( 687 poph->output_tokens, 688 options[i].details.output_tokens.tokens, 689 poph->num_output_tokens 690 * sizeof (struct TALER_MERCHANT_PostOrdersPayOutputToken)); 691 } 692 break; 693 case TALER_MERCHANT_POST_ORDERS_PAY_OPTION_OUTPUT_TOKENS_JSON: 694 json_decref (poph->output_tokens_json); 695 poph->output_tokens_json = NULL; 696 if (NULL != options[i].details.output_tokens_json) 697 poph->output_tokens_json = json_incref ( 698 options[i].details.output_tokens_json); 699 break; 700 case TALER_MERCHANT_POST_ORDERS_PAY_OPTION_OUTPUT_DONAU: 701 if (NULL != poph->donau_url) 702 { 703 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 704 "Only one set of donation receipts is allowed to be specified\n"); 705 return GNUNET_NO; 706 } 707 poph->donau_url 708 = GNUNET_strdup (options[i].details.output_donau.donau_base_url); 709 poph->donau_year 710 = options[i].details.output_donau.year; 711 poph->num_donau_bkps = options[i].details.output_donau.num_bkps; 712 poph->donau_bkps = GNUNET_new_array ( 713 poph->num_donau_bkps, 714 struct DONAU_BlindedUniqueDonorIdentifierKeyPair); 715 for (size_t j=0; j<poph->num_donau_bkps; j++) 716 { 717 const struct DONAU_BlindedUniqueDonorIdentifierKeyPair *src 718 = &options[i].details.output_donau.bkps[j]; 719 struct DONAU_BlindedUniqueDonorIdentifierKeyPair *dst 720 = &poph->donau_bkps[j]; 721 722 dst->h_donation_unit_pub = src->h_donation_unit_pub; 723 dst->blinded_udi.blinded_message 724 = GNUNET_CRYPTO_blinded_message_incref ( 725 src->blinded_udi.blinded_message); 726 } 727 break; 728 case TALER_MERCHANT_POST_ORDERS_PAY_OPTION_CHOICE_INDEX: 729 poph->choice_index = options[i].details.choice_index; 730 break; 731 default: 732 GNUNET_break (0); 733 return GNUNET_SYSERR; 734 } 735 } 736 return GNUNET_OK; 737 } 738 739 740 enum TALER_ErrorCode 741 TALER_MERCHANT_post_orders_pay_start ( 742 struct TALER_MERCHANT_PostOrdersPayHandle *poph, 743 TALER_MERCHANT_PostOrdersPayCallback cb, 744 TALER_MERCHANT_POST_ORDERS_PAY_RESULT_CLOSURE *cb_cls) 745 { 746 json_t *pay_obj; 747 json_t *j_coins; 748 json_t *j_tokens = NULL; 749 json_t *j_output_tokens = NULL; 750 CURL *eh; 751 752 poph->cb = cb; 753 poph->cb_cls = cb_cls; 754 { 755 char *path; 756 757 GNUNET_asprintf (&path, 758 "orders/%s/pay", 759 poph->order_id); 760 poph->url = TALER_url_join (poph->base_url, 761 path, 762 NULL); 763 GNUNET_free (path); 764 } 765 if (NULL == poph->url) 766 return TALER_EC_GENERIC_CONFIGURATION_INVALID; 767 768 if (poph->am_wallet) 769 { 770 /* Wallet mode: sign coins and tokens, build wallet_data */ 771 json_t *wallet_data = poph->wallet_data; 772 json_t *j_donau_data = NULL; 773 struct GNUNET_HashCode wallet_data_hash; 774 775 if (NULL != poph->donau_url) 776 { 777 json_t *budis; 778 779 budis = json_array (); 780 GNUNET_assert (NULL != budis); 781 for (size_t i=0; i<poph->num_donau_bkps; i++) 782 { 783 const struct DONAU_BlindedUniqueDonorIdentifierKeyPair *bkp 784 = &poph->donau_bkps[i]; 785 json_t *budikeypair = GNUNET_JSON_PACK ( 786 GNUNET_JSON_pack_data_auto ("h_donation_unit_pub", 787 &bkp->h_donation_unit_pub), 788 DONAU_JSON_pack_blinded_donation_identifier ("blinded_udi", 789 &bkp->blinded_udi)); 790 791 GNUNET_assert (0 == 792 json_array_append_new (budis, 793 budikeypair)); 794 } 795 796 j_donau_data = GNUNET_JSON_PACK ( 797 GNUNET_JSON_pack_string ("url", 798 poph->donau_url), 799 GNUNET_JSON_pack_int64 ("year", 800 poph->donau_year), 801 GNUNET_JSON_pack_array_steal ("budikeypairs", 802 budis)); 803 } 804 805 /* Build output token envelopes JSON if we have output tokens */ 806 if (0 < poph->num_output_tokens) 807 { 808 j_output_tokens = json_array (); 809 GNUNET_assert (NULL != j_output_tokens); 810 for (unsigned int i = 0; i < poph->num_output_tokens; i++) 811 { 812 json_t *j_token_ev; 813 const struct TALER_MERCHANT_PostOrdersPayOutputToken *ev 814 = &poph->output_tokens[i]; 815 816 j_token_ev = GNUNET_JSON_PACK ( 817 TALER_JSON_pack_token_envelope (NULL, 818 &ev->envelope)); 819 if (0 != 820 json_array_append_new (j_output_tokens, 821 j_token_ev)) 822 { 823 GNUNET_break (0); 824 json_decref (j_output_tokens); 825 json_decref (j_donau_data); 826 return TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE; 827 } 828 } 829 } 830 else if (NULL != poph->output_tokens_json) 831 { 832 j_output_tokens = json_incref (poph->output_tokens_json); 833 } 834 835 /* Build wallet_data if choice_index is valid */ 836 if (0 <= poph->choice_index) 837 { 838 if (NULL == wallet_data) 839 { 840 wallet_data = GNUNET_JSON_PACK ( 841 GNUNET_JSON_pack_int64 ("choice_index", 842 poph->choice_index), 843 GNUNET_JSON_pack_allow_null ( 844 GNUNET_JSON_pack_object_incref ("donau", 845 j_donau_data)), 846 GNUNET_JSON_pack_allow_null ( 847 GNUNET_JSON_pack_array_incref ("tokens_evs", 848 j_output_tokens))); 849 } 850 TALER_json_hash (wallet_data, 851 &wallet_data_hash); 852 } 853 json_decref (j_donau_data); 854 j_donau_data = NULL; 855 856 if ( (0 < poph->num_use_tokens || 0 < poph->num_output_tokens 857 || NULL != poph->output_tokens_json) 858 && (0 > poph->choice_index) ) 859 { 860 GNUNET_break (0); 861 json_decref (j_output_tokens); 862 if ( (NULL == poph->wallet_data) && 863 (NULL != wallet_data) ) 864 json_decref (wallet_data); 865 return TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE; 866 } 867 868 /* Sign coins */ 869 j_coins = json_array (); 870 GNUNET_assert (NULL != j_coins); 871 for (unsigned int i = 0; i < poph->num_coins; i++) 872 { 873 const struct TALER_MERCHANT_PostOrdersPayCoin *coin = &poph->coins[i]; 874 struct TALER_CoinSpendPublicKeyP coin_pub; 875 struct TALER_CoinSpendSignatureP coin_sig; 876 struct TALER_Amount fee; 877 struct TALER_DenominationHashP h_denom_pub; 878 json_t *j_coin; 879 880 if (0 > 881 TALER_amount_subtract (&fee, 882 &coin->amount_with_fee, 883 &coin->amount_without_fee)) 884 { 885 GNUNET_break (0); 886 json_decref (j_coins); 887 json_decref (j_output_tokens); 888 if ( (NULL == poph->wallet_data) && 889 (NULL != wallet_data) ) 890 json_decref (wallet_data); 891 return TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE; 892 } 893 TALER_denom_pub_hash (&coin->denom_pub, 894 &h_denom_pub); 895 TALER_wallet_deposit_sign (&coin->amount_with_fee, 896 &fee, 897 &poph->h_wire, 898 &poph->h_contract_terms, 899 (0 <= poph->choice_index) 900 ? &wallet_data_hash 901 : NULL, 902 GNUNET_is_zero (&coin->h_age_commitment) 903 ? NULL 904 : &coin->h_age_commitment, 905 NULL /* h_extensions */, 906 &h_denom_pub, 907 poph->timestamp, 908 &poph->merchant_pub, 909 poph->refund_deadline, 910 &coin->coin_priv, 911 &coin_sig); 912 GNUNET_CRYPTO_eddsa_key_get_public (&coin->coin_priv.eddsa_priv, 913 &coin_pub.eddsa_pub); 914 j_coin = GNUNET_JSON_PACK ( 915 TALER_JSON_pack_amount ("contribution", 916 &coin->amount_with_fee), 917 GNUNET_JSON_pack_data_auto ("coin_pub", 918 &coin_pub), 919 GNUNET_JSON_pack_string ("exchange_url", 920 coin->exchange_url), 921 GNUNET_JSON_pack_data_auto ("h_denom", 922 &h_denom_pub), 923 TALER_JSON_pack_denom_sig ("ub_sig", 924 &coin->denom_sig), 925 GNUNET_JSON_pack_data_auto ("coin_sig", 926 &coin_sig)); 927 if (0 != 928 json_array_append_new (j_coins, 929 j_coin)) 930 { 931 GNUNET_break (0); 932 json_decref (j_coins); 933 json_decref (j_output_tokens); 934 if ( (NULL == poph->wallet_data) && 935 (NULL != wallet_data) ) 936 json_decref (wallet_data); 937 return TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE; 938 } 939 } 940 941 /* Sign use tokens */ 942 if (0 < poph->num_use_tokens) 943 { 944 j_tokens = json_array (); 945 GNUNET_assert (NULL != j_tokens); 946 for (unsigned int i = 0; i < poph->num_use_tokens; i++) 947 { 948 const struct TALER_MERCHANT_PostOrdersPayUseToken *token 949 = &poph->use_tokens[i]; 950 struct TALER_TokenUseSignatureP token_sig; 951 struct TALER_TokenUsePublicKeyP token_pub; 952 json_t *j_token; 953 954 TALER_wallet_token_use_sign (&poph->h_contract_terms, 955 &wallet_data_hash, 956 &token->token_priv, 957 &token_sig); 958 GNUNET_CRYPTO_eddsa_key_get_public ( 959 &token->token_priv.private_key, 960 &token_pub.public_key); 961 j_token = GNUNET_JSON_PACK ( 962 GNUNET_JSON_pack_data_auto ("token_sig", 963 &token_sig), 964 GNUNET_JSON_pack_data_auto ("token_pub", 965 &token_pub), 966 GNUNET_JSON_pack_data_auto ( 967 "h_issue", 968 &token->issue_pub.public_key->pub_key_hash), 969 TALER_JSON_pack_token_issue_sig ("ub_sig", 970 &token->ub_sig)); 971 if (0 != 972 json_array_append_new (j_tokens, 973 j_token)) 974 { 975 GNUNET_break (0); 976 json_decref (j_coins); 977 json_decref (j_tokens); 978 json_decref (j_output_tokens); 979 if ( (NULL == poph->wallet_data) && 980 (NULL != wallet_data) ) 981 json_decref (wallet_data); 982 return TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE; 983 } 984 } 985 } 986 987 pay_obj = GNUNET_JSON_PACK ( 988 GNUNET_JSON_pack_array_steal ("coins", 989 j_coins), 990 GNUNET_JSON_pack_allow_null ( 991 GNUNET_JSON_pack_array_steal ("tokens", 992 j_tokens)), 993 GNUNET_JSON_pack_allow_null ( 994 GNUNET_JSON_pack_object_incref ("wallet_data", 995 wallet_data)), 996 GNUNET_JSON_pack_allow_null ( 997 GNUNET_JSON_pack_string ("session_id", 998 poph->session_id))); 999 if ( (NULL == poph->wallet_data) && 1000 (NULL != wallet_data) ) 1001 json_decref (wallet_data); 1002 json_decref (j_output_tokens); 1003 } 1004 else 1005 { 1006 /* Frontend mode: coins are already signed */ 1007 j_coins = json_array (); 1008 GNUNET_assert (NULL != j_coins); 1009 for (unsigned int i = 0; i < poph->num_paid_coins; i++) 1010 { 1011 const struct TALER_MERCHANT_PostOrdersPayPaidCoin *pc 1012 = &poph->paid_coins[i]; 1013 struct TALER_DenominationHashP denom_hash; 1014 json_t *j_coin; 1015 1016 TALER_denom_pub_hash (&pc->denom_pub, 1017 &denom_hash); 1018 j_coin = GNUNET_JSON_PACK ( 1019 TALER_JSON_pack_amount ("contribution", 1020 &pc->amount_with_fee), 1021 GNUNET_JSON_pack_data_auto ("coin_pub", 1022 &pc->coin_pub), 1023 GNUNET_JSON_pack_string ("exchange_url", 1024 pc->exchange_url), 1025 GNUNET_JSON_pack_data_auto ("h_denom", 1026 &denom_hash), 1027 TALER_JSON_pack_denom_sig ("ub_sig", 1028 &pc->denom_sig), 1029 GNUNET_JSON_pack_data_auto ("coin_sig", 1030 &pc->coin_sig)); 1031 if (0 != 1032 json_array_append_new (j_coins, 1033 j_coin)) 1034 { 1035 GNUNET_break (0); 1036 json_decref (j_coins); 1037 return TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE; 1038 } 1039 } 1040 1041 /* Build used tokens JSON (frontend mode) */ 1042 if (0 < poph->num_used_tokens) 1043 { 1044 j_tokens = json_array (); 1045 GNUNET_assert (NULL != j_tokens); 1046 for (unsigned int i = 0; i < poph->num_used_tokens; i++) 1047 { 1048 const struct TALER_MERCHANT_PostOrdersPayUsedToken *ut 1049 = &poph->used_tokens[i]; 1050 json_t *j_token; 1051 1052 j_token = GNUNET_JSON_PACK ( 1053 GNUNET_JSON_pack_data_auto ("token_sig", 1054 &ut->token_sig), 1055 GNUNET_JSON_pack_data_auto ("token_pub", 1056 &ut->token_pub), 1057 GNUNET_JSON_pack_data_auto ( 1058 "h_issue", 1059 &ut->issue_pub.public_key->pub_key_hash), 1060 TALER_JSON_pack_token_issue_sig ("ub_sig", 1061 &ut->ub_sig)); 1062 if (0 != 1063 json_array_append_new (j_tokens, 1064 j_token)) 1065 { 1066 GNUNET_break (0); 1067 json_decref (j_coins); 1068 json_decref (j_tokens); 1069 return TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE; 1070 } 1071 } 1072 } 1073 1074 pay_obj = GNUNET_JSON_PACK ( 1075 GNUNET_JSON_pack_array_steal ("coins", 1076 j_coins), 1077 GNUNET_JSON_pack_allow_null ( 1078 GNUNET_JSON_pack_array_steal ("tokens", 1079 j_tokens)), 1080 GNUNET_JSON_pack_allow_null ( 1081 GNUNET_JSON_pack_object_incref ("wallet_data", 1082 poph->wallet_data)), 1083 GNUNET_JSON_pack_allow_null ( 1084 GNUNET_JSON_pack_string ("session_id", 1085 poph->session_id))); 1086 } 1087 1088 eh = TALER_MERCHANT_curl_easy_get_ (poph->url); 1089 if ( (NULL == eh) || 1090 (GNUNET_OK != 1091 TALER_curl_easy_post (&poph->post_ctx, 1092 eh, 1093 pay_obj)) ) 1094 { 1095 GNUNET_break (0); 1096 json_decref (pay_obj); 1097 if (NULL != eh) 1098 curl_easy_cleanup (eh); 1099 return TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE; 1100 } 1101 json_decref (pay_obj); 1102 poph->job = GNUNET_CURL_job_add2 (poph->ctx, 1103 eh, 1104 poph->post_ctx.headers, 1105 &handle_pay_finished, 1106 poph); 1107 if (NULL == poph->job) 1108 return TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE; 1109 return TALER_EC_NONE; 1110 } 1111 1112 1113 void 1114 TALER_MERCHANT_post_orders_pay_cancel ( 1115 struct TALER_MERCHANT_PostOrdersPayHandle *poph) 1116 { 1117 if (NULL != poph->job) 1118 { 1119 GNUNET_CURL_job_cancel (poph->job); 1120 poph->job = NULL; 1121 } 1122 TALER_curl_easy_post_finished (&poph->post_ctx); 1123 if (NULL != poph->paid_coins) 1124 { 1125 for (unsigned int i = 0; i < poph->num_paid_coins; i++) 1126 { 1127 TALER_denom_pub_free (&poph->paid_coins[i].denom_pub); 1128 TALER_denom_sig_free (&poph->paid_coins[i].denom_sig); 1129 GNUNET_free (poph->paid_coins[i].exchange_url); 1130 } 1131 GNUNET_free (poph->paid_coins); 1132 } 1133 if (NULL != poph->coins) 1134 { 1135 for (unsigned int i = 0; i < poph->num_coins; i++) 1136 { 1137 TALER_denom_pub_free (&poph->coins[i].denom_pub); 1138 TALER_denom_sig_free (&poph->coins[i].denom_sig); 1139 GNUNET_free (poph->coins[i].exchange_url); 1140 } 1141 GNUNET_free (poph->coins); 1142 } 1143 for (size_t j = 0; j<poph->num_donau_bkps; j++) 1144 { 1145 struct DONAU_BlindedUniqueDonorIdentifierKeyPair *bpk 1146 = &poph->donau_bkps[j]; 1147 1148 GNUNET_CRYPTO_blinded_message_decref (bpk->blinded_udi.blinded_message); 1149 } 1150 GNUNET_free (poph->donau_bkps); 1151 GNUNET_free (poph->donau_url); 1152 GNUNET_free (poph->used_tokens); 1153 GNUNET_free (poph->use_tokens); 1154 GNUNET_free (poph->output_tokens); 1155 json_decref (poph->output_tokens_json); 1156 json_decref (poph->wallet_data); 1157 GNUNET_free (poph->session_id); 1158 GNUNET_free (poph->order_id); 1159 GNUNET_free (poph->url); 1160 GNUNET_free (poph->base_url); 1161 GNUNET_free (poph); 1162 } 1163 1164 1165 /* end of merchant_api_post-orders-ORDER_ID-pay-new.c */