taler-merchant-httpd_get-private-kyc.c (48159B)
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 { 1091 const char *exchange_account_payto 1092 = account->fpayto_uri.full_payto; 1093 char *payto_kycauth; 1094 1095 if (TALER_amount_is_zero (&kyc_amount)) 1096 GNUNET_asprintf (&payto_kycauth, 1097 "%s%cmessage=KYC:%s", 1098 exchange_account_payto, 1099 (NULL == strchr (exchange_account_payto, 1100 '?')) 1101 ? '?' 1102 : '&', 1103 merchant_pub_str); 1104 else 1105 GNUNET_asprintf (&payto_kycauth, 1106 "%s%camount=%s&message=KYC:%s", 1107 exchange_account_payto, 1108 (NULL == strchr (exchange_account_payto, 1109 '?')) 1110 ? '?' 1111 : '&', 1112 TALER_amount2s (&kyc_amount), 1113 merchant_pub_str); 1114 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 1115 "Found account %s where KYC auth is possible\n", 1116 payto_kycauth); 1117 GNUNET_assert (0 == 1118 json_array_append_new (ekr->pkaa, 1119 json_string (payto_kycauth))); 1120 GNUNET_free (payto_kycauth); 1121 } 1122 } 1123 GNUNET_free (np.normalized_payto); 1124 GNUNET_free (merchant_pub_str); 1125 } 1126 1127 1128 /** 1129 * Function called with the result of a #TMH_EXCHANGES_keys4exchange() 1130 * operation. Runs the KYC check against the exchange. 1131 * 1132 * @param cls closure with our `struct ExchangeKycRequest *` 1133 * @param keys keys of the exchange context 1134 * @param exchange representation of the exchange 1135 */ 1136 static void 1137 kyc_with_exchange (void *cls, 1138 struct TALER_EXCHANGE_Keys *keys, 1139 struct TMH_Exchange *exchange) 1140 { 1141 struct ExchangeKycRequest *ekr = cls; 1142 1143 (void) exchange; 1144 ekr->fo = NULL; 1145 if (NULL == keys) 1146 { 1147 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 1148 "Failed to download `%skeys`\n", 1149 ekr->exchange_url); 1150 ekr->no_keys = true; 1151 ekr_finished (ekr); 1152 return; 1153 } 1154 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 1155 "Got /keys for `%s'\n", 1156 ekr->exchange_url); 1157 ekr->keys = TALER_EXCHANGE_keys_incref (keys); 1158 if (! ekr->auth_ok) 1159 { 1160 determine_eligible_accounts (ekr); 1161 if (0 == json_array_size (ekr->pkaa)) 1162 { 1163 /* No KYC auth wire transfers are possible to this exchange from 1164 our merchant bank account, so we cannot use this account with 1165 this exchange if it has any KYC requirements! */ 1166 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 1167 "KYC auth to `%s' impossible for merchant account `%s'\n", 1168 ekr->exchange_url, 1169 ekr->payto_uri.full_payto); 1170 ekr->kyc_auth_conflict = true; 1171 } 1172 } 1173 ekr_finished (ekr); 1174 } 1175 1176 1177 /** 1178 * Closure for add_unreachable_status(). 1179 */ 1180 struct UnreachableContext 1181 { 1182 /** 1183 * Where we are building the response. 1184 */ 1185 struct KycContext *kc; 1186 1187 /** 1188 * Pointer to our account hash. 1189 */ 1190 const struct TALER_MerchantWireHashP *h_wire; 1191 1192 /** 1193 * Bank account for which we have no status from any exchange. 1194 */ 1195 struct TALER_FullPayto payto_uri; 1196 1197 }; 1198 1199 /** 1200 * Add all trusted exchanges with "unknown" status for the 1201 * bank account given in the context. 1202 * 1203 * @param cls a `struct UnreachableContext` 1204 * @param url base URL of the exchange 1205 * @param exchange internal handle for the exchange 1206 */ 1207 static void 1208 add_unreachable_status (void *cls, 1209 const char *url, 1210 const struct TMH_Exchange *exchange) 1211 { 1212 struct UnreachableContext *uc = cls; 1213 struct KycContext *kc = uc->kc; 1214 1215 clear_status (kc, 1216 "exchange-unreachable"); 1217 GNUNET_assert ( 1218 0 == 1219 json_array_append_new ( 1220 kc->kycs_data, 1221 GNUNET_JSON_PACK ( 1222 TALER_JSON_pack_full_payto ( 1223 "payto_uri", 1224 uc->payto_uri), 1225 GNUNET_JSON_pack_data_auto ( 1226 "h_wire", 1227 uc->h_wire), 1228 GNUNET_JSON_pack_string ( 1229 "exchange_currency", 1230 TMH_EXCHANGES_get_currency (exchange)), 1231 GNUNET_JSON_pack_string ( 1232 "status", 1233 "exchange-unreachable"), 1234 GNUNET_JSON_pack_string ( 1235 "exchange_url", 1236 url), 1237 GNUNET_JSON_pack_bool ("no_keys", 1238 true), 1239 GNUNET_JSON_pack_bool ("auth_conflict", 1240 false), 1241 GNUNET_JSON_pack_uint64 ("exchange_http_status", 1242 0) 1243 ))); 1244 1245 } 1246 1247 1248 /** 1249 * Function called from account_kyc_get_status() with KYC status information 1250 * for this merchant. 1251 * 1252 * @param cls our `struct KycContext *` 1253 * @param h_wire hash of the wire account 1254 * @param payto_uri payto:// URI of the merchant's bank account 1255 * @param exchange_url base URL of the exchange for which this is a status 1256 * @param last_check when did we last get an update on our KYC status from the exchange 1257 * @param kyc_ok true if we satisfied the KYC requirements 1258 * @param access_token access token for the KYC SPA, NULL if we cannot access it yet (need KYC auth wire transfer) 1259 * @param last_http_status last HTTP status from /kyc-check 1260 * @param last_ec last Taler error code from /kyc-check 1261 * @param in_aml_review true if the account is pending review 1262 * @param jlimits JSON array of applicable AccountLimits, or NULL if unknown (like defaults apply) 1263 */ 1264 static void 1265 kyc_status_cb ( 1266 void *cls, 1267 const struct TALER_MerchantWireHashP *h_wire, 1268 struct TALER_FullPayto payto_uri, 1269 const char *exchange_url, 1270 struct GNUNET_TIME_Timestamp last_check, 1271 bool kyc_ok, 1272 const struct TALER_AccountAccessTokenP *access_token, 1273 unsigned int last_http_status, 1274 enum TALER_ErrorCode last_ec, 1275 bool in_aml_review, 1276 const json_t *jlimits) 1277 { 1278 struct KycContext *kc = cls; 1279 struct ExchangeKycRequest *ekr; 1280 1281 if (NULL == exchange_url) 1282 { 1283 struct UnreachableContext uc = { 1284 .kc = kc, 1285 .h_wire = h_wire, 1286 .payto_uri = payto_uri 1287 }; 1288 1289 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 1290 "Account has unknown KYC status for all exchanges.\n"); 1291 TMH_exchange_get_trusted (&add_unreachable_status, 1292 &uc); 1293 return; 1294 } 1295 if (! TMH_EXCHANGES_check_trusted (exchange_url)) 1296 { 1297 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 1298 "Skipping exchange `%s': not trusted\n", 1299 exchange_url); 1300 return; 1301 } 1302 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 1303 "KYC status for `%s' at `%s' is %u/%s/%s/%s\n", 1304 payto_uri.full_payto, 1305 exchange_url, 1306 last_http_status, 1307 kyc_ok ? "KYC OK" : "KYC NEEDED", 1308 in_aml_review ? "IN AML REVIEW" : "NO AML REVIEW", 1309 NULL == jlimits ? "DEFAULT LIMITS" : "CUSTOM LIMITS"); 1310 switch (kc->lpt) 1311 { 1312 case TALER_EXCHANGE_KLPT_NONE: 1313 break; 1314 case TALER_EXCHANGE_KLPT_KYC_AUTH_TRANSFER: 1315 if (NULL != access_token) 1316 kc->return_immediately = true; 1317 break; 1318 case TALER_EXCHANGE_KLPT_INVESTIGATION_DONE: 1319 if (! in_aml_review) 1320 kc->return_immediately = true; 1321 break; 1322 case TALER_EXCHANGE_KLPT_KYC_OK: 1323 if (kyc_ok) 1324 kc->return_immediately = true; 1325 break; 1326 } 1327 ekr = GNUNET_new (struct ExchangeKycRequest); 1328 GNUNET_CONTAINER_DLL_insert (kc->exchange_pending_head, 1329 kc->exchange_pending_tail, 1330 ekr); 1331 ekr->last_http_status = last_http_status; 1332 ekr->last_ec = last_ec; 1333 if (NULL != jlimits) 1334 ekr->jlimits = json_incref ((json_t *) jlimits); 1335 ekr->h_wire = *h_wire; 1336 ekr->exchange_url = GNUNET_strdup (exchange_url); 1337 ekr->payto_uri.full_payto 1338 = GNUNET_strdup (payto_uri.full_payto); 1339 ekr->last_check = last_check; 1340 ekr->kyc_ok = kyc_ok; 1341 ekr->kc = kc; 1342 ekr->in_aml_review = in_aml_review; 1343 ekr->auth_ok = (NULL != access_token); 1344 if ( (! ekr->auth_ok) || 1345 (NULL == ekr->jlimits) ) 1346 { 1347 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 1348 "Awaiting /keys from `%s'\n", 1349 exchange_url); 1350 1351 /* Figure out wire transfer instructions */ 1352 if (GNUNET_NO == kc->suspended) 1353 { 1354 MHD_suspend_connection (kc->connection); 1355 kc->suspended = GNUNET_YES; 1356 } 1357 ekr->fo = TMH_EXCHANGES_keys4exchange ( 1358 exchange_url, 1359 false, 1360 &kyc_with_exchange, 1361 ekr); 1362 if (NULL == ekr->fo) 1363 { 1364 GNUNET_break (0); 1365 ekr_finished (ekr); 1366 return; 1367 } 1368 return; 1369 } 1370 ekr->access_token = *access_token; 1371 ekr_finished (ekr); 1372 } 1373 1374 1375 /** 1376 * Check the KYC status of an instance. 1377 * 1378 * @param mi instance to check KYC status of 1379 * @param connection the MHD connection to handle 1380 * @param[in,out] hc context with further information about the request 1381 * @return MHD result code 1382 */ 1383 static enum MHD_Result 1384 get_instances_ID_kyc ( 1385 struct TMH_MerchantInstance *mi, 1386 struct MHD_Connection *connection, 1387 struct TMH_HandlerContext *hc) 1388 { 1389 struct KycContext *kc = hc->ctx; 1390 1391 if (NULL == kc) 1392 { 1393 kc = GNUNET_new (struct KycContext); 1394 kc->mi = mi; 1395 hc->ctx = kc; 1396 hc->cc = &kyc_context_cleanup; 1397 GNUNET_CONTAINER_DLL_insert (kc_head, 1398 kc_tail, 1399 kc); 1400 kc->connection = connection; 1401 kc->hc = hc; 1402 kc->kycs_data = json_array (); 1403 GNUNET_assert (NULL != kc->kycs_data); 1404 TALER_MHD_parse_request_timeout (connection, 1405 &kc->timeout); 1406 { 1407 uint64_t num = 0; 1408 int val; 1409 1410 TALER_MHD_parse_request_number (connection, 1411 "lpt", 1412 &num); 1413 val = (int) num; 1414 if ( (val < 0) || 1415 (val > TALER_EXCHANGE_KLPT_MAX) ) 1416 { 1417 /* Protocol violation, but we can be graceful and 1418 just ignore the long polling! */ 1419 GNUNET_break_op (0); 1420 val = TALER_EXCHANGE_KLPT_NONE; 1421 } 1422 kc->lpt = (enum TALER_EXCHANGE_KycLongPollTarget) val; 1423 } 1424 kc->return_immediately 1425 = (TALER_EXCHANGE_KLPT_NONE == kc->lpt); 1426 /* process 'exchange_url' argument */ 1427 kc->exchange_url = MHD_lookup_connection_value ( 1428 connection, 1429 MHD_GET_ARGUMENT_KIND, 1430 "exchange_url"); 1431 if ( (NULL != kc->exchange_url) && 1432 ( (! TALER_url_valid_charset (kc->exchange_url)) || 1433 (! TALER_is_web_url (kc->exchange_url)) ) ) 1434 { 1435 GNUNET_break_op (0); 1436 return TALER_MHD_reply_with_error ( 1437 connection, 1438 MHD_HTTP_BAD_REQUEST, 1439 TALER_EC_GENERIC_PARAMETER_MALFORMED, 1440 "exchange_url must be a valid HTTP(s) URL"); 1441 } 1442 kc->lp_status = MHD_lookup_connection_value ( 1443 connection, 1444 MHD_GET_ARGUMENT_KIND, 1445 "lp_status"); 1446 kc->lp_not_status = MHD_lookup_connection_value ( 1447 connection, 1448 MHD_GET_ARGUMENT_KIND, 1449 "lp_not_status"); 1450 TALER_MHD_parse_request_arg_auto (connection, 1451 "h_wire", 1452 &kc->h_wire, 1453 kc->have_h_wire); 1454 TALER_MHD_parse_request_arg_auto (connection, 1455 "lp_not_etag", 1456 &kc->lp_not_etag, 1457 kc->have_lp_not_etag); 1458 1459 /* Determine desired output format from Accept header */ 1460 { 1461 const char *mime; 1462 1463 mime = MHD_lookup_connection_value (connection, 1464 MHD_HEADER_KIND, 1465 MHD_HTTP_HEADER_ACCEPT); 1466 if (NULL == mime) 1467 mime = "application/json"; 1468 if (0 == strcmp (mime, 1469 "*/*")) 1470 mime = "application/json"; 1471 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 1472 "KYC status requested for format %s\n", 1473 mime); 1474 if (0 == strcmp (mime, 1475 "application/json")) 1476 { 1477 kc->format = POF_JSON; 1478 } 1479 else if (0 == strcmp (mime, 1480 "text/plain")) 1481 { 1482 kc->format = POF_TEXT; 1483 } 1484 #if FUTURE 1485 else if (0 == strcmp (mime, 1486 "application/pdf")) 1487 { 1488 kc->format = POF_PDF; 1489 } 1490 #endif 1491 else 1492 { 1493 GNUNET_break_op (0); 1494 return TALER_MHD_REPLY_JSON_PACK ( 1495 connection, 1496 MHD_HTTP_NOT_ACCEPTABLE, 1497 GNUNET_JSON_pack_string ("hint", 1498 mime)); 1499 } 1500 } 1501 1502 if (! GNUNET_TIME_absolute_is_past (kc->timeout)) 1503 { 1504 if (kc->have_h_wire) 1505 { 1506 struct TALER_MERCHANTDB_MerchantKycStatusChangeEventP ev = { 1507 .header.size = htons (sizeof (ev)), 1508 .header.type = htons ( 1509 TALER_DBEVENT_MERCHANT_EXCHANGE_KYC_STATUS_CHANGED 1510 ), 1511 .h_wire = kc->h_wire 1512 }; 1513 1514 kc->eh = TALER_MERCHANTDB_event_listen ( 1515 TMH_db, 1516 &ev.header, 1517 GNUNET_TIME_absolute_get_remaining (kc->timeout), 1518 &kyc_change_cb, 1519 kc); 1520 } 1521 else 1522 { 1523 struct GNUNET_DB_EventHeaderP hdr = { 1524 .size = htons (sizeof (hdr)), 1525 .type = htons (TALER_DBEVENT_MERCHANT_KYC_STATUS_CHANGED) 1526 }; 1527 1528 kc->eh = TALER_MERCHANTDB_event_listen ( 1529 TMH_db, 1530 &hdr, 1531 GNUNET_TIME_absolute_get_remaining (kc->timeout), 1532 &kyc_change_cb, 1533 kc); 1534 } 1535 } /* end register LISTEN hooks */ 1536 } /* end 1st time initialization */ 1537 1538 if (GNUNET_SYSERR == kc->suspended) 1539 return MHD_NO; /* during shutdown, we don't generate any more replies */ 1540 GNUNET_assert (GNUNET_NO == kc->suspended); 1541 1542 if (NULL != kc->response) 1543 return MHD_queue_response (connection, 1544 kc->response_code, 1545 kc->response); 1546 1547 /* Check our database */ 1548 { 1549 enum GNUNET_DB_QueryStatus qs; 1550 1551 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 1552 "Checking KYC status for %s (%d/%s)\n", 1553 mi->settings.id, 1554 kc->have_h_wire, 1555 kc->exchange_url); 1556 /* We may run repeatedly due to long-polling; clear data 1557 from previous runs first */ 1558 GNUNET_break (0 == 1559 json_array_clear (kc->kycs_data)); 1560 kc->in_db = true; 1561 qs = TALER_MERCHANTDB_account_kyc_get_status ( 1562 TMH_db, 1563 mi->settings.id, 1564 kc->have_h_wire 1565 ? &kc->h_wire 1566 : NULL, 1567 kc->exchange_url, 1568 &kyc_status_cb, 1569 kc); 1570 kc->in_db = false; 1571 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 1572 "account_kyc_get_status returned %d records\n", 1573 (int) qs); 1574 switch (qs) 1575 { 1576 case GNUNET_DB_STATUS_HARD_ERROR: 1577 case GNUNET_DB_STATUS_SOFT_ERROR: 1578 /* Database error */ 1579 GNUNET_break (0); 1580 if (GNUNET_YES == kc->suspended) 1581 { 1582 /* must have suspended before DB error, resume! */ 1583 MHD_resume_connection (connection); 1584 kc->suspended = GNUNET_NO; 1585 } 1586 return TALER_MHD_reply_with_ec ( 1587 connection, 1588 TALER_EC_GENERIC_DB_FETCH_FAILED, 1589 "account_kyc_get_status"); 1590 case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS: 1591 { 1592 /* We use an Etag of all zeros for the 204 status code */ 1593 static struct GNUNET_ShortHashCode zero_etag; 1594 1595 /* no matching accounts, could not have suspended */ 1596 GNUNET_assert (GNUNET_NO == kc->suspended); 1597 if (kc->have_lp_not_etag && 1598 (0 == GNUNET_memcmp (&zero_etag, 1599 &kc->lp_not_etag)) && 1600 (! GNUNET_TIME_absolute_is_past (kc->timeout)) ) 1601 { 1602 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 1603 "No matching accounts, suspending to wait for this to change\n"); 1604 MHD_suspend_connection (kc->connection); 1605 kc->suspended = GNUNET_YES; 1606 return MHD_YES; 1607 } 1608 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 1609 "No matching accounts, returning empty response\n"); 1610 kc->response_code = MHD_HTTP_NO_CONTENT; 1611 kc->response = MHD_create_response_from_buffer_static (0, 1612 NULL); 1613 TALER_MHD_add_global_headers (kc->response, 1614 false); 1615 { 1616 char *etag; 1617 1618 etag = GNUNET_STRINGS_data_to_string_alloc (&zero_etag, 1619 sizeof (zero_etag)); 1620 GNUNET_break (MHD_YES == 1621 MHD_add_response_header (kc->response, 1622 MHD_HTTP_HEADER_ETAG, 1623 etag)); 1624 GNUNET_free (etag); 1625 } 1626 return MHD_queue_response (connection, 1627 kc->response_code, 1628 kc->response); 1629 } 1630 case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT: 1631 break; 1632 } /* end switch (qs) */ 1633 } 1634 1635 /* normal case, but maybe no async activity? In this case, 1636 respond immediately */ 1637 if (NULL == kc->exchange_pending_head) 1638 { 1639 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 1640 "No asynchronous activity, responding now\n"); 1641 kc_respond (kc); 1642 } 1643 if (GNUNET_YES == kc->suspended) 1644 { 1645 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 1646 "Request handling suspended, waiting for KYC status change\n"); 1647 return MHD_YES; 1648 } 1649 1650 /* Should have generated a response */ 1651 GNUNET_break (NULL != kc->response); 1652 return MHD_queue_response (connection, 1653 kc->response_code, 1654 kc->response); 1655 } 1656 1657 1658 enum MHD_Result 1659 TMH_private_get_instances_ID_kyc ( 1660 const struct TMH_RequestHandler *rh, 1661 struct MHD_Connection *connection, 1662 struct TMH_HandlerContext *hc) 1663 { 1664 struct TMH_MerchantInstance *mi = hc->instance; 1665 1666 (void) rh; 1667 return get_instances_ID_kyc (mi, 1668 connection, 1669 hc); 1670 } 1671 1672 1673 enum MHD_Result 1674 TMH_private_get_instances_default_ID_kyc ( 1675 const struct TMH_RequestHandler *rh, 1676 struct MHD_Connection *connection, 1677 struct TMH_HandlerContext *hc) 1678 { 1679 struct TMH_MerchantInstance *mi; 1680 1681 (void) rh; 1682 mi = TMH_lookup_instance (hc->infix); 1683 if (NULL == mi) 1684 { 1685 return TALER_MHD_reply_with_error ( 1686 connection, 1687 MHD_HTTP_NOT_FOUND, 1688 TALER_EC_MERCHANT_GENERIC_INSTANCE_UNKNOWN, 1689 hc->infix); 1690 } 1691 return get_instances_ID_kyc (mi, 1692 connection, 1693 hc); 1694 } 1695 1696 1697 /* end of taler-merchant-httpd_get-private-kyc.c */