taler-merchant-httpd_get-private-kyc.c (50882B)
1 /* 2 This file is part of GNU Taler 3 (C) 2021-2026 Taler Systems SA 4 5 GNU Taler is free software; you can redistribute it and/or modify 6 it under the terms of the GNU Affero General Public License as 7 published by the Free Software Foundation; either version 3, 8 or (at your option) any later version. 9 10 GNU Taler is distributed in the hope that it will be useful, but 11 WITHOUT ANY WARRANTY; without even the implied warranty of 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 GNU General Public License for more details. 14 15 You should have received a copy of the GNU General Public 16 License along with TALER; see the file COPYING. If not, 17 see <http://www.gnu.org/licenses/> 18 */ 19 20 /** 21 * @file src/backend/taler-merchant-httpd_get-private-kyc.c 22 * @brief implementing GET /instances/$ID/kyc request handling 23 * @author Christian Grothoff 24 */ 25 #include "platform.h" 26 #include "taler-merchant-httpd_exchanges.h" 27 #include "taler-merchant-httpd_get-private-kyc.h" 28 #include "taler-merchant-httpd_kyc-order.h" 29 #include "taler-merchant-httpd_helper.h" 30 #include "taler-merchant-httpd_get-exchanges.h" 31 #include <taler/taler_json_lib.h> 32 #include <taler/taler_templating_lib.h> 33 #include <taler/taler_dbevents.h> 34 #include <regex.h> 35 #include "merchant-database/iterate_kyc_statuses.h" 36 #include "merchant-database/event_listen.h" 37 #include "merchant-database/set_instance.h" 38 #include "merchant-database/get_tos_accepted_early.h" 39 40 /** 41 * Information we keep per /kyc request. 42 */ 43 struct KycContext; 44 45 46 /** 47 * Structure for tracking requests to the exchange's 48 * ``/kyc-check`` API. 49 */ 50 struct ExchangeKycRequest 51 { 52 /** 53 * Kept in a DLL. 54 */ 55 struct ExchangeKycRequest *next; 56 57 /** 58 * Kept in a DLL. 59 */ 60 struct ExchangeKycRequest *prev; 61 62 /** 63 * Find operation where we connect to the respective exchange. 64 */ 65 struct TMH_EXCHANGES_KeysOperation *fo; 66 67 /** 68 * JSON array of payto-URIs with KYC auth wire transfer 69 * instructions. Provided if @e auth_ok is false and 70 * @e kyc_auth_conflict is false. 71 */ 72 json_t *pkaa; 73 74 /** 75 * The keys of the exchange. 76 */ 77 struct TALER_EXCHANGE_Keys *keys; 78 79 /** 80 * KYC request this exchange request is made for. 81 */ 82 struct KycContext *kc; 83 84 /** 85 * JSON array of AccountLimits that apply, NULL if 86 * unknown (and likely defaults apply). 87 */ 88 json_t *jlimits; 89 90 /** 91 * Our account's payto URI. 92 */ 93 struct TALER_FullPayto payto_uri; 94 95 /** 96 * Base URL of the exchange. 97 */ 98 char *exchange_url; 99 100 /** 101 * Hash of the wire account (with salt) we are checking. 102 */ 103 struct TALER_MerchantWireHashP h_wire; 104 105 /** 106 * Current access token for the KYC SPA. Only set 107 * if @e auth_ok is true. 108 */ 109 struct TALER_AccountAccessTokenP access_token; 110 111 /** 112 * Timestamp when we last got a reply from the exchange. 113 */ 114 struct GNUNET_TIME_Timestamp last_check; 115 116 /** 117 * Last HTTP status code obtained via /kyc-check from the exchange. 118 */ 119 unsigned int last_http_status; 120 121 /** 122 * Last Taler error code returned from /kyc-check. 123 */ 124 enum TALER_ErrorCode last_ec; 125 126 /** 127 * True if this account cannot work at this exchange because KYC auth is 128 * impossible. 129 */ 130 bool kyc_auth_conflict; 131 132 /** 133 * We could not get /keys from the exchange. 134 */ 135 bool no_keys; 136 137 /** 138 * True if @e access_token is available. 139 */ 140 bool auth_ok; 141 142 /** 143 * True if we believe no KYC is currently required 144 * for this account at this exchange. 145 */ 146 bool kyc_ok; 147 148 /** 149 * True if the exchange exposed to us that the account 150 * is currently under AML review. 151 */ 152 bool in_aml_review; 153 154 }; 155 156 157 /** 158 * Information we keep per /kyc request. 159 */ 160 struct KycContext 161 { 162 /** 163 * Stored in a DLL. 164 */ 165 struct KycContext *next; 166 167 /** 168 * Stored in a DLL. 169 */ 170 struct KycContext *prev; 171 172 /** 173 * Connection we are handling. 174 */ 175 struct MHD_Connection *connection; 176 177 /** 178 * Instance we are serving. 179 */ 180 struct TMH_MerchantInstance *mi; 181 182 /** 183 * Our handler context. 184 */ 185 struct TMH_HandlerContext *hc; 186 187 /** 188 * JSON array where we are building up the array with 189 * pending KYC operations. 190 */ 191 json_t *kycs_data; 192 193 /** 194 * Head of DLL of requests we are making to an 195 * exchange to inquire about the latest KYC status. 196 */ 197 struct ExchangeKycRequest *exchange_pending_head; 198 199 /** 200 * Tail of DLL of requests we are making to an 201 * exchange to inquire about the latest KYC status. 202 */ 203 struct ExchangeKycRequest *exchange_pending_tail; 204 205 /** 206 * Notification handler from database on changes 207 * to the KYC status. 208 */ 209 struct GNUNET_DB_EventHandler *eh; 210 211 /** 212 * Set to the exchange URL, or NULL to not filter by 213 * exchange. "exchange_url" query parameter. 214 */ 215 const char *exchange_url; 216 217 /** 218 * How long are we willing to wait for the exchange(s)? 219 * Based on "timeout_ms" query parameter. 220 */ 221 struct GNUNET_TIME_Absolute timeout; 222 223 /** 224 * Set to the h_wire of the merchant account if 225 * @a have_h_wire is true, used to filter by account. 226 * Set from "h_wire" query parameter. 227 */ 228 struct TALER_MerchantWireHashP h_wire; 229 230 /** 231 * Set to the Etag of a response already known to the 232 * client. We should only return from long-polling 233 * on timeout (with "Not Modified") or when the Etag 234 * of the response differs from what is given here. 235 * Only set if @a have_lp_not_etag is true. 236 * Set from "lp_etag" query parameter. 237 */ 238 struct GNUNET_ShortHashCode lp_not_etag; 239 240 /** 241 * Specifies what status change we are long-polling for. If specified, the 242 * endpoint will only return once the status *matches* the given value. If 243 * multiple accounts or exchanges match the query, any account reaching the 244 * STATUS will cause the response to be returned. 245 */ 246 const char *lp_status; 247 248 /** 249 * Specifies what status change we are long-polling for. If specified, the 250 * endpoint will only return once the status no longer matches the given 251 * value. If multiple accounts or exchanges *no longer matches* the given 252 * STATUS will cause the response to be returned. 253 */ 254 const char *lp_not_status; 255 256 /** 257 * #GNUNET_NO if the @e connection was not suspended, 258 * #GNUNET_YES if the @e connection was suspended, 259 * #GNUNET_SYSERR if @e connection was resumed to as 260 * part of #MH_force_pc_resume during shutdown. 261 */ 262 enum GNUNET_GenericReturnValue suspended; 263 264 /** 265 * What state are we long-polling for? "lpt" argument. 266 */ 267 enum TALER_EXCHANGE_KycLongPollTarget lpt; 268 269 /** 270 * Processing phase. 271 */ 272 enum 273 { 274 PHASE_INIT = 0, 275 PHASE_DETERMINE_LONG_POLL, 276 PHASE_DATABASE_KYC_CHECK, 277 PHASE_NO_ACCOUNTS, 278 PHASE_GENERATE_RESPONSE, 279 PHASE_IN_SHUTDOWN = 999, 280 PHASE_RETURN_YES, 281 PHASE_RETURN_NO, 282 PHASE_SUSPENDED_ON_ACCOUNT, 283 PHASE_SUSPENDED_ON_EXCHANGE, 284 } phase; 285 286 /** 287 * Output format requested by the client. 288 */ 289 enum 290 { 291 POF_JSON, 292 POF_TEXT, 293 POF_PDF 294 } format; 295 296 /** 297 * Set to true if the database notified us about a change 298 * in the account but we did not yet check the database 299 * status as we were waiting on something else. 300 */ 301 bool account_signal; 302 303 /** 304 * True if @e h_wire was given. 305 */ 306 bool have_h_wire; 307 308 /** 309 * True if @e lp_not_etag was given. 310 */ 311 bool have_lp_not_etag; 312 313 /** 314 * We're still waiting on the exchange to determine 315 * the KYC status of our deposit(s). 316 */ 317 bool return_immediately; 318 319 /** 320 * Are we currently still iterating over the database and 321 * thus must not yet respond? 322 */ 323 bool in_db; 324 }; 325 326 327 /** 328 * Head of DLL. 329 */ 330 static struct KycContext *kc_head; 331 332 /** 333 * Tail of DLL. 334 */ 335 static struct KycContext *kc_tail; 336 337 338 /* ******************* cleanup ***************** */ 339 340 void 341 TMH_force_kyc_resume () 342 { 343 for (struct KycContext *kc = kc_head; 344 NULL != kc; 345 kc = kc->next) 346 { 347 if (GNUNET_YES == kc->suspended) 348 { 349 kc->suspended = GNUNET_SYSERR; 350 kc->phase = PHASE_IN_SHUTDOWN; 351 MHD_resume_connection (kc->connection); 352 } 353 } 354 } 355 356 357 /** 358 * Release resources of @a ekr 359 * 360 * @param[in] ekr key request data to clean up 361 */ 362 static void 363 ekr_cleanup (struct ExchangeKycRequest *ekr) 364 { 365 struct KycContext *kc = ekr->kc; 366 367 GNUNET_CONTAINER_DLL_remove (kc->exchange_pending_head, 368 kc->exchange_pending_tail, 369 ekr); 370 if (NULL != ekr->fo) 371 { 372 TMH_EXCHANGES_keys4exchange_cancel (ekr->fo); 373 ekr->fo = NULL; 374 } 375 json_decref (ekr->pkaa); 376 json_decref (ekr->jlimits); 377 if (NULL != ekr->keys) 378 TALER_EXCHANGE_keys_decref (ekr->keys); 379 GNUNET_free (ekr->exchange_url); 380 GNUNET_free (ekr->payto_uri.full_payto); 381 GNUNET_free (ekr); 382 } 383 384 385 /** 386 * Custom cleanup routine for a `struct KycContext`. 387 * 388 * @param cls the `struct KycContext` to clean up. 389 */ 390 static void 391 kyc_context_cleanup (void *cls) 392 { 393 struct KycContext *kc = cls; 394 struct ExchangeKycRequest *ekr; 395 396 while (NULL != (ekr = kc->exchange_pending_head)) 397 { 398 ekr_cleanup (ekr); 399 } 400 if (NULL != kc->eh) 401 { 402 TALER_MERCHANTDB_event_listen_cancel (kc->eh); 403 kc->eh = NULL; 404 } 405 GNUNET_CONTAINER_DLL_remove (kc_head, 406 kc_tail, 407 kc); 408 json_decref (kc->kycs_data); 409 GNUNET_free (kc); 410 } 411 412 413 /** 414 * Finish handling the connection returning @a ret to MHD 415 * 416 * @param[in,out] kc connection we are handling 417 * @param mhd_ret result to return for the @a kc request 418 */ 419 static void 420 finish_request (struct KycContext *kc, 421 enum MHD_Result mhd_ret) 422 { 423 kc->phase = (MHD_YES == mhd_ret) 424 ? PHASE_RETURN_YES 425 : PHASE_RETURN_NO; 426 } 427 428 429 /* ******************* phase_init ***************** */ 430 431 432 /** 433 * Initialize basic data structures of the connection, 434 * finishes parsing the request. 435 * 436 * @param[in,out] kc connection we are handling 437 */ 438 static void 439 phase_init (struct KycContext *kc) 440 { 441 kc->kycs_data = json_array (); 442 GNUNET_assert (NULL != kc->kycs_data); 443 /* process 'exchange_url' argument */ 444 kc->exchange_url = MHD_lookup_connection_value ( 445 kc->connection, 446 MHD_GET_ARGUMENT_KIND, 447 "exchange_url"); 448 if ( (NULL != kc->exchange_url) && 449 ( (! TALER_url_valid_charset (kc->exchange_url)) || 450 (! TALER_is_web_url (kc->exchange_url)) ) ) 451 { 452 GNUNET_break_op (0); 453 finish_request (kc, 454 TALER_MHD_reply_with_error ( 455 kc->connection, 456 MHD_HTTP_BAD_REQUEST, 457 TALER_EC_GENERIC_PARAMETER_MALFORMED, 458 "exchange_url must be a valid HTTP(s) URL")); 459 return; 460 } 461 462 /* Determine desired output format from Accept header */ 463 { 464 const char *mime; 465 466 mime = MHD_lookup_connection_value (kc->connection, 467 MHD_HEADER_KIND, 468 MHD_HTTP_HEADER_ACCEPT); 469 if (NULL == mime) 470 mime = "application/json"; 471 if (0 == strcmp (mime, 472 "*/*")) 473 mime = "application/json"; 474 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 475 "KYC status requested for format %s\n", 476 mime); 477 if (0 == strcmp (mime, 478 "application/json")) 479 { 480 kc->format = POF_JSON; 481 } 482 else if (0 == strcmp (mime, 483 "text/plain")) 484 { 485 kc->format = POF_TEXT; 486 } 487 #if FUTURE 488 else if (0 == strcmp (mime, 489 "application/pdf")) 490 { 491 kc->format = POF_PDF; 492 } 493 #endif 494 else 495 { 496 GNUNET_break_op (0); 497 finish_request (kc, 498 TALER_MHD_REPLY_JSON_PACK ( 499 kc->connection, 500 MHD_HTTP_NOT_ACCEPTABLE, 501 GNUNET_JSON_pack_string ("hint", 502 mime))); 503 return; 504 } 505 } 506 kc->phase++; 507 } 508 509 510 /* ******************* phase_determine_long_poll ***************** */ 511 512 513 /** 514 * Handle a DB event about an update relevant 515 * for the processing of the kyc request. 516 * 517 * @param cls our `struct KycContext` 518 * @param extra additional event data provided 519 * @param extra_size number of bytes in @a extra 520 */ 521 static void 522 kyc_change_cb (void *cls, 523 const void *extra, 524 size_t extra_size) 525 { 526 struct KycContext *kc = cls; 527 528 if ( (GNUNET_YES == kc->suspended) && 529 (PHASE_SUSPENDED_ON_ACCOUNT == kc->phase) ) 530 { 531 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 532 "Resuming KYC with gateway timeout\n"); 533 kc->suspended = GNUNET_NO; 534 kc->phase = PHASE_DATABASE_KYC_CHECK; 535 MHD_resume_connection (kc->connection); 536 TALER_MHD_daemon_trigger (); /* we resumed, kick MHD */ 537 } 538 else 539 { 540 /* remember for later */ 541 kc->account_signal = true; 542 } 543 } 544 545 546 /** 547 * Suspend @a kc until we have a change in the account status. 548 * 549 * @param[in,out] kc request to suspend 550 */ 551 static void 552 wait_for_account (struct KycContext *kc) 553 { 554 GNUNET_assert (GNUNET_NO == kc->suspended); 555 if (kc->account_signal) 556 { 557 /* we got a NOTIFY earlier, handle it immediately */ 558 kc->account_signal = false; 559 kc->phase = PHASE_DATABASE_KYC_CHECK; 560 return; 561 } 562 /* Wait on account notification */ 563 MHD_suspend_connection (kc->connection); 564 kc->suspended = GNUNET_YES; 565 kc->phase = PHASE_SUSPENDED_ON_ACCOUNT; 566 } 567 568 569 /** 570 * Setup long-polling for the connection, if applicable. 571 * 572 * @param[in,out] kc connection we are handling 573 */ 574 static void 575 phase_determine_long_poll (struct KycContext *kc) 576 { 577 if (GNUNET_TIME_absolute_is_past (kc->timeout)) 578 { 579 kc->phase++; 580 return; 581 } 582 if (kc->have_h_wire) 583 { 584 struct TALER_MERCHANTDB_MerchantKycStatusChangeEventP ev = { 585 .header.size = htons (sizeof (ev)), 586 .header.type = htons ( 587 TALER_DBEVENT_MERCHANT_EXCHANGE_KYC_STATUS_CHANGED 588 ), 589 .h_wire = kc->h_wire 590 }; 591 592 kc->eh = TALER_MERCHANTDB_event_listen ( 593 TMH_db, 594 &ev.header, 595 GNUNET_TIME_absolute_get_remaining (kc->timeout), 596 &kyc_change_cb, 597 kc); 598 } 599 else 600 { 601 struct GNUNET_DB_EventHeaderP hdr = { 602 .size = htons (sizeof (hdr)), 603 .type = htons (TALER_DBEVENT_MERCHANT_KYC_STATUS_CHANGED) 604 }; 605 606 kc->eh = TALER_MERCHANTDB_event_listen ( 607 TMH_db, 608 &hdr, 609 GNUNET_TIME_absolute_get_remaining (kc->timeout), 610 &kyc_change_cb, 611 kc); 612 } 613 kc->phase++; 614 } 615 616 617 /* ***************** phase_database_kyc_check ************** */ 618 619 620 /** 621 * Maps @a ekr to a status code for clients to interpret the 622 * overall result. 623 * 624 * @param ekr request summary 625 * @return status of the KYC state as a string 626 */ 627 static const char * 628 map_to_status (const struct ExchangeKycRequest *ekr) 629 { 630 if (ekr->no_keys) 631 { 632 return "no-exchange-keys"; 633 } 634 if (TALER_EC_MERCHANT_PRIVATE_ACCOUNT_NOT_ELIGIBLE_FOR_EXCHANGE == 635 ekr->last_ec) 636 return "unsupported-account"; 637 if (ekr->kyc_ok) 638 { 639 if (NULL != ekr->jlimits) 640 { 641 size_t off; 642 json_t *limit; 643 json_array_foreach (ekr->jlimits, off, limit) 644 { 645 struct TALER_Amount threshold; 646 enum TALER_KYCLOGIC_KycTriggerEvent operation_type; 647 bool soft = false; 648 struct GNUNET_JSON_Specification spec[] = { 649 TALER_JSON_spec_kycte ("operation_type", 650 &operation_type), 651 TALER_JSON_spec_amount_any ("threshold", 652 &threshold), 653 GNUNET_JSON_spec_mark_optional ( 654 GNUNET_JSON_spec_bool ("soft_limit", 655 &soft), 656 NULL), 657 GNUNET_JSON_spec_end () 658 }; 659 660 if (GNUNET_OK != 661 GNUNET_JSON_parse (limit, 662 spec, 663 NULL, NULL)) 664 { 665 GNUNET_break (0); 666 return "merchant-internal-error"; 667 } 668 if (! TALER_amount_is_zero (&threshold)) 669 continue; /* only care about zero-limits */ 670 if (! soft) 671 continue; /* only care about soft limits */ 672 if ( (operation_type == TALER_KYCLOGIC_KYC_TRIGGER_DEPOSIT) || 673 (operation_type == TALER_KYCLOGIC_KYC_TRIGGER_AGGREGATE) || 674 (operation_type == TALER_KYCLOGIC_KYC_TRIGGER_TRANSACTION) ) 675 { 676 if (! ekr->auth_ok) 677 { 678 if (ekr->kyc_auth_conflict) 679 return "kyc-wire-impossible"; 680 return "kyc-wire-required"; 681 } 682 return "kyc-required"; 683 } 684 } 685 } 686 if (NULL == ekr->jlimits) 687 { 688 /* check default limits */ 689 const struct TALER_EXCHANGE_Keys *keys = ekr->keys; 690 691 for (unsigned int i = 0; i < keys->zero_limits_length; i++) 692 { 693 enum TALER_KYCLOGIC_KycTriggerEvent operation_type 694 = keys->zero_limits[i].operation_type; 695 696 if ( (operation_type == TALER_KYCLOGIC_KYC_TRIGGER_DEPOSIT) || 697 (operation_type == TALER_KYCLOGIC_KYC_TRIGGER_AGGREGATE) || 698 (operation_type == TALER_KYCLOGIC_KYC_TRIGGER_TRANSACTION) ) 699 { 700 if (! ekr->auth_ok) 701 { 702 if (ekr->kyc_auth_conflict) 703 return "kyc-wire-impossible"; 704 return "kyc-wire-required"; 705 } 706 return "kyc-required"; 707 } 708 } 709 } 710 return "ready"; 711 } 712 if (! ekr->auth_ok) 713 { 714 if (ekr->kyc_auth_conflict) 715 return "kyc-wire-impossible"; 716 return "kyc-wire-required"; 717 } 718 if (ekr->in_aml_review) 719 return "awaiting-aml-review"; 720 switch (ekr->last_http_status) 721 { 722 case 0: 723 return "exchange-unreachable"; 724 case MHD_HTTP_OK: 725 /* then we should have kyc_ok */ 726 GNUNET_break (0); 727 return NULL; 728 case MHD_HTTP_ACCEPTED: 729 /* Then KYC is really what is needed */ 730 return "kyc-required"; 731 case MHD_HTTP_NO_CONTENT: 732 /* then we should have had kyc_ok! */ 733 GNUNET_break (0); 734 return NULL; 735 case MHD_HTTP_FORBIDDEN: 736 /* then we should have had ! auth_ok */ 737 GNUNET_break (0); 738 return NULL; 739 case MHD_HTTP_NOT_FOUND: 740 /* then we should have had ! auth_ok */ 741 GNUNET_break (0); 742 return NULL; 743 case MHD_HTTP_CONFLICT: 744 /* then we should have had ! auth_ok */ 745 GNUNET_break (0); 746 return NULL; 747 case MHD_HTTP_INTERNAL_SERVER_ERROR: 748 return "exchange-internal-error"; 749 case MHD_HTTP_GATEWAY_TIMEOUT: 750 return "exchange-gateway-timeout"; 751 default: 752 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 753 "Exchange responded with unexpected HTTP status %u to /kyc-check request!\n", 754 ekr->last_http_status); 755 break; 756 } 757 return "exchange-status-invalid"; 758 } 759 760 761 /** 762 * We have found an exchange in status @a status. Clear any 763 * long-pollers that wait for us having (or not having) this 764 * status. 765 * 766 * @param[in,out] kc context 767 * @param status the status we encountered 768 */ 769 static void 770 clear_status (struct KycContext *kc, 771 const char *status) 772 { 773 if ( (NULL != kc->lp_status) && 774 (0 == strcmp (kc->lp_status, 775 status)) ) 776 kc->lp_status = NULL; /* satisfied! */ 777 if ( (NULL != kc->lp_not_status) && 778 (0 != strcmp (kc->lp_not_status, 779 status) ) ) 780 kc->lp_not_status = NULL; /* satisfied! */ 781 } 782 783 784 /** 785 * Pack the given @a limit into the JSON @a limits array. 786 * 787 * @param kc overall request context 788 * @param limit account limit to pack 789 * @param[in,out] limits JSON array to extend 790 */ 791 static void 792 pack_limit (const struct KycContext *kc, 793 const struct TALER_EXCHANGE_AccountLimit *limit, 794 json_t *limits) 795 { 796 json_t *jl; 797 798 jl = GNUNET_JSON_PACK ( 799 TALER_JSON_pack_kycte ("operation_type", 800 limit->operation_type), 801 (POF_TEXT == kc->format) 802 ? GNUNET_JSON_pack_string ("interval", 803 GNUNET_TIME_relative2s (limit->timeframe, 804 true)) 805 : GNUNET_JSON_pack_time_rel ("timeframe", 806 limit->timeframe), 807 TALER_JSON_pack_amount ("threshold", 808 &limit->threshold), 809 GNUNET_JSON_pack_bool ("soft_limit", 810 limit->soft_limit) 811 ); 812 GNUNET_assert (0 == 813 json_array_append_new (limits, 814 jl)); 815 } 816 817 818 /** 819 * Return JSON array with AccountLimit objects giving 820 * the current limits for this exchange. 821 * 822 * @param[in,out] ekr overall request context 823 */ 824 static json_t * 825 get_exchange_limits ( 826 struct ExchangeKycRequest *ekr) 827 { 828 const struct TALER_EXCHANGE_Keys *keys = ekr->keys; 829 json_t *limits; 830 831 if (NULL != ekr->jlimits) 832 { 833 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 834 "Returning custom KYC limits\n"); 835 return json_incref (ekr->jlimits); 836 } 837 if (NULL == keys) 838 { 839 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 840 "No keys, thus no default KYC limits known\n"); 841 return NULL; 842 } 843 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 844 "Returning default KYC limits (%u/%u)\n", 845 keys->hard_limits_length, 846 keys->zero_limits_length); 847 limits = json_array (); 848 GNUNET_assert (NULL != limits); 849 for (unsigned int i = 0; i<keys->hard_limits_length; i++) 850 { 851 const struct TALER_EXCHANGE_AccountLimit *limit 852 = &keys->hard_limits[i]; 853 854 pack_limit (ekr->kc, 855 limit, 856 limits); 857 } 858 for (unsigned int i = 0; i<keys->zero_limits_length; i++) 859 { 860 const struct TALER_EXCHANGE_ZeroLimitedOperation *zlimit 861 = &keys->zero_limits[i]; 862 json_t *jl; 863 struct TALER_Amount zero; 864 865 GNUNET_assert (GNUNET_OK == 866 TALER_amount_set_zero (keys->currency, 867 &zero)); 868 jl = GNUNET_JSON_PACK ( 869 TALER_JSON_pack_kycte ("operation_type", 870 zlimit->operation_type), 871 GNUNET_JSON_pack_bool ( 872 "disallowed", 873 true), 874 (POF_TEXT == ekr->kc->format) 875 ? GNUNET_JSON_pack_string ( 876 "interval", 877 GNUNET_TIME_relative2s (GNUNET_TIME_UNIT_ZERO, 878 true)) 879 : GNUNET_JSON_pack_time_rel ("timeframe", 880 GNUNET_TIME_UNIT_ZERO), 881 TALER_JSON_pack_amount ("threshold", 882 &zero), 883 GNUNET_JSON_pack_bool ("soft_limit", 884 true) 885 ); 886 GNUNET_assert (0 == 887 json_array_append_new (limits, 888 jl)); 889 } 890 return limits; 891 } 892 893 894 /** 895 * Take data from @a ekr to expand our response. 896 * 897 * @param ekr exchange we are done inspecting 898 */ 899 static void 900 ekr_expand_response (struct ExchangeKycRequest *ekr) 901 { 902 const struct KycContext *kc = ekr->kc; 903 struct TMH_Exchange *e = TMH_EXCHANGES_lookup_exchange (ekr->exchange_url); 904 const char *status; 905 const char *q; 906 char *short_account; 907 bool kyc_swap_tos_acceptance = false; 908 char *tos_accepted_early = NULL; 909 910 GNUNET_assert (NULL != e); 911 status = map_to_status (ekr); 912 if (NULL == status) 913 { 914 GNUNET_break (0); 915 status = "logic-bug"; 916 } 917 clear_status (ekr->kc, 918 status); 919 q = strchr (ekr->payto_uri.full_payto, 920 '?'); 921 if (NULL == q) 922 short_account = GNUNET_strdup (ekr->payto_uri.full_payto); 923 else 924 short_account = GNUNET_strndup (ekr->payto_uri.full_payto, 925 q - ekr->payto_uri.full_payto); 926 if (NULL != ekr->keys) 927 kyc_swap_tos_acceptance = ekr->keys->kyc_swap_tos_acceptance; 928 { 929 enum GNUNET_DB_QueryStatus qs; 930 931 qs = TALER_MERCHANTDB_set_instance ( 932 TMH_db, 933 kc->mi->settings.id); 934 if (0 >= qs) 935 { 936 GNUNET_break (0); 937 tos_accepted_early = NULL; 938 } 939 else 940 { 941 qs = TALER_MERCHANTDB_get_tos_accepted_early (TMH_db, 942 kc->mi->settings.id, 943 ekr->exchange_url, 944 &tos_accepted_early); 945 GNUNET_break (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT == 946 TALER_MERCHANTDB_set_instance ( 947 TMH_db, 948 NULL)); 949 if (qs < 0) 950 { 951 GNUNET_break (0); 952 /* fall through with tos_accepted_early == NULL */ 953 tos_accepted_early = NULL; 954 } 955 } 956 } 957 GNUNET_assert ( 958 0 == 959 json_array_append_new ( 960 ekr->kc->kycs_data, 961 GNUNET_JSON_PACK ( 962 (POF_TEXT == kc->format) 963 ? GNUNET_JSON_pack_string ( 964 "short_payto_uri", 965 short_account) 966 : TALER_JSON_pack_full_payto ( 967 "payto_uri", 968 ekr->payto_uri), 969 GNUNET_JSON_pack_data_auto ( 970 "h_wire", 971 &ekr->h_wire), 972 GNUNET_JSON_pack_string ( 973 "status", 974 status), 975 GNUNET_JSON_pack_string ( 976 "exchange_url", 977 ekr->exchange_url), 978 GNUNET_JSON_pack_string ( 979 "exchange_currency", 980 TMH_EXCHANGES_get_currency (e)), 981 GNUNET_JSON_pack_bool ("no_keys", 982 ekr->no_keys), 983 GNUNET_JSON_pack_bool ("auth_conflict", 984 ekr->kyc_auth_conflict), 985 GNUNET_JSON_pack_bool ("kyc_swap_tos_acceptance", 986 kyc_swap_tos_acceptance), 987 GNUNET_JSON_pack_allow_null ( 988 GNUNET_JSON_pack_string ( 989 "tos_accepted_early", 990 tos_accepted_early)), 991 GNUNET_JSON_pack_uint64 ("exchange_http_status", 992 ekr->last_http_status), 993 GNUNET_JSON_pack_conditional ( 994 TALER_EC_NONE != ekr->last_ec, 995 GNUNET_JSON_pack_uint64 ("exchange_code", 996 ekr->last_ec)), 997 GNUNET_JSON_pack_conditional ( 998 ekr->auth_ok, 999 GNUNET_JSON_pack_data_auto ( 1000 "access_token", 1001 &ekr->access_token)), 1002 GNUNET_JSON_pack_allow_null ( 1003 GNUNET_JSON_pack_array_steal ( 1004 "limits", 1005 get_exchange_limits (ekr))), 1006 GNUNET_JSON_pack_allow_null ( 1007 GNUNET_JSON_pack_array_incref ("payto_kycauths", 1008 ekr->pkaa)) 1009 ))); 1010 GNUNET_free (tos_accepted_early); 1011 GNUNET_free (short_account); 1012 } 1013 1014 1015 /** 1016 * We are done with the KYC request @a ekr. Remove it from the work list and 1017 * check if we are done overall. 1018 * 1019 * @param[in] ekr key request that is done (and will be freed) 1020 */ 1021 static void 1022 ekr_finished (struct ExchangeKycRequest *ekr) 1023 { 1024 struct KycContext *kc = ekr->kc; 1025 1026 ekr_expand_response (ekr); 1027 ekr_cleanup (ekr); 1028 if (NULL != kc->exchange_pending_head) 1029 return; /* wait for more */ 1030 if (kc->in_db) 1031 return; 1032 GNUNET_assert (GNUNET_YES == kc->suspended); 1033 kc->phase = PHASE_GENERATE_RESPONSE; 1034 kc->suspended = GNUNET_NO; 1035 MHD_resume_connection (kc->connection); 1036 TALER_MHD_daemon_trigger (); /* we resumed, kick MHD */ 1037 } 1038 1039 1040 /** 1041 * Figure out which exchange accounts from @a keys could 1042 * be used for a KYC auth wire transfer from the account 1043 * that @a ekr is checking. Will set the "pkaa" array 1044 * in @a ekr. 1045 * 1046 * @param[in,out] ekr request we are processing 1047 */ 1048 static void 1049 determine_eligible_accounts ( 1050 struct ExchangeKycRequest *ekr) 1051 { 1052 struct KycContext *kc = ekr->kc; 1053 const struct TALER_EXCHANGE_Keys *keys = ekr->keys; 1054 struct TALER_Amount kyc_amount; 1055 char *merchant_pub_str; 1056 struct TALER_NormalizedPayto np; 1057 1058 { 1059 const struct TALER_EXCHANGE_GlobalFee *gf; 1060 1061 gf = TALER_EXCHANGE_get_global_fee (keys, 1062 GNUNET_TIME_timestamp_get ()); 1063 if (NULL == gf) 1064 { 1065 GNUNET_assert (GNUNET_OK == 1066 TALER_amount_set_zero (keys->currency, 1067 &kyc_amount)); 1068 } 1069 else 1070 { 1071 /* FIXME-#9427: history fee should be globally renamed to KYC fee... */ 1072 kyc_amount = gf->fees.history; 1073 } 1074 } 1075 1076 merchant_pub_str 1077 = GNUNET_STRINGS_data_to_string_alloc ( 1078 &kc->mi->merchant_pub, 1079 sizeof (kc->mi->merchant_pub)); 1080 /* For all accounts of the exchange */ 1081 np = TALER_payto_normalize (ekr->payto_uri); 1082 for (unsigned int i = 0; i<keys->accounts_len; i++) 1083 { 1084 const struct TALER_EXCHANGE_WireAccount *account 1085 = &keys->accounts[i]; 1086 1087 /* KYC auth transfers are never supported with conversion */ 1088 if (NULL != account->conversion_url) 1089 continue; 1090 /* filter by source account by credit_restrictions */ 1091 if (GNUNET_YES != 1092 TALER_EXCHANGE_test_account_allowed (account, 1093 true, /* credit */ 1094 np)) 1095 continue; 1096 /* exchange account is allowed, add it */ 1097 // FIXME: #11520: support short wire transfer subjects! 1098 // if (NULL != account->prepared_transfer_url) // ... 1099 { 1100 const char *exchange_account_payto 1101 = account->fpayto_uri.full_payto; 1102 char *payto_kycauth; 1103 1104 if (TALER_amount_is_zero (&kyc_amount)) 1105 GNUNET_asprintf (&payto_kycauth, 1106 "%s%cmessage=KYC:%s", 1107 exchange_account_payto, 1108 (NULL == strchr (exchange_account_payto, 1109 '?')) 1110 ? '?' 1111 : '&', 1112 merchant_pub_str); 1113 else 1114 GNUNET_asprintf (&payto_kycauth, 1115 "%s%camount=%s&message=KYC:%s", 1116 exchange_account_payto, 1117 (NULL == strchr (exchange_account_payto, 1118 '?')) 1119 ? '?' 1120 : '&', 1121 TALER_amount2s (&kyc_amount), 1122 merchant_pub_str); 1123 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 1124 "Found account %s where KYC auth is possible\n", 1125 payto_kycauth); 1126 GNUNET_assert (0 == 1127 json_array_append_new (ekr->pkaa, 1128 json_string (payto_kycauth))); 1129 GNUNET_free (payto_kycauth); 1130 } 1131 } 1132 GNUNET_free (np.normalized_payto); 1133 GNUNET_free (merchant_pub_str); 1134 } 1135 1136 1137 /** 1138 * Function called with the result of a #TMH_EXCHANGES_keys4exchange() 1139 * operation. Runs the KYC check against the exchange. 1140 * 1141 * @param cls closure with our `struct ExchangeKycRequest *` 1142 * @param keys keys of the exchange context 1143 * @param exchange representation of the exchange 1144 */ 1145 static void 1146 kyc_with_exchange (void *cls, 1147 struct TALER_EXCHANGE_Keys *keys, 1148 struct TMH_Exchange *exchange) 1149 { 1150 struct ExchangeKycRequest *ekr = cls; 1151 1152 (void) exchange; 1153 ekr->fo = NULL; 1154 if (NULL == keys) 1155 { 1156 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 1157 "Failed to download `%skeys`\n", 1158 ekr->exchange_url); 1159 ekr->no_keys = true; 1160 ekr_finished (ekr); 1161 return; 1162 } 1163 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 1164 "Got /keys for `%s'\n", 1165 ekr->exchange_url); 1166 ekr->keys = TALER_EXCHANGE_keys_incref (keys); 1167 if (! ekr->auth_ok) 1168 { 1169 ekr->pkaa = json_array (); 1170 GNUNET_assert (NULL != ekr->pkaa); 1171 determine_eligible_accounts (ekr); 1172 if (0 == json_array_size (ekr->pkaa)) 1173 { 1174 /* No KYC auth wire transfers are possible to this exchange from 1175 our merchant bank account, so we cannot use this account with 1176 this exchange if it has any KYC requirements! */ 1177 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 1178 "KYC auth to `%s' impossible for merchant account `%s'\n", 1179 ekr->exchange_url, 1180 ekr->payto_uri.full_payto); 1181 ekr->kyc_auth_conflict = true; 1182 } 1183 } 1184 ekr_finished (ekr); 1185 } 1186 1187 1188 /** 1189 * Closure for add_unreachable_status(). 1190 */ 1191 struct UnreachableContext 1192 { 1193 /** 1194 * Where we are building the response. 1195 */ 1196 struct KycContext *kc; 1197 1198 /** 1199 * Pointer to our account hash. 1200 */ 1201 const struct TALER_MerchantWireHashP *h_wire; 1202 1203 /** 1204 * Bank account for which we have no status from any exchange. 1205 */ 1206 struct TALER_FullPayto payto_uri; 1207 1208 }; 1209 1210 1211 /** 1212 * Add all trusted exchanges with "unknown" status for the 1213 * bank account given in the context. 1214 * 1215 * @param cls a `struct UnreachableContext` 1216 * @param url base URL of the exchange 1217 * @param exchange internal handle for the exchange 1218 */ 1219 static void 1220 add_unreachable_status (void *cls, 1221 const char *url, 1222 const struct TMH_Exchange *exchange) 1223 { 1224 struct UnreachableContext *uc = cls; 1225 struct KycContext *kc = uc->kc; 1226 1227 clear_status (kc, 1228 "exchange-unreachable"); 1229 GNUNET_assert ( 1230 0 == 1231 json_array_append_new ( 1232 kc->kycs_data, 1233 GNUNET_JSON_PACK ( 1234 TALER_JSON_pack_full_payto ( 1235 "payto_uri", 1236 uc->payto_uri), 1237 GNUNET_JSON_pack_data_auto ( 1238 "h_wire", 1239 uc->h_wire), 1240 GNUNET_JSON_pack_string ( 1241 "exchange_currency", 1242 TMH_EXCHANGES_get_currency (exchange)), 1243 GNUNET_JSON_pack_string ( 1244 "status", 1245 "exchange-unreachable"), 1246 GNUNET_JSON_pack_string ( 1247 "exchange_url", 1248 url), 1249 GNUNET_JSON_pack_bool ("no_keys", 1250 true), 1251 GNUNET_JSON_pack_bool ("auth_conflict", 1252 false), 1253 GNUNET_JSON_pack_uint64 ("exchange_http_status", 1254 0) 1255 ))); 1256 1257 } 1258 1259 1260 /** 1261 * Function called from iterate_kyc_statuses() with KYC status information 1262 * for this merchant. 1263 * 1264 * @param cls our `struct KycContext *` 1265 * @param h_wire hash of the wire account 1266 * @param payto_uri payto:// URI of the merchant's bank account 1267 * @param exchange_url base URL of the exchange for which this is a status 1268 * @param last_check when did we last get an update on our KYC status from the exchange 1269 * @param kyc_ok true if we satisfied the KYC requirements 1270 * @param access_token access token for the KYC SPA, NULL if we cannot access it yet (need KYC auth wire transfer) 1271 * @param last_http_status last HTTP status from /kyc-check 1272 * @param last_ec last Taler error code from /kyc-check 1273 * @param in_aml_review true if the account is pending review 1274 * @param jlimits JSON array of applicable AccountLimits, or NULL if unknown (like defaults apply) 1275 */ 1276 static void 1277 kyc_status_cb ( 1278 void *cls, 1279 const struct TALER_MerchantWireHashP *h_wire, 1280 struct TALER_FullPayto payto_uri, 1281 const char *exchange_url, 1282 struct GNUNET_TIME_Timestamp last_check, 1283 bool kyc_ok, 1284 const struct TALER_AccountAccessTokenP *access_token, 1285 unsigned int last_http_status, 1286 enum TALER_ErrorCode last_ec, 1287 bool in_aml_review, 1288 const json_t *jlimits) 1289 { 1290 struct KycContext *kc = cls; 1291 struct ExchangeKycRequest *ekr; 1292 1293 if (NULL == exchange_url) 1294 { 1295 struct UnreachableContext uc = { 1296 .kc = kc, 1297 .h_wire = h_wire, 1298 .payto_uri = payto_uri 1299 }; 1300 1301 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 1302 "Account has unknown KYC status for all exchanges.\n"); 1303 TMH_exchange_get_trusted (&add_unreachable_status, 1304 &uc); 1305 return; 1306 } 1307 if (! TMH_EXCHANGES_check_trusted (exchange_url)) 1308 { 1309 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 1310 "Skipping exchange `%s': not trusted\n", 1311 exchange_url); 1312 return; 1313 } 1314 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 1315 "KYC status for `%s' at `%s' is %u/%s/%s/%s\n", 1316 payto_uri.full_payto, 1317 exchange_url, 1318 last_http_status, 1319 kyc_ok ? "KYC OK" : "KYC NEEDED", 1320 in_aml_review ? "IN AML REVIEW" : "NO AML REVIEW", 1321 NULL == jlimits ? "DEFAULT LIMITS" : "CUSTOM LIMITS"); 1322 switch (kc->lpt) 1323 { 1324 case TALER_EXCHANGE_KLPT_NONE: 1325 break; 1326 case TALER_EXCHANGE_KLPT_KYC_AUTH_TRANSFER: 1327 if (NULL != access_token) 1328 kc->return_immediately = true; 1329 break; 1330 case TALER_EXCHANGE_KLPT_INVESTIGATION_DONE: 1331 if (! in_aml_review) 1332 kc->return_immediately = true; 1333 break; 1334 case TALER_EXCHANGE_KLPT_KYC_OK: 1335 if (kyc_ok) 1336 kc->return_immediately = true; 1337 break; 1338 } 1339 ekr = GNUNET_new (struct ExchangeKycRequest); 1340 GNUNET_CONTAINER_DLL_insert (kc->exchange_pending_head, 1341 kc->exchange_pending_tail, 1342 ekr); 1343 ekr->last_http_status = last_http_status; 1344 ekr->last_ec = last_ec; 1345 if (NULL != jlimits) 1346 ekr->jlimits = json_incref ((json_t *) jlimits); 1347 ekr->h_wire = *h_wire; 1348 ekr->exchange_url = GNUNET_strdup (exchange_url); 1349 ekr->payto_uri.full_payto 1350 = GNUNET_strdup (payto_uri.full_payto); 1351 ekr->last_check = last_check; 1352 ekr->kyc_ok = kyc_ok; 1353 ekr->kc = kc; 1354 ekr->in_aml_review = in_aml_review; 1355 ekr->auth_ok = (NULL != access_token); 1356 if ( (! ekr->auth_ok) || 1357 (NULL == ekr->jlimits) ) 1358 { 1359 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 1360 "Awaiting /keys from `%s'\n", 1361 exchange_url); 1362 /* Figure out wire transfer instructions */ 1363 ekr->fo = TMH_EXCHANGES_keys4exchange ( 1364 exchange_url, 1365 false, 1366 &kyc_with_exchange, 1367 ekr); 1368 if (NULL == ekr->fo) 1369 { 1370 GNUNET_break (0); 1371 ekr_finished (ekr); 1372 return; 1373 } 1374 return; 1375 } 1376 ekr->access_token = *access_token; 1377 ekr_finished (ekr); 1378 } 1379 1380 1381 /** 1382 * Check our database for the KYC status. Determines if we then 1383 * need to wait on exchange data or have no exchange and can 1384 * immediately proceed to return 204. 1385 * 1386 * @param[in,out] kc connection we are handling 1387 */ 1388 static void 1389 phase_database_kyc_check (struct KycContext *kc) 1390 { 1391 enum GNUNET_DB_QueryStatus qs; 1392 1393 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 1394 "Checking KYC status for %s (%d/%s)\n", 1395 kc->mi->settings.id, 1396 kc->have_h_wire, 1397 kc->exchange_url); 1398 /* We may run repeatedly due to long-polling; clear data 1399 from previous runs first */ 1400 GNUNET_break (0 == 1401 json_array_clear (kc->kycs_data)); 1402 kc->in_db = true; 1403 qs = TALER_MERCHANTDB_iterate_kyc_statuses ( 1404 TMH_db, 1405 kc->mi->settings.id, 1406 kc->have_h_wire 1407 ? &kc->h_wire 1408 : NULL, 1409 kc->exchange_url, 1410 &kyc_status_cb, 1411 kc); 1412 kc->in_db = false; 1413 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 1414 "iterate_kyc_statuses returned %d records\n", 1415 (int) qs); 1416 switch (qs) 1417 { 1418 case GNUNET_DB_STATUS_HARD_ERROR: 1419 case GNUNET_DB_STATUS_SOFT_ERROR: 1420 /* Database error */ 1421 GNUNET_break (0); 1422 finish_request (kc, 1423 TALER_MHD_reply_with_ec ( 1424 kc->connection, 1425 TALER_EC_GENERIC_DB_FETCH_FAILED, 1426 "iterate_kyc_statuses")); 1427 return; 1428 case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS: 1429 kc->phase = PHASE_NO_ACCOUNTS; 1430 return; 1431 case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT: 1432 /* Handled below */ 1433 break; 1434 } 1435 if (NULL == kc->exchange_pending_head) 1436 { 1437 kc->phase = PHASE_GENERATE_RESPONSE; 1438 return; 1439 } 1440 MHD_suspend_connection (kc->connection); 1441 kc->suspended = GNUNET_YES; 1442 kc->phase = PHASE_SUSPENDED_ON_EXCHANGE; 1443 } 1444 1445 1446 /* ********************* phase_no_accounts *********** */ 1447 1448 /** 1449 * We have no accounts, return a 204 No content, 1450 * or suspend if long-polling. 1451 * 1452 * @param[in,out] kc connection we are handling 1453 */ 1454 static void 1455 phase_no_accounts (struct KycContext *kc) 1456 { 1457 /* We use an Etag of all zeros for the 204 status code */ 1458 static struct GNUNET_ShortHashCode zero_etag; 1459 struct MHD_Response *response; 1460 1461 /* no matching accounts, could not have suspended */ 1462 GNUNET_assert (GNUNET_NO == kc->suspended); 1463 if (kc->have_lp_not_etag && 1464 (0 == GNUNET_memcmp (&zero_etag, 1465 &kc->lp_not_etag)) && 1466 (! GNUNET_TIME_absolute_is_past (kc->timeout)) ) 1467 { 1468 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 1469 "No matching accounts, suspending to wait for this to change\n"); 1470 MHD_suspend_connection (kc->connection); 1471 kc->suspended = GNUNET_YES; 1472 kc->phase = PHASE_SUSPENDED_ON_ACCOUNT; 1473 return; 1474 } 1475 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 1476 "No matching accounts, returning empty response\n"); 1477 response = MHD_create_response_from_buffer_static (0, 1478 NULL); 1479 TALER_MHD_add_global_headers (response, 1480 false); 1481 { 1482 char *etag; 1483 1484 etag = GNUNET_STRINGS_data_to_string_alloc (&zero_etag, 1485 sizeof (zero_etag)); 1486 GNUNET_break (MHD_YES == 1487 MHD_add_response_header (response, 1488 MHD_HTTP_HEADER_ETAG, 1489 etag)); 1490 GNUNET_free (etag); 1491 } 1492 finish_request (kc, 1493 MHD_queue_response (kc->connection, 1494 MHD_HTTP_NO_CONTENT, 1495 response)); 1496 MHD_destroy_response (response); 1497 } 1498 1499 1500 /* ********************* phase_generate_response *********** */ 1501 1502 /** 1503 * Resume the given KYC context and send the final response. Stores the 1504 * response in the @a kc and signals MHD to resume the connection. Also 1505 * ensures MHD runs immediately. 1506 * 1507 * @param kc KYC context 1508 */ 1509 static void 1510 resume_kyc_with_response (struct KycContext *kc) 1511 { 1512 struct GNUNET_ShortHashCode sh; 1513 bool not_modified; 1514 char *can; 1515 unsigned int response_code; 1516 struct MHD_Response *response; 1517 1518 /* The database returns KYC records in a stable order, but entries that 1519 require exchange /keys data are appended when their asynchronous lookup 1520 finishes. Sort only after all lookups are done so callback timing and 1521 synthetic exchange-unreachable entries cannot affect the response or its 1522 ETag. */ 1523 TMH_kyc_data_sort (kc->kycs_data); 1524 can = TALER_JSON_canonicalize (kc->kycs_data); 1525 GNUNET_assert (GNUNET_YES == 1526 GNUNET_CRYPTO_hkdf_gnunet (&sh, 1527 sizeof (sh), 1528 "KYC-SALT", 1529 strlen ("KYC-SALT"), 1530 can, 1531 strlen (can))); 1532 not_modified = kc->have_lp_not_etag && 1533 (0 == GNUNET_memcmp (&sh, 1534 &kc->lp_not_etag)); 1535 if (not_modified && 1536 (! GNUNET_TIME_absolute_is_past (kc->timeout)) ) 1537 { 1538 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 1539 "Status unchanged, not returning response yet\n"); 1540 wait_for_account (kc); 1541 GNUNET_free (can); 1542 return; 1543 } 1544 { 1545 const char *inm; 1546 1547 inm = MHD_lookup_connection_value (kc->connection, 1548 MHD_HEADER_KIND, 1549 MHD_HTTP_HEADER_IF_NONE_MATCH); 1550 if ( (NULL == inm) || 1551 ('"' != inm[0]) || 1552 ('"' != inm[strlen (inm) - 1]) || 1553 (0 != strncmp (inm + 1, 1554 can, 1555 strlen (can))) ) 1556 not_modified = false; /* must return full response */ 1557 } 1558 GNUNET_free (can); 1559 response_code = not_modified 1560 ? MHD_HTTP_NOT_MODIFIED 1561 : MHD_HTTP_OK; 1562 switch (kc->format) 1563 { 1564 case POF_JSON: 1565 response = TALER_MHD_MAKE_JSON_PACK ( 1566 GNUNET_JSON_pack_array_incref ("kyc_data", 1567 kc->kycs_data)); 1568 break; 1569 case POF_TEXT: 1570 { 1571 enum GNUNET_GenericReturnValue ret; 1572 json_t *obj; 1573 1574 obj = GNUNET_JSON_PACK ( 1575 GNUNET_JSON_pack_array_incref ("kyc_data", 1576 kc->kycs_data)); 1577 ret = TALER_TEMPLATING_build (kc->connection, 1578 &response_code, 1579 "kyc_text", 1580 kc->mi->settings.id, 1581 NULL, 1582 obj, 1583 &response); 1584 json_decref (obj); 1585 switch (ret) 1586 { 1587 case GNUNET_SYSERR: 1588 /* failed to even produce a response */ 1589 GNUNET_break (0); 1590 kc->phase = PHASE_RETURN_NO; 1591 return; 1592 case GNUNET_NO: 1593 finish_request (kc, 1594 MHD_queue_response ( 1595 kc->connection, 1596 response_code, 1597 response)); 1598 MHD_destroy_response (response); 1599 return; 1600 case GNUNET_OK: 1601 TALER_MHD_add_global_headers (response, 1602 false); 1603 GNUNET_break (MHD_YES == 1604 MHD_add_response_header (response, 1605 MHD_HTTP_HEADER_CONTENT_TYPE, 1606 "text/plain")); 1607 break; 1608 } /* switch (ret) */ 1609 } 1610 break; 1611 case POF_PDF: 1612 // not yet implemented 1613 GNUNET_assert (0); 1614 break; 1615 } 1616 { 1617 char *etag; 1618 char *qetag; 1619 1620 etag = GNUNET_STRINGS_data_to_string_alloc (&sh, 1621 sizeof (sh)); 1622 GNUNET_asprintf (&qetag, 1623 "\"%s\"", 1624 etag); 1625 GNUNET_break (MHD_YES == 1626 MHD_add_response_header (response, 1627 MHD_HTTP_HEADER_ETAG, 1628 qetag)); 1629 GNUNET_free (qetag); 1630 GNUNET_free (etag); 1631 } 1632 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 1633 "Resuming /kyc handling as exchange interaction is done (%u)\n", 1634 MHD_HTTP_OK); 1635 finish_request (kc, 1636 MHD_queue_response ( 1637 kc->connection, 1638 response_code, 1639 response)); 1640 MHD_destroy_response (response); 1641 } 1642 1643 1644 /** 1645 * We are done with asynchronous processing, generate the 1646 * response for the @e kc. 1647 * 1648 * @param[in,out] kc KYC context to respond for 1649 */ 1650 static void 1651 phase_generate_response (struct KycContext *kc) 1652 { 1653 GNUNET_assert (NULL == kc->exchange_pending_head); 1654 GNUNET_assert (GNUNET_NO == kc->suspended); 1655 /* FIXME: mixing these two suspend conditions like this 1656 does not seem sane */ 1657 if ( (! kc->return_immediately) && 1658 (! GNUNET_TIME_absolute_is_past (kc->timeout)) ) 1659 { 1660 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 1661 "Suspending: long poll target %d not reached\n", 1662 kc->lpt); 1663 wait_for_account (kc); 1664 return; 1665 } 1666 if ( (! GNUNET_TIME_absolute_is_past (kc->timeout)) && 1667 ( (NULL != kc->lp_not_status) || 1668 (NULL != kc->lp_status) ) ) 1669 { 1670 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 1671 "Long-poll target status not reached, not returning response yet\n"); 1672 wait_for_account (kc); 1673 return; 1674 } 1675 /* All exchange requests done, create final 1676 big response from cumulated replies */ 1677 resume_kyc_with_response (kc); 1678 } 1679 1680 1681 /* ******************* main logic ***************** */ 1682 1683 /** 1684 * Check the KYC status of an instance. 1685 * 1686 * @param mi instance to check KYC status of 1687 * @param connection the MHD connection to handle 1688 * @param[in,out] hc context with further information about the request 1689 * @return MHD result code 1690 */ 1691 static enum MHD_Result 1692 get_instances_ID_kyc ( 1693 struct TMH_MerchantInstance *mi, 1694 struct MHD_Connection *connection, 1695 struct TMH_HandlerContext *hc) 1696 { 1697 struct KycContext *kc = hc->ctx; 1698 1699 if (NULL == kc) 1700 { 1701 kc = GNUNET_new (struct KycContext); 1702 kc->mi = mi; 1703 hc->ctx = kc; 1704 hc->cc = &kyc_context_cleanup; 1705 GNUNET_CONTAINER_DLL_insert (kc_head, 1706 kc_tail, 1707 kc); 1708 kc->connection = connection; 1709 kc->hc = hc; 1710 TALER_MHD_parse_request_timeout (connection, 1711 &kc->timeout); 1712 { 1713 uint64_t num = 0; 1714 int val; 1715 1716 TALER_MHD_parse_request_number (connection, 1717 "lpt", 1718 &num); 1719 val = (int) num; 1720 if ( (val < 0) || 1721 (val > TALER_EXCHANGE_KLPT_MAX) ) 1722 { 1723 /* Protocol violation, but we can be graceful and 1724 just ignore the long polling! */ 1725 GNUNET_break_op (0); 1726 val = TALER_EXCHANGE_KLPT_NONE; 1727 } 1728 kc->lpt = (enum TALER_EXCHANGE_KycLongPollTarget) val; 1729 } 1730 kc->return_immediately 1731 = (TALER_EXCHANGE_KLPT_NONE == kc->lpt); 1732 kc->lp_status = MHD_lookup_connection_value ( 1733 connection, 1734 MHD_GET_ARGUMENT_KIND, 1735 "lp_status"); 1736 kc->lp_not_status = MHD_lookup_connection_value ( 1737 connection, 1738 MHD_GET_ARGUMENT_KIND, 1739 "lp_not_status"); 1740 TALER_MHD_parse_request_arg_auto (connection, 1741 "h_wire", 1742 &kc->h_wire, 1743 kc->have_h_wire); 1744 TALER_MHD_parse_request_arg_auto (connection, 1745 "lp_not_etag", 1746 &kc->lp_not_etag, 1747 kc->have_lp_not_etag); 1748 } 1749 while (1) 1750 { 1751 switch (kc->phase) 1752 { 1753 case PHASE_INIT: 1754 phase_init (kc); 1755 break; 1756 case PHASE_DETERMINE_LONG_POLL: 1757 phase_determine_long_poll (kc); 1758 break; 1759 case PHASE_DATABASE_KYC_CHECK: 1760 phase_database_kyc_check (kc); 1761 break; 1762 case PHASE_NO_ACCOUNTS: 1763 phase_no_accounts (kc); 1764 break; 1765 case PHASE_GENERATE_RESPONSE: 1766 phase_generate_response (kc); 1767 break; 1768 case PHASE_IN_SHUTDOWN: 1769 /* during shutdown, we don't generate any more replies */ 1770 GNUNET_assert (GNUNET_SYSERR == kc->suspended); 1771 return MHD_NO; 1772 case PHASE_RETURN_YES: 1773 return MHD_YES; 1774 case PHASE_RETURN_NO: 1775 return MHD_NO; 1776 case PHASE_SUSPENDED_ON_ACCOUNT: 1777 /* suspended */ 1778 GNUNET_assert (GNUNET_YES == kc->suspended); 1779 return MHD_YES; 1780 case PHASE_SUSPENDED_ON_EXCHANGE: 1781 /* suspended */ 1782 GNUNET_assert (GNUNET_YES == kc->suspended); 1783 return MHD_YES; 1784 } 1785 } 1786 } 1787 1788 1789 enum MHD_Result 1790 TMH_private_get_instances_ID_kyc ( 1791 const struct TMH_RequestHandler *rh, 1792 struct MHD_Connection *connection, 1793 struct TMH_HandlerContext *hc) 1794 { 1795 struct TMH_MerchantInstance *mi = hc->instance; 1796 1797 (void) rh; 1798 return get_instances_ID_kyc (mi, 1799 connection, 1800 hc); 1801 } 1802 1803 1804 enum MHD_Result 1805 TMH_private_get_instances_default_ID_kyc ( 1806 const struct TMH_RequestHandler *rh, 1807 struct MHD_Connection *connection, 1808 struct TMH_HandlerContext *hc) 1809 { 1810 struct TMH_MerchantInstance *mi; 1811 1812 (void) rh; 1813 mi = TMH_lookup_instance (hc->infix); 1814 if (NULL == mi) 1815 { 1816 return TALER_MHD_reply_with_error ( 1817 connection, 1818 MHD_HTTP_NOT_FOUND, 1819 TALER_EC_MERCHANT_GENERIC_INSTANCE_UNKNOWN, 1820 hc->infix); 1821 } 1822 return get_instances_ID_kyc (mi, 1823 connection, 1824 hc); 1825 } 1826 1827 1828 /* end of taler-merchant-httpd_get-private-kyc.c */