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