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