taler-merchant-httpd_get-private-kyc.c (46009B)
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 (POF_TEXT == kc->format) 603 ? GNUNET_JSON_pack_string ("interval", 604 GNUNET_TIME_relative2s (limit->timeframe, 605 true)) 606 : GNUNET_JSON_pack_time_rel ("timeframe", 607 limit->timeframe), 608 TALER_JSON_pack_amount ("threshold", 609 &limit->threshold), 610 GNUNET_JSON_pack_bool ("soft_limit", 611 limit->soft_limit) 612 ); 613 GNUNET_assert (0 == 614 json_array_append_new (limits, 615 jl)); 616 } 617 618 619 /** 620 * Return JSON array with AccountLimit objects giving 621 * the current limits for this exchange. 622 * 623 * @param[in,out] ekr overall request context 624 */ 625 static json_t * 626 get_exchange_limits ( 627 struct ExchangeKycRequest *ekr) 628 { 629 const struct TALER_EXCHANGE_Keys *keys = ekr->keys; 630 json_t *limits; 631 632 if (NULL != ekr->jlimits) 633 { 634 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 635 "Returning custom KYC limits\n"); 636 return json_incref (ekr->jlimits); 637 } 638 if (NULL == keys) 639 { 640 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 641 "No keys, thus no default KYC limits known\n"); 642 return NULL; 643 } 644 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 645 "Returning default KYC limits (%u/%u)\n", 646 keys->hard_limits_length, 647 keys->zero_limits_length); 648 limits = json_array (); 649 GNUNET_assert (NULL != limits); 650 for (unsigned int i = 0; i<keys->hard_limits_length; i++) 651 { 652 const struct TALER_EXCHANGE_AccountLimit *limit 653 = &keys->hard_limits[i]; 654 655 pack_limit (ekr->kc, 656 limit, 657 limits); 658 } 659 for (unsigned int i = 0; i<keys->zero_limits_length; i++) 660 { 661 const struct TALER_EXCHANGE_ZeroLimitedOperation *zlimit 662 = &keys->zero_limits[i]; 663 json_t *jl; 664 struct TALER_Amount zero; 665 666 GNUNET_assert (GNUNET_OK == 667 TALER_amount_set_zero (keys->currency, 668 &zero)); 669 jl = GNUNET_JSON_PACK ( 670 TALER_JSON_pack_kycte ("operation_type", 671 zlimit->operation_type), 672 GNUNET_JSON_pack_time_rel ("timeframe", 673 GNUNET_TIME_UNIT_ZERO), 674 TALER_JSON_pack_amount ("threshold", 675 &zero), 676 GNUNET_JSON_pack_bool ("soft_limit", 677 true) 678 ); 679 GNUNET_assert (0 == 680 json_array_append_new (limits, 681 jl)); 682 } 683 return limits; 684 } 685 686 687 /** 688 * Maps @a ekr to a status code for clients to interpret the 689 * overall result. 690 * 691 * @param ekr request summary 692 * @return status of the KYC state as a string 693 */ 694 static const char * 695 map_to_status (const struct ExchangeKycRequest *ekr) 696 { 697 if (ekr->no_keys) 698 { 699 return "no-exchange-keys"; 700 } 701 if (TALER_EC_MERCHANT_PRIVATE_ACCOUNT_NOT_ELIGIBLE_FOR_EXCHANGE == 702 ekr->last_ec) 703 return "unsupported-account"; 704 if (ekr->kyc_ok) 705 { 706 if (NULL != ekr->jlimits) 707 { 708 size_t off; 709 json_t *limit; 710 json_array_foreach (ekr->jlimits, off, limit) 711 { 712 struct TALER_Amount threshold; 713 enum TALER_KYCLOGIC_KycTriggerEvent operation_type; 714 bool soft = false; 715 struct GNUNET_JSON_Specification spec[] = { 716 TALER_JSON_spec_kycte ("operation_type", 717 &operation_type), 718 TALER_JSON_spec_amount_any ("threshold", 719 &threshold), 720 GNUNET_JSON_spec_mark_optional ( 721 GNUNET_JSON_spec_bool ("soft_limit", 722 &soft), 723 NULL), 724 GNUNET_JSON_spec_end () 725 }; 726 727 if (GNUNET_OK != 728 GNUNET_JSON_parse (limit, 729 spec, 730 NULL, NULL)) 731 { 732 GNUNET_break (0); 733 return "merchant-internal-error"; 734 } 735 if (! TALER_amount_is_zero (&threshold)) 736 continue; /* only care about zero-limits */ 737 if (! soft) 738 continue; /* only care about soft limits */ 739 if ( (operation_type == TALER_KYCLOGIC_KYC_TRIGGER_DEPOSIT) || 740 (operation_type == TALER_KYCLOGIC_KYC_TRIGGER_AGGREGATE) || 741 (operation_type == TALER_KYCLOGIC_KYC_TRIGGER_TRANSACTION) ) 742 { 743 if (! ekr->auth_ok) 744 { 745 if (ekr->kyc_auth_conflict) 746 return "kyc-wire-impossible"; 747 return "kyc-wire-required"; 748 } 749 return "kyc-required"; 750 } 751 } 752 } 753 if (NULL == ekr->jlimits) 754 { 755 /* check default limits */ 756 const struct TALER_EXCHANGE_Keys *keys = ekr->keys; 757 758 for (unsigned int i = 0; i < keys->zero_limits_length; i++) 759 { 760 enum TALER_KYCLOGIC_KycTriggerEvent operation_type 761 = keys->zero_limits[i].operation_type; 762 763 if ( (operation_type == TALER_KYCLOGIC_KYC_TRIGGER_DEPOSIT) || 764 (operation_type == TALER_KYCLOGIC_KYC_TRIGGER_AGGREGATE) || 765 (operation_type == TALER_KYCLOGIC_KYC_TRIGGER_TRANSACTION) ) 766 { 767 if (! ekr->auth_ok) 768 { 769 if (ekr->kyc_auth_conflict) 770 return "kyc-wire-impossible"; 771 return "kyc-wire-required"; 772 } 773 return "kyc-required"; 774 } 775 } 776 } 777 return "ready"; 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 if (ekr->in_aml_review) 786 return "awaiting-aml-review"; 787 switch (ekr->last_http_status) 788 { 789 case 0: 790 return "exchange-unreachable"; 791 case MHD_HTTP_OK: 792 /* then we should have kyc_ok */ 793 GNUNET_break (0); 794 return NULL; 795 case MHD_HTTP_ACCEPTED: 796 /* Then KYC is really what is needed */ 797 return "kyc-required"; 798 case MHD_HTTP_NO_CONTENT: 799 /* then we should have had kyc_ok! */ 800 GNUNET_break (0); 801 return NULL; 802 case MHD_HTTP_FORBIDDEN: 803 /* then we should have had ! auth_ok */ 804 GNUNET_break (0); 805 return NULL; 806 case MHD_HTTP_NOT_FOUND: 807 /* then we should have had ! auth_ok */ 808 GNUNET_break (0); 809 return NULL; 810 case MHD_HTTP_CONFLICT: 811 /* then we should have had ! auth_ok */ 812 GNUNET_break (0); 813 return NULL; 814 case MHD_HTTP_INTERNAL_SERVER_ERROR: 815 return "exchange-internal-error"; 816 case MHD_HTTP_GATEWAY_TIMEOUT: 817 return "exchange-gateway-timeout"; 818 default: 819 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 820 "Exchange responded with unexpected HTTP status %u to /kyc-check request!\n", 821 ekr->last_http_status); 822 break; 823 } 824 return "exchange-status-invalid"; 825 } 826 827 828 /** 829 * Take data from @a ekr to expand our response. 830 * 831 * @param ekr exchange we are done inspecting 832 */ 833 static void 834 ekr_expand_response (struct ExchangeKycRequest *ekr) 835 { 836 const struct KycContext *kc = ekr->kc; 837 struct TMH_Exchange *e = TMH_EXCHANGES_lookup_exchange (ekr->exchange_url); 838 const char *status; 839 const char *q; 840 char *short_account; 841 842 GNUNET_assert (NULL != e); 843 status = map_to_status (ekr); 844 if (NULL == status) 845 { 846 GNUNET_break (0); 847 status = "logic-bug"; 848 } 849 clear_status (ekr->kc, 850 status); 851 q = strchr (ekr->payto_uri.full_payto, 852 '?'); 853 if (NULL == q) 854 short_account = GNUNET_strdup (ekr->payto_uri.full_payto); 855 else 856 short_account = GNUNET_strndup (ekr->payto_uri.full_payto, 857 q - ekr->payto_uri.full_payto); 858 GNUNET_assert ( 859 0 == 860 json_array_append_new ( 861 ekr->kc->kycs_data, 862 GNUNET_JSON_PACK ( 863 (POF_TEXT == kc->format) 864 ? GNUNET_JSON_pack_string ( 865 "short_payto_uri", 866 short_account) 867 : TALER_JSON_pack_full_payto ( 868 "payto_uri", 869 ekr->payto_uri), 870 GNUNET_JSON_pack_data_auto ( 871 "h_wire", 872 &ekr->h_wire), 873 GNUNET_JSON_pack_string ( 874 "status", 875 status), 876 GNUNET_JSON_pack_string ( 877 "exchange_url", 878 ekr->exchange_url), 879 GNUNET_JSON_pack_string ( 880 "exchange_currency", 881 TMH_EXCHANGES_get_currency (e)), 882 GNUNET_JSON_pack_bool ("no_keys", 883 ekr->no_keys), 884 GNUNET_JSON_pack_bool ("auth_conflict", 885 ekr->kyc_auth_conflict), 886 GNUNET_JSON_pack_uint64 ("exchange_http_status", 887 ekr->last_http_status), 888 (TALER_EC_NONE == ekr->last_ec) 889 ? GNUNET_JSON_pack_allow_null ( 890 GNUNET_JSON_pack_string ( 891 "dummy", 892 NULL)) 893 : GNUNET_JSON_pack_uint64 ("exchange_code", 894 ekr->last_ec), 895 ekr->auth_ok 896 ? GNUNET_JSON_pack_data_auto ( 897 "access_token", 898 &ekr->access_token) 899 : GNUNET_JSON_pack_allow_null ( 900 GNUNET_JSON_pack_string ( 901 "dummy", 902 NULL)), 903 GNUNET_JSON_pack_allow_null ( 904 GNUNET_JSON_pack_array_steal ( 905 "limits", 906 get_exchange_limits (ekr))), 907 GNUNET_JSON_pack_allow_null ( 908 GNUNET_JSON_pack_array_incref ("payto_kycauths", 909 ekr->pkaa)) 910 ))); 911 GNUNET_free (short_account); 912 } 913 914 915 /** 916 * We are done with asynchronous processing, generate the 917 * response for the @e kc. 918 * 919 * @param[in,out] kc KYC context to respond for 920 */ 921 static void 922 kc_respond (struct KycContext *kc) 923 { 924 if ( (! kc->return_immediately) && 925 (! GNUNET_TIME_absolute_is_past (kc->timeout)) ) 926 { 927 if (GNUNET_NO == kc->suspended) 928 { 929 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 930 "Suspending: long poll target %d not reached\n", 931 kc->lpt); 932 MHD_suspend_connection (kc->connection); 933 kc->suspended = GNUNET_YES; 934 } 935 else 936 { 937 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 938 "Remaining suspended: long poll target %d not reached\n", 939 kc->lpt); 940 } 941 return; 942 } 943 /* All exchange requests done, create final 944 big response from cumulated replies */ 945 resume_kyc_with_response (kc); 946 } 947 948 949 /** 950 * We are done with the KYC request @a ekr. Remove it from the work list and 951 * check if we are done overall. 952 * 953 * @param[in] ekr key request that is done (and will be freed) 954 */ 955 static void 956 ekr_finished (struct ExchangeKycRequest *ekr) 957 { 958 struct KycContext *kc = ekr->kc; 959 960 ekr_expand_response (ekr); 961 ekr_cleanup (ekr); 962 if (NULL != kc->exchange_pending_head) 963 return; /* wait for more */ 964 kc_respond (kc); 965 } 966 967 968 /** 969 * Figure out which exchange accounts from @a keys could 970 * be used for a KYC auth wire transfer from the account 971 * that @a ekr is checking. Will set the "pkaa" array 972 * in @a ekr. 973 * 974 * @param[in,out] ekr request we are processing 975 */ 976 static void 977 determine_eligible_accounts ( 978 struct ExchangeKycRequest *ekr) 979 { 980 struct KycContext *kc = ekr->kc; 981 const struct TALER_EXCHANGE_Keys *keys = ekr->keys; 982 struct TALER_Amount kyc_amount; 983 char *merchant_pub_str; 984 struct TALER_NormalizedPayto np; 985 986 ekr->pkaa = json_array (); 987 GNUNET_assert (NULL != ekr->pkaa); 988 { 989 const struct TALER_EXCHANGE_GlobalFee *gf; 990 991 gf = TALER_EXCHANGE_get_global_fee (keys, 992 GNUNET_TIME_timestamp_get ()); 993 if (NULL == gf) 994 { 995 GNUNET_assert (GNUNET_OK == 996 TALER_amount_set_zero (keys->currency, 997 &kyc_amount)); 998 } 999 else 1000 { 1001 /* FIXME-#9427: history fee should be globally renamed to KYC fee... */ 1002 kyc_amount = gf->fees.history; 1003 } 1004 } 1005 1006 merchant_pub_str 1007 = GNUNET_STRINGS_data_to_string_alloc ( 1008 &kc->mi->merchant_pub, 1009 sizeof (kc->mi->merchant_pub)); 1010 /* For all accounts of the exchange */ 1011 np = TALER_payto_normalize (ekr->payto_uri); 1012 for (unsigned int i = 0; i<keys->accounts_len; i++) 1013 { 1014 const struct TALER_EXCHANGE_WireAccount *account 1015 = &keys->accounts[i]; 1016 1017 /* KYC auth transfers are never supported with conversion */ 1018 if (NULL != account->conversion_url) 1019 continue; 1020 /* filter by source account by credit_restrictions */ 1021 if (GNUNET_YES != 1022 TALER_EXCHANGE_test_account_allowed (account, 1023 true, /* credit */ 1024 np)) 1025 continue; 1026 /* exchange account is allowed, add it */ 1027 { 1028 const char *exchange_account_payto 1029 = account->fpayto_uri.full_payto; 1030 char *payto_kycauth; 1031 1032 if (TALER_amount_is_zero (&kyc_amount)) 1033 GNUNET_asprintf (&payto_kycauth, 1034 "%s%cmessage=KYC:%s", 1035 exchange_account_payto, 1036 (NULL == strchr (exchange_account_payto, 1037 '?')) 1038 ? '?' 1039 : '&', 1040 merchant_pub_str); 1041 else 1042 GNUNET_asprintf (&payto_kycauth, 1043 "%s%camount=%s&message=KYC:%s", 1044 exchange_account_payto, 1045 (NULL == strchr (exchange_account_payto, 1046 '?')) 1047 ? '?' 1048 : '&', 1049 TALER_amount2s (&kyc_amount), 1050 merchant_pub_str); 1051 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 1052 "Found account %s where KYC auth is possible\n", 1053 payto_kycauth); 1054 GNUNET_assert (0 == 1055 json_array_append_new (ekr->pkaa, 1056 json_string (payto_kycauth))); 1057 GNUNET_free (payto_kycauth); 1058 } 1059 } 1060 GNUNET_free (np.normalized_payto); 1061 GNUNET_free (merchant_pub_str); 1062 } 1063 1064 1065 /** 1066 * Function called with the result of a #TMH_EXCHANGES_keys4exchange() 1067 * operation. Runs the KYC check against the exchange. 1068 * 1069 * @param cls closure with our `struct ExchangeKycRequest *` 1070 * @param keys keys of the exchange context 1071 * @param exchange representation of the exchange 1072 */ 1073 static void 1074 kyc_with_exchange (void *cls, 1075 struct TALER_EXCHANGE_Keys *keys, 1076 struct TMH_Exchange *exchange) 1077 { 1078 struct ExchangeKycRequest *ekr = cls; 1079 1080 (void) exchange; 1081 ekr->fo = NULL; 1082 if (NULL == keys) 1083 { 1084 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 1085 "Failed to download `%skeys`\n", 1086 ekr->exchange_url); 1087 ekr->no_keys = true; 1088 ekr_finished (ekr); 1089 return; 1090 } 1091 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 1092 "Got /keys for `%s'\n", 1093 ekr->exchange_url); 1094 ekr->keys = TALER_EXCHANGE_keys_incref (keys); 1095 if (! ekr->auth_ok) 1096 { 1097 determine_eligible_accounts (ekr); 1098 if (0 == json_array_size (ekr->pkaa)) 1099 { 1100 /* No KYC auth wire transfers are possible to this exchange from 1101 our merchant bank account, so we cannot use this account with 1102 this exchange if it has any KYC requirements! */ 1103 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 1104 "KYC auth to `%s' impossible for merchant account `%s'\n", 1105 ekr->exchange_url, 1106 ekr->payto_uri.full_payto); 1107 ekr->kyc_auth_conflict = true; 1108 } 1109 } 1110 ekr_finished (ekr); 1111 } 1112 1113 1114 /** 1115 * Closure for add_unreachable_status(). 1116 */ 1117 struct UnreachableContext 1118 { 1119 /** 1120 * Where we are building the response. 1121 */ 1122 struct KycContext *kc; 1123 1124 /** 1125 * Pointer to our account hash. 1126 */ 1127 const struct TALER_MerchantWireHashP *h_wire; 1128 1129 /** 1130 * Bank account for which we have no status from any exchange. 1131 */ 1132 struct TALER_FullPayto payto_uri; 1133 1134 }; 1135 1136 /** 1137 * Add all trusted exchanges with "unknown" status for the 1138 * bank account given in the context. 1139 * 1140 * @param cls a `struct UnreachableContext` 1141 * @param url base URL of the exchange 1142 * @param exchange internal handle for the exchange 1143 */ 1144 static void 1145 add_unreachable_status (void *cls, 1146 const char *url, 1147 const struct TMH_Exchange *exchange) 1148 { 1149 struct UnreachableContext *uc = cls; 1150 struct KycContext *kc = uc->kc; 1151 1152 clear_status (kc, 1153 "exchange-unreachable"); 1154 GNUNET_assert ( 1155 0 == 1156 json_array_append_new ( 1157 kc->kycs_data, 1158 GNUNET_JSON_PACK ( 1159 TALER_JSON_pack_full_payto ( 1160 "payto_uri", 1161 uc->payto_uri), 1162 GNUNET_JSON_pack_data_auto ( 1163 "h_wire", 1164 uc->h_wire), 1165 GNUNET_JSON_pack_string ( 1166 "exchange_currency", 1167 TMH_EXCHANGES_get_currency (exchange)), 1168 GNUNET_JSON_pack_string ( 1169 "status", 1170 "exchange-unreachable"), 1171 GNUNET_JSON_pack_string ( 1172 "exchange_url", 1173 url), 1174 GNUNET_JSON_pack_bool ("no_keys", 1175 true), 1176 GNUNET_JSON_pack_bool ("auth_conflict", 1177 false), 1178 GNUNET_JSON_pack_uint64 ("exchange_http_status", 1179 0) 1180 ))); 1181 1182 } 1183 1184 1185 /** 1186 * Function called from account_kyc_get_status() with KYC status information 1187 * for this merchant. 1188 * 1189 * @param cls our `struct KycContext *` 1190 * @param h_wire hash of the wire account 1191 * @param payto_uri payto:// URI of the merchant's bank account 1192 * @param exchange_url base URL of the exchange for which this is a status 1193 * @param last_check when did we last get an update on our KYC status from the exchange 1194 * @param kyc_ok true if we satisfied the KYC requirements 1195 * @param access_token access token for the KYC SPA, NULL if we cannot access it yet (need KYC auth wire transfer) 1196 * @param last_http_status last HTTP status from /kyc-check 1197 * @param last_ec last Taler error code from /kyc-check 1198 * @param in_aml_review true if the account is pending review 1199 * @param jlimits JSON array of applicable AccountLimits, or NULL if unknown (like defaults apply) 1200 */ 1201 static void 1202 kyc_status_cb ( 1203 void *cls, 1204 const struct TALER_MerchantWireHashP *h_wire, 1205 struct TALER_FullPayto payto_uri, 1206 const char *exchange_url, 1207 struct GNUNET_TIME_Timestamp last_check, 1208 bool kyc_ok, 1209 const struct TALER_AccountAccessTokenP *access_token, 1210 unsigned int last_http_status, 1211 enum TALER_ErrorCode last_ec, 1212 bool in_aml_review, 1213 const json_t *jlimits) 1214 { 1215 struct KycContext *kc = cls; 1216 struct ExchangeKycRequest *ekr; 1217 1218 if (NULL == exchange_url) 1219 { 1220 struct UnreachableContext uc = { 1221 .kc = kc, 1222 .h_wire = h_wire, 1223 .payto_uri = payto_uri 1224 }; 1225 1226 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 1227 "Account has unknown KYC status for all exchanges.\n"); 1228 TMH_exchange_get_trusted (&add_unreachable_status, 1229 &uc); 1230 return; 1231 } 1232 if (! TMH_EXCHANGES_check_trusted (exchange_url)) 1233 { 1234 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 1235 "Skipping exchange `%s': not trusted\n", 1236 exchange_url); 1237 return; 1238 } 1239 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 1240 "KYC status for `%s' at `%s' is %u/%s/%s/%s\n", 1241 payto_uri.full_payto, 1242 exchange_url, 1243 last_http_status, 1244 kyc_ok ? "KYC OK" : "KYC NEEDED", 1245 in_aml_review ? "IN AML REVIEW" : "NO AML REVIEW", 1246 NULL == jlimits ? "DEFAULT LIMITS" : "CUSTOM LIMITS"); 1247 switch (kc->lpt) 1248 { 1249 case TALER_EXCHANGE_KLPT_NONE: 1250 break; 1251 case TALER_EXCHANGE_KLPT_KYC_AUTH_TRANSFER: 1252 if (NULL != access_token) 1253 kc->return_immediately = true; 1254 break; 1255 case TALER_EXCHANGE_KLPT_INVESTIGATION_DONE: 1256 if (! in_aml_review) 1257 kc->return_immediately = true; 1258 break; 1259 case TALER_EXCHANGE_KLPT_KYC_OK: 1260 if (kyc_ok) 1261 kc->return_immediately = true; 1262 break; 1263 } 1264 ekr = GNUNET_new (struct ExchangeKycRequest); 1265 GNUNET_CONTAINER_DLL_insert (kc->exchange_pending_head, 1266 kc->exchange_pending_tail, 1267 ekr); 1268 ekr->last_http_status = last_http_status; 1269 ekr->last_ec = last_ec; 1270 if (NULL != jlimits) 1271 ekr->jlimits = json_incref ((json_t *) jlimits); 1272 ekr->h_wire = *h_wire; 1273 ekr->exchange_url = GNUNET_strdup (exchange_url); 1274 ekr->payto_uri.full_payto 1275 = GNUNET_strdup (payto_uri.full_payto); 1276 ekr->last_check = last_check; 1277 ekr->kyc_ok = kyc_ok; 1278 ekr->kc = kc; 1279 ekr->in_aml_review = in_aml_review; 1280 ekr->auth_ok = (NULL != access_token); 1281 if ( (! ekr->auth_ok) || 1282 (NULL == ekr->jlimits) ) 1283 { 1284 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 1285 "Awaiting /keys from `%s'\n", 1286 exchange_url); 1287 1288 /* Figure out wire transfer instructions */ 1289 if (GNUNET_NO == kc->suspended) 1290 { 1291 MHD_suspend_connection (kc->connection); 1292 kc->suspended = GNUNET_YES; 1293 } 1294 ekr->fo = TMH_EXCHANGES_keys4exchange ( 1295 exchange_url, 1296 false, 1297 &kyc_with_exchange, 1298 ekr); 1299 if (NULL == ekr->fo) 1300 { 1301 GNUNET_break (0); 1302 ekr_finished (ekr); 1303 return; 1304 } 1305 return; 1306 } 1307 ekr->access_token = *access_token; 1308 ekr_finished (ekr); 1309 } 1310 1311 1312 /** 1313 * Check the KYC status of an instance. 1314 * 1315 * @param mi instance to check KYC status of 1316 * @param connection the MHD connection to handle 1317 * @param[in,out] hc context with further information about the request 1318 * @return MHD result code 1319 */ 1320 static MHD_RESULT 1321 get_instances_ID_kyc ( 1322 struct TMH_MerchantInstance *mi, 1323 struct MHD_Connection *connection, 1324 struct TMH_HandlerContext *hc) 1325 { 1326 struct KycContext *kc = hc->ctx; 1327 1328 if (NULL == kc) 1329 { 1330 kc = GNUNET_new (struct KycContext); 1331 kc->mi = mi; 1332 hc->ctx = kc; 1333 hc->cc = &kyc_context_cleanup; 1334 GNUNET_CONTAINER_DLL_insert (kc_head, 1335 kc_tail, 1336 kc); 1337 kc->connection = connection; 1338 kc->hc = hc; 1339 kc->kycs_data = json_array (); 1340 GNUNET_assert (NULL != kc->kycs_data); 1341 TALER_MHD_parse_request_timeout (connection, 1342 &kc->timeout); 1343 { 1344 uint64_t num = 0; 1345 int val; 1346 1347 TALER_MHD_parse_request_number (connection, 1348 "lpt", 1349 &num); 1350 val = (int) num; 1351 if ( (val < 0) || 1352 (val > TALER_EXCHANGE_KLPT_MAX) ) 1353 { 1354 /* Protocol violation, but we can be graceful and 1355 just ignore the long polling! */ 1356 GNUNET_break_op (0); 1357 val = TALER_EXCHANGE_KLPT_NONE; 1358 } 1359 kc->lpt = (enum TALER_EXCHANGE_KycLongPollTarget) val; 1360 } 1361 kc->return_immediately 1362 = (TALER_EXCHANGE_KLPT_NONE == kc->lpt); 1363 /* process 'exchange_url' argument */ 1364 kc->exchange_url = MHD_lookup_connection_value ( 1365 connection, 1366 MHD_GET_ARGUMENT_KIND, 1367 "exchange_url"); 1368 if ( (NULL != kc->exchange_url) && 1369 ( (! TALER_url_valid_charset (kc->exchange_url)) || 1370 (! TALER_is_web_url (kc->exchange_url)) ) ) 1371 { 1372 GNUNET_break_op (0); 1373 return TALER_MHD_reply_with_error ( 1374 connection, 1375 MHD_HTTP_BAD_REQUEST, 1376 TALER_EC_GENERIC_PARAMETER_MALFORMED, 1377 "exchange_url must be a valid HTTP(s) URL"); 1378 } 1379 kc->lp_status = MHD_lookup_connection_value ( 1380 connection, 1381 MHD_GET_ARGUMENT_KIND, 1382 "lp_status"); 1383 kc->lp_not_status = MHD_lookup_connection_value ( 1384 connection, 1385 MHD_GET_ARGUMENT_KIND, 1386 "lp_not_status"); 1387 TALER_MHD_parse_request_arg_auto (connection, 1388 "h_wire", 1389 &kc->h_wire, 1390 kc->have_h_wire); 1391 TALER_MHD_parse_request_arg_auto (connection, 1392 "lp_not_etag", 1393 &kc->lp_not_etag, 1394 kc->have_lp_not_etag); 1395 1396 /* Determine desired output format from Accept header */ 1397 { 1398 const char *mime; 1399 1400 mime = MHD_lookup_connection_value (connection, 1401 MHD_HEADER_KIND, 1402 MHD_HTTP_HEADER_ACCEPT); 1403 if (NULL == mime) 1404 mime = "application/json"; 1405 if (0 == strcmp (mime, 1406 "*/*")) 1407 mime = "application/json"; 1408 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 1409 "KYC status requested for format %s\n", 1410 mime); 1411 if (0 == strcmp (mime, 1412 "application/json")) 1413 { 1414 kc->format = POF_JSON; 1415 } 1416 else if (0 == strcmp (mime, 1417 "text/plain")) 1418 { 1419 kc->format = POF_TEXT; 1420 } 1421 #if FUTURE 1422 else if (0 == strcmp (mime, 1423 "application/pdf")) 1424 { 1425 kc->format = POF_PDF; 1426 } 1427 #endif 1428 else 1429 { 1430 GNUNET_break_op (0); 1431 return TALER_MHD_REPLY_JSON_PACK ( 1432 connection, 1433 MHD_HTTP_NOT_ACCEPTABLE, 1434 GNUNET_JSON_pack_string ("hint", 1435 mime)); 1436 } 1437 } 1438 1439 if (! GNUNET_TIME_absolute_is_past (kc->timeout)) 1440 { 1441 if (kc->have_h_wire) 1442 { 1443 struct TALER_MERCHANTDB_MerchantKycStatusChangeEventP ev = { 1444 .header.size = htons (sizeof (ev)), 1445 .header.type = htons ( 1446 TALER_DBEVENT_MERCHANT_EXCHANGE_KYC_STATUS_CHANGED 1447 ), 1448 .h_wire = kc->h_wire 1449 }; 1450 1451 kc->eh = TMH_db->event_listen ( 1452 TMH_db->cls, 1453 &ev.header, 1454 GNUNET_TIME_absolute_get_remaining (kc->timeout), 1455 &kyc_change_cb, 1456 kc); 1457 } 1458 else 1459 { 1460 struct GNUNET_DB_EventHeaderP hdr = { 1461 .size = htons (sizeof (hdr)), 1462 .type = htons (TALER_DBEVENT_MERCHANT_KYC_STATUS_CHANGED) 1463 }; 1464 1465 kc->eh = TMH_db->event_listen ( 1466 TMH_db->cls, 1467 &hdr, 1468 GNUNET_TIME_absolute_get_remaining (kc->timeout), 1469 &kyc_change_cb, 1470 kc); 1471 } 1472 } /* end register LISTEN hooks */ 1473 } /* end 1st time initialization */ 1474 1475 if (GNUNET_SYSERR == kc->suspended) 1476 return MHD_NO; /* during shutdown, we don't generate any more replies */ 1477 GNUNET_assert (GNUNET_NO == kc->suspended); 1478 1479 if (NULL != kc->response) 1480 return MHD_queue_response (connection, 1481 kc->response_code, 1482 kc->response); 1483 1484 /* Check our database */ 1485 { 1486 enum GNUNET_DB_QueryStatus qs; 1487 1488 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 1489 "Checking KYC status for %s (%d/%s)\n", 1490 mi->settings.id, 1491 kc->have_h_wire, 1492 kc->exchange_url); 1493 /* We may run repeatedly due to long-polling; clear data 1494 from previous runs first */ 1495 GNUNET_break (0 == 1496 json_array_clear (kc->kycs_data)); 1497 qs = TMH_db->account_kyc_get_status ( 1498 TMH_db->cls, 1499 mi->settings.id, 1500 kc->have_h_wire 1501 ? &kc->h_wire 1502 : NULL, 1503 kc->exchange_url, 1504 &kyc_status_cb, 1505 kc); 1506 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 1507 "account_kyc_get_status returned %d records\n", 1508 (int) qs); 1509 switch (qs) 1510 { 1511 case GNUNET_DB_STATUS_HARD_ERROR: 1512 case GNUNET_DB_STATUS_SOFT_ERROR: 1513 /* Database error */ 1514 GNUNET_break (0); 1515 if (GNUNET_YES == kc->suspended) 1516 { 1517 /* must have suspended before DB error, resume! */ 1518 MHD_resume_connection (connection); 1519 kc->suspended = GNUNET_NO; 1520 } 1521 return TALER_MHD_reply_with_ec ( 1522 connection, 1523 TALER_EC_GENERIC_DB_FETCH_FAILED, 1524 "account_kyc_get_status"); 1525 case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS: 1526 { 1527 /* We use an Etag of all zeros for the 204 status code */ 1528 static struct GNUNET_ShortHashCode zero_etag; 1529 1530 /* no matching accounts, could not have suspended */ 1531 GNUNET_assert (GNUNET_NO == kc->suspended); 1532 if (kc->have_lp_not_etag && 1533 (0 == GNUNET_memcmp (&zero_etag, 1534 &kc->lp_not_etag)) && 1535 (! GNUNET_TIME_absolute_is_past (kc->timeout)) ) 1536 { 1537 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 1538 "No matching accounts, suspending to wait for this to change\n"); 1539 MHD_suspend_connection (kc->connection); 1540 kc->suspended = GNUNET_YES; 1541 return MHD_YES; 1542 } 1543 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 1544 "No matching accounts, returning empty response\n"); 1545 kc->response_code = MHD_HTTP_NO_CONTENT; 1546 kc->response = MHD_create_response_from_buffer_static (0, 1547 NULL); 1548 TALER_MHD_add_global_headers (kc->response, 1549 false); 1550 { 1551 char *etag; 1552 1553 etag = GNUNET_STRINGS_data_to_string_alloc (&zero_etag, 1554 sizeof (zero_etag)); 1555 GNUNET_break (MHD_YES == 1556 MHD_add_response_header (kc->response, 1557 MHD_HTTP_HEADER_ETAG, 1558 etag)); 1559 GNUNET_free (etag); 1560 } 1561 return MHD_queue_response (connection, 1562 kc->response_code, 1563 kc->response); 1564 } 1565 case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT: 1566 break; 1567 } /* end switch (qs) */ 1568 } 1569 1570 /* normal case, but maybe no async activity? In this case, 1571 respond immediately */ 1572 if (NULL == kc->exchange_pending_head) 1573 { 1574 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 1575 "No asynchronous activity, responding now\n"); 1576 kc_respond (kc); 1577 } 1578 if (GNUNET_YES == kc->suspended) 1579 { 1580 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 1581 "Request handling suspended, waiting for KYC status change\n"); 1582 return MHD_YES; 1583 } 1584 1585 /* Should have generated a response */ 1586 GNUNET_break (NULL != kc->response); 1587 return MHD_queue_response (connection, 1588 kc->response_code, 1589 kc->response); 1590 } 1591 1592 1593 MHD_RESULT 1594 TMH_private_get_instances_ID_kyc ( 1595 const struct TMH_RequestHandler *rh, 1596 struct MHD_Connection *connection, 1597 struct TMH_HandlerContext *hc) 1598 { 1599 struct TMH_MerchantInstance *mi = hc->instance; 1600 1601 (void) rh; 1602 return get_instances_ID_kyc (mi, 1603 connection, 1604 hc); 1605 } 1606 1607 1608 MHD_RESULT 1609 TMH_private_get_instances_default_ID_kyc ( 1610 const struct TMH_RequestHandler *rh, 1611 struct MHD_Connection *connection, 1612 struct TMH_HandlerContext *hc) 1613 { 1614 struct TMH_MerchantInstance *mi; 1615 1616 (void) rh; 1617 mi = TMH_lookup_instance (hc->infix); 1618 if (NULL == mi) 1619 { 1620 return TALER_MHD_reply_with_error ( 1621 connection, 1622 MHD_HTTP_NOT_FOUND, 1623 TALER_EC_MERCHANT_GENERIC_INSTANCE_UNKNOWN, 1624 hc->infix); 1625 } 1626 return get_instances_ID_kyc (mi, 1627 connection, 1628 hc); 1629 } 1630 1631 1632 /* end of taler-merchant-httpd_get-private-kyc.c */