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