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