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