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