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