taler-merchant-httpd_get-private-kyc.c (50799B)
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 } 459 460 /* Determine desired output format from Accept header */ 461 { 462 const char *mime; 463 464 mime = MHD_lookup_connection_value (kc->connection, 465 MHD_HEADER_KIND, 466 MHD_HTTP_HEADER_ACCEPT); 467 if (NULL == mime) 468 mime = "application/json"; 469 if (0 == strcmp (mime, 470 "*/*")) 471 mime = "application/json"; 472 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 473 "KYC status requested for format %s\n", 474 mime); 475 if (0 == strcmp (mime, 476 "application/json")) 477 { 478 kc->format = POF_JSON; 479 } 480 else if (0 == strcmp (mime, 481 "text/plain")) 482 { 483 kc->format = POF_TEXT; 484 } 485 #if FUTURE 486 else if (0 == strcmp (mime, 487 "application/pdf")) 488 { 489 kc->format = POF_PDF; 490 } 491 #endif 492 else 493 { 494 GNUNET_break_op (0); 495 finish_request (kc, 496 TALER_MHD_REPLY_JSON_PACK ( 497 kc->connection, 498 MHD_HTTP_NOT_ACCEPTABLE, 499 GNUNET_JSON_pack_string ("hint", 500 mime))); 501 return; 502 } 503 } 504 kc->phase++; 505 } 506 507 508 /* ******************* phase_determine_long_poll ***************** */ 509 510 511 /** 512 * Handle a DB event about an update relevant 513 * for the processing of the kyc request. 514 * 515 * @param cls our `struct KycContext` 516 * @param extra additional event data provided 517 * @param extra_size number of bytes in @a extra 518 */ 519 static void 520 kyc_change_cb (void *cls, 521 const void *extra, 522 size_t extra_size) 523 { 524 struct KycContext *kc = cls; 525 526 if ( (GNUNET_YES == kc->suspended) && 527 (PHASE_SUSPENDED_ON_ACCOUNT == kc->phase) ) 528 { 529 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 530 "Resuming KYC with gateway timeout\n"); 531 kc->suspended = GNUNET_NO; 532 kc->phase = PHASE_DATABASE_KYC_CHECK; 533 MHD_resume_connection (kc->connection); 534 TALER_MHD_daemon_trigger (); /* we resumed, kick MHD */ 535 } 536 else 537 { 538 /* remember for later */ 539 kc->account_signal = true; 540 } 541 } 542 543 544 /** 545 * Suspend @a kc until we have a change in the account status. 546 * 547 * @param[in,out] kc request to suspend 548 */ 549 static void 550 wait_for_account (struct KycContext *kc) 551 { 552 GNUNET_assert (GNUNET_NO == kc->suspended); 553 if (kc->account_signal) 554 { 555 /* we got a NOTIFY earlier, handle it immediately */ 556 kc->account_signal = false; 557 kc->phase = PHASE_DATABASE_KYC_CHECK; 558 return; 559 } 560 /* Wait on account notification */ 561 MHD_suspend_connection (kc->connection); 562 kc->suspended = GNUNET_YES; 563 kc->phase = PHASE_SUSPENDED_ON_ACCOUNT; 564 } 565 566 567 /** 568 * Setup long-polling for the connection, if applicable. 569 * 570 * @param[in,out] kc connection we are handling 571 */ 572 static void 573 phase_determine_long_poll (struct KycContext *kc) 574 { 575 if (GNUNET_TIME_absolute_is_past (kc->timeout)) 576 { 577 kc->phase++; 578 return; 579 } 580 if (kc->have_h_wire) 581 { 582 struct TALER_MERCHANTDB_MerchantKycStatusChangeEventP ev = { 583 .header.size = htons (sizeof (ev)), 584 .header.type = htons ( 585 TALER_DBEVENT_MERCHANT_EXCHANGE_KYC_STATUS_CHANGED 586 ), 587 .h_wire = kc->h_wire 588 }; 589 590 kc->eh = TALER_MERCHANTDB_event_listen ( 591 TMH_db, 592 &ev.header, 593 GNUNET_TIME_absolute_get_remaining (kc->timeout), 594 &kyc_change_cb, 595 kc); 596 } 597 else 598 { 599 struct GNUNET_DB_EventHeaderP hdr = { 600 .size = htons (sizeof (hdr)), 601 .type = htons (TALER_DBEVENT_MERCHANT_KYC_STATUS_CHANGED) 602 }; 603 604 kc->eh = TALER_MERCHANTDB_event_listen ( 605 TMH_db, 606 &hdr, 607 GNUNET_TIME_absolute_get_remaining (kc->timeout), 608 &kyc_change_cb, 609 kc); 610 } 611 kc->phase++; 612 } 613 614 615 /* ***************** phase_database_kyc_check ************** */ 616 617 618 /** 619 * Maps @a ekr to a status code for clients to interpret the 620 * overall result. 621 * 622 * @param ekr request summary 623 * @return status of the KYC state as a string 624 */ 625 static const char * 626 map_to_status (const struct ExchangeKycRequest *ekr) 627 { 628 if (ekr->no_keys) 629 { 630 return "no-exchange-keys"; 631 } 632 if (TALER_EC_MERCHANT_PRIVATE_ACCOUNT_NOT_ELIGIBLE_FOR_EXCHANGE == 633 ekr->last_ec) 634 return "unsupported-account"; 635 if (ekr->kyc_ok) 636 { 637 if (NULL != ekr->jlimits) 638 { 639 size_t off; 640 json_t *limit; 641 json_array_foreach (ekr->jlimits, off, limit) 642 { 643 struct TALER_Amount threshold; 644 enum TALER_KYCLOGIC_KycTriggerEvent operation_type; 645 bool soft = false; 646 struct GNUNET_JSON_Specification spec[] = { 647 TALER_JSON_spec_kycte ("operation_type", 648 &operation_type), 649 TALER_JSON_spec_amount_any ("threshold", 650 &threshold), 651 GNUNET_JSON_spec_mark_optional ( 652 GNUNET_JSON_spec_bool ("soft_limit", 653 &soft), 654 NULL), 655 GNUNET_JSON_spec_end () 656 }; 657 658 if (GNUNET_OK != 659 GNUNET_JSON_parse (limit, 660 spec, 661 NULL, NULL)) 662 { 663 GNUNET_break (0); 664 return "merchant-internal-error"; 665 } 666 if (! TALER_amount_is_zero (&threshold)) 667 continue; /* only care about zero-limits */ 668 if (! soft) 669 continue; /* only care about soft limits */ 670 if ( (operation_type == TALER_KYCLOGIC_KYC_TRIGGER_DEPOSIT) || 671 (operation_type == TALER_KYCLOGIC_KYC_TRIGGER_AGGREGATE) || 672 (operation_type == TALER_KYCLOGIC_KYC_TRIGGER_TRANSACTION) ) 673 { 674 if (! ekr->auth_ok) 675 { 676 if (ekr->kyc_auth_conflict) 677 return "kyc-wire-impossible"; 678 return "kyc-wire-required"; 679 } 680 return "kyc-required"; 681 } 682 } 683 } 684 if (NULL == ekr->jlimits) 685 { 686 /* check default limits */ 687 const struct TALER_EXCHANGE_Keys *keys = ekr->keys; 688 689 for (unsigned int i = 0; i < keys->zero_limits_length; i++) 690 { 691 enum TALER_KYCLOGIC_KycTriggerEvent operation_type 692 = keys->zero_limits[i].operation_type; 693 694 if ( (operation_type == TALER_KYCLOGIC_KYC_TRIGGER_DEPOSIT) || 695 (operation_type == TALER_KYCLOGIC_KYC_TRIGGER_AGGREGATE) || 696 (operation_type == TALER_KYCLOGIC_KYC_TRIGGER_TRANSACTION) ) 697 { 698 if (! ekr->auth_ok) 699 { 700 if (ekr->kyc_auth_conflict) 701 return "kyc-wire-impossible"; 702 return "kyc-wire-required"; 703 } 704 return "kyc-required"; 705 } 706 } 707 } 708 return "ready"; 709 } 710 if (! ekr->auth_ok) 711 { 712 if (ekr->kyc_auth_conflict) 713 return "kyc-wire-impossible"; 714 return "kyc-wire-required"; 715 } 716 if (ekr->in_aml_review) 717 return "awaiting-aml-review"; 718 switch (ekr->last_http_status) 719 { 720 case 0: 721 return "exchange-unreachable"; 722 case MHD_HTTP_OK: 723 /* then we should have kyc_ok */ 724 GNUNET_break (0); 725 return NULL; 726 case MHD_HTTP_ACCEPTED: 727 /* Then KYC is really what is needed */ 728 return "kyc-required"; 729 case MHD_HTTP_NO_CONTENT: 730 /* then we should have had kyc_ok! */ 731 GNUNET_break (0); 732 return NULL; 733 case MHD_HTTP_FORBIDDEN: 734 /* then we should have had ! auth_ok */ 735 GNUNET_break (0); 736 return NULL; 737 case MHD_HTTP_NOT_FOUND: 738 /* then we should have had ! auth_ok */ 739 GNUNET_break (0); 740 return NULL; 741 case MHD_HTTP_CONFLICT: 742 /* then we should have had ! auth_ok */ 743 GNUNET_break (0); 744 return NULL; 745 case MHD_HTTP_INTERNAL_SERVER_ERROR: 746 return "exchange-internal-error"; 747 case MHD_HTTP_GATEWAY_TIMEOUT: 748 return "exchange-gateway-timeout"; 749 default: 750 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 751 "Exchange responded with unexpected HTTP status %u to /kyc-check request!\n", 752 ekr->last_http_status); 753 break; 754 } 755 return "exchange-status-invalid"; 756 } 757 758 759 /** 760 * We have found an exchange in status @a status. Clear any 761 * long-pollers that wait for us having (or not having) this 762 * status. 763 * 764 * @param[in,out] kc context 765 * @param status the status we encountered 766 */ 767 static void 768 clear_status (struct KycContext *kc, 769 const char *status) 770 { 771 if ( (NULL != kc->lp_status) && 772 (0 == strcmp (kc->lp_status, 773 status)) ) 774 kc->lp_status = NULL; /* satisfied! */ 775 if ( (NULL != kc->lp_not_status) && 776 (0 != strcmp (kc->lp_not_status, 777 status) ) ) 778 kc->lp_not_status = NULL; /* satisfied! */ 779 } 780 781 782 /** 783 * Pack the given @a limit into the JSON @a limits array. 784 * 785 * @param kc overall request context 786 * @param limit account limit to pack 787 * @param[in,out] limits JSON array to extend 788 */ 789 static void 790 pack_limit (const struct KycContext *kc, 791 const struct TALER_EXCHANGE_AccountLimit *limit, 792 json_t *limits) 793 { 794 json_t *jl; 795 796 jl = GNUNET_JSON_PACK ( 797 TALER_JSON_pack_kycte ("operation_type", 798 limit->operation_type), 799 GNUNET_JSON_pack_bool ( 800 "disallowed", 801 GNUNET_TIME_relative_is_zero (limit->timeframe) || 802 TALER_amount_is_zero (&limit->threshold)), 803 (POF_TEXT == kc->format) 804 ? GNUNET_JSON_pack_string ("interval", 805 GNUNET_TIME_relative2s (limit->timeframe, 806 true)) 807 : GNUNET_JSON_pack_time_rel ("timeframe", 808 limit->timeframe), 809 TALER_JSON_pack_amount ("threshold", 810 &limit->threshold), 811 GNUNET_JSON_pack_bool ("soft_limit", 812 limit->soft_limit) 813 ); 814 GNUNET_assert (0 == 815 json_array_append_new (limits, 816 jl)); 817 } 818 819 820 /** 821 * Return JSON array with AccountLimit objects giving 822 * the current limits for this exchange. 823 * 824 * @param[in,out] ekr overall request context 825 */ 826 static json_t * 827 get_exchange_limits ( 828 struct ExchangeKycRequest *ekr) 829 { 830 const struct TALER_EXCHANGE_Keys *keys = ekr->keys; 831 json_t *limits; 832 833 if (NULL != ekr->jlimits) 834 { 835 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 836 "Returning custom KYC limits\n"); 837 return json_incref (ekr->jlimits); 838 } 839 if (NULL == keys) 840 { 841 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 842 "No keys, thus no default KYC limits known\n"); 843 return NULL; 844 } 845 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 846 "Returning default KYC limits (%u/%u)\n", 847 keys->hard_limits_length, 848 keys->zero_limits_length); 849 limits = json_array (); 850 GNUNET_assert (NULL != limits); 851 for (unsigned int i = 0; i<keys->hard_limits_length; i++) 852 { 853 const struct TALER_EXCHANGE_AccountLimit *limit 854 = &keys->hard_limits[i]; 855 856 pack_limit (ekr->kc, 857 limit, 858 limits); 859 } 860 for (unsigned int i = 0; i<keys->zero_limits_length; i++) 861 { 862 const struct TALER_EXCHANGE_ZeroLimitedOperation *zlimit 863 = &keys->zero_limits[i]; 864 json_t *jl; 865 struct TALER_Amount zero; 866 867 GNUNET_assert (GNUNET_OK == 868 TALER_amount_set_zero (keys->currency, 869 &zero)); 870 jl = GNUNET_JSON_PACK ( 871 TALER_JSON_pack_kycte ("operation_type", 872 zlimit->operation_type), 873 GNUNET_JSON_pack_bool ( 874 "disallowed", 875 true), 876 (POF_TEXT == ekr->kc->format) 877 ? GNUNET_JSON_pack_string ( 878 "interval", 879 GNUNET_TIME_relative2s (GNUNET_TIME_UNIT_ZERO, 880 true)) 881 : GNUNET_JSON_pack_time_rel ("timeframe", 882 GNUNET_TIME_UNIT_ZERO), 883 TALER_JSON_pack_amount ("threshold", 884 &zero), 885 GNUNET_JSON_pack_bool ("soft_limit", 886 true) 887 ); 888 GNUNET_assert (0 == 889 json_array_append_new (limits, 890 jl)); 891 } 892 return limits; 893 } 894 895 896 /** 897 * Take data from @a ekr to expand our response. 898 * 899 * @param ekr exchange we are done inspecting 900 */ 901 static void 902 ekr_expand_response (struct ExchangeKycRequest *ekr) 903 { 904 const struct KycContext *kc = ekr->kc; 905 struct TMH_Exchange *e = TMH_EXCHANGES_lookup_exchange (ekr->exchange_url); 906 const char *status; 907 const char *q; 908 char *short_account; 909 bool kyc_swap_tos_acceptance = false; 910 char *tos_accepted_early = NULL; 911 912 GNUNET_assert (NULL != e); 913 status = map_to_status (ekr); 914 if (NULL == status) 915 { 916 GNUNET_break (0); 917 status = "logic-bug"; 918 } 919 clear_status (ekr->kc, 920 status); 921 q = strchr (ekr->payto_uri.full_payto, 922 '?'); 923 if (NULL == q) 924 short_account = GNUNET_strdup (ekr->payto_uri.full_payto); 925 else 926 short_account = GNUNET_strndup (ekr->payto_uri.full_payto, 927 q - ekr->payto_uri.full_payto); 928 if (NULL != ekr->keys) 929 kyc_swap_tos_acceptance = ekr->keys->kyc_swap_tos_acceptance; 930 { 931 enum GNUNET_DB_QueryStatus qs; 932 933 qs = TALER_MERCHANTDB_set_instance ( 934 TMH_db, 935 kc->mi->settings.id); 936 if (0 >= qs) 937 { 938 GNUNET_break (0); 939 tos_accepted_early = NULL; 940 } 941 else 942 { 943 qs = TALER_MERCHANTDB_lookup_tos_accepted_early (TMH_db, 944 kc->mi->settings.id, 945 ekr->exchange_url, 946 &tos_accepted_early); 947 GNUNET_break (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT == 948 TALER_MERCHANTDB_set_instance ( 949 TMH_db, 950 NULL)); 951 if (qs < 0) 952 { 953 GNUNET_break (0); 954 /* fall through with tos_accepted_early == NULL */ 955 tos_accepted_early = NULL; 956 } 957 } 958 } 959 GNUNET_assert ( 960 0 == 961 json_array_append_new ( 962 ekr->kc->kycs_data, 963 GNUNET_JSON_PACK ( 964 (POF_TEXT == kc->format) 965 ? GNUNET_JSON_pack_string ( 966 "short_payto_uri", 967 short_account) 968 : TALER_JSON_pack_full_payto ( 969 "payto_uri", 970 ekr->payto_uri), 971 GNUNET_JSON_pack_data_auto ( 972 "h_wire", 973 &ekr->h_wire), 974 GNUNET_JSON_pack_string ( 975 "status", 976 status), 977 GNUNET_JSON_pack_string ( 978 "exchange_url", 979 ekr->exchange_url), 980 GNUNET_JSON_pack_string ( 981 "exchange_currency", 982 TMH_EXCHANGES_get_currency (e)), 983 GNUNET_JSON_pack_bool ("no_keys", 984 ekr->no_keys), 985 GNUNET_JSON_pack_bool ("auth_conflict", 986 ekr->kyc_auth_conflict), 987 GNUNET_JSON_pack_bool ("kyc_swap_tos_acceptance", 988 kyc_swap_tos_acceptance), 989 GNUNET_JSON_pack_allow_null ( 990 GNUNET_JSON_pack_string ( 991 "tos_accepted_early", 992 tos_accepted_early)), 993 GNUNET_JSON_pack_uint64 ("exchange_http_status", 994 ekr->last_http_status), 995 (TALER_EC_NONE == ekr->last_ec) 996 ? GNUNET_JSON_pack_allow_null ( 997 GNUNET_JSON_pack_string ( 998 "dummy", 999 NULL)) 1000 : GNUNET_JSON_pack_uint64 ("exchange_code", 1001 ekr->last_ec), 1002 ekr->auth_ok 1003 ? GNUNET_JSON_pack_data_auto ( 1004 "access_token", 1005 &ekr->access_token) 1006 : GNUNET_JSON_pack_allow_null ( 1007 GNUNET_JSON_pack_string ( 1008 "dummy", 1009 NULL)), 1010 GNUNET_JSON_pack_allow_null ( 1011 GNUNET_JSON_pack_array_steal ( 1012 "limits", 1013 get_exchange_limits (ekr))), 1014 GNUNET_JSON_pack_allow_null ( 1015 GNUNET_JSON_pack_array_incref ("payto_kycauths", 1016 ekr->pkaa)) 1017 ))); 1018 GNUNET_free (tos_accepted_early); 1019 GNUNET_free (short_account); 1020 } 1021 1022 1023 /** 1024 * We are done with the KYC request @a ekr. Remove it from the work list and 1025 * check if we are done overall. 1026 * 1027 * @param[in] ekr key request that is done (and will be freed) 1028 */ 1029 static void 1030 ekr_finished (struct ExchangeKycRequest *ekr) 1031 { 1032 struct KycContext *kc = ekr->kc; 1033 1034 ekr_expand_response (ekr); 1035 ekr_cleanup (ekr); 1036 if (NULL != kc->exchange_pending_head) 1037 return; /* wait for more */ 1038 if (kc->in_db) 1039 return; 1040 GNUNET_assert (GNUNET_YES == kc->suspended); 1041 kc->phase = PHASE_GENERATE_RESPONSE; 1042 kc->suspended = GNUNET_NO; 1043 MHD_resume_connection (kc->connection); 1044 TALER_MHD_daemon_trigger (); /* we resumed, kick MHD */ 1045 } 1046 1047 1048 /** 1049 * Figure out which exchange accounts from @a keys could 1050 * be used for a KYC auth wire transfer from the account 1051 * that @a ekr is checking. Will set the "pkaa" array 1052 * in @a ekr. 1053 * 1054 * @param[in,out] ekr request we are processing 1055 */ 1056 static void 1057 determine_eligible_accounts ( 1058 struct ExchangeKycRequest *ekr) 1059 { 1060 struct KycContext *kc = ekr->kc; 1061 const struct TALER_EXCHANGE_Keys *keys = ekr->keys; 1062 struct TALER_Amount kyc_amount; 1063 char *merchant_pub_str; 1064 struct TALER_NormalizedPayto np; 1065 1066 { 1067 const struct TALER_EXCHANGE_GlobalFee *gf; 1068 1069 gf = TALER_EXCHANGE_get_global_fee (keys, 1070 GNUNET_TIME_timestamp_get ()); 1071 if (NULL == gf) 1072 { 1073 GNUNET_assert (GNUNET_OK == 1074 TALER_amount_set_zero (keys->currency, 1075 &kyc_amount)); 1076 } 1077 else 1078 { 1079 /* FIXME-#9427: history fee should be globally renamed to KYC fee... */ 1080 kyc_amount = gf->fees.history; 1081 } 1082 } 1083 1084 merchant_pub_str 1085 = GNUNET_STRINGS_data_to_string_alloc ( 1086 &kc->mi->merchant_pub, 1087 sizeof (kc->mi->merchant_pub)); 1088 /* For all accounts of the exchange */ 1089 np = TALER_payto_normalize (ekr->payto_uri); 1090 for (unsigned int i = 0; i<keys->accounts_len; i++) 1091 { 1092 const struct TALER_EXCHANGE_WireAccount *account 1093 = &keys->accounts[i]; 1094 1095 /* KYC auth transfers are never supported with conversion */ 1096 if (NULL != account->conversion_url) 1097 continue; 1098 /* filter by source account by credit_restrictions */ 1099 if (GNUNET_YES != 1100 TALER_EXCHANGE_test_account_allowed (account, 1101 true, /* credit */ 1102 np)) 1103 continue; 1104 /* exchange account is allowed, add it */ 1105 // FIXME: #11520: support short wire transfer subjects! 1106 // if (NULL != account->prepared_transfer_url) // ... 1107 { 1108 const char *exchange_account_payto 1109 = account->fpayto_uri.full_payto; 1110 char *payto_kycauth; 1111 1112 if (TALER_amount_is_zero (&kyc_amount)) 1113 GNUNET_asprintf (&payto_kycauth, 1114 "%s%cmessage=KYC:%s", 1115 exchange_account_payto, 1116 (NULL == strchr (exchange_account_payto, 1117 '?')) 1118 ? '?' 1119 : '&', 1120 merchant_pub_str); 1121 else 1122 GNUNET_asprintf (&payto_kycauth, 1123 "%s%camount=%s&message=KYC:%s", 1124 exchange_account_payto, 1125 (NULL == strchr (exchange_account_payto, 1126 '?')) 1127 ? '?' 1128 : '&', 1129 TALER_amount2s (&kyc_amount), 1130 merchant_pub_str); 1131 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 1132 "Found account %s where KYC auth is possible\n", 1133 payto_kycauth); 1134 GNUNET_assert (0 == 1135 json_array_append_new (ekr->pkaa, 1136 json_string (payto_kycauth))); 1137 GNUNET_free (payto_kycauth); 1138 } 1139 } 1140 GNUNET_free (np.normalized_payto); 1141 GNUNET_free (merchant_pub_str); 1142 } 1143 1144 1145 /** 1146 * Function called with the result of a #TMH_EXCHANGES_keys4exchange() 1147 * operation. Runs the KYC check against the exchange. 1148 * 1149 * @param cls closure with our `struct ExchangeKycRequest *` 1150 * @param keys keys of the exchange context 1151 * @param exchange representation of the exchange 1152 */ 1153 static void 1154 kyc_with_exchange (void *cls, 1155 struct TALER_EXCHANGE_Keys *keys, 1156 struct TMH_Exchange *exchange) 1157 { 1158 struct ExchangeKycRequest *ekr = cls; 1159 1160 (void) exchange; 1161 ekr->fo = NULL; 1162 if (NULL == keys) 1163 { 1164 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 1165 "Failed to download `%skeys`\n", 1166 ekr->exchange_url); 1167 ekr->no_keys = true; 1168 ekr_finished (ekr); 1169 return; 1170 } 1171 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 1172 "Got /keys for `%s'\n", 1173 ekr->exchange_url); 1174 ekr->keys = TALER_EXCHANGE_keys_incref (keys); 1175 if (! ekr->auth_ok) 1176 { 1177 ekr->pkaa = json_array (); 1178 GNUNET_assert (NULL != ekr->pkaa); 1179 determine_eligible_accounts (ekr); 1180 if (0 == json_array_size (ekr->pkaa)) 1181 { 1182 /* No KYC auth wire transfers are possible to this exchange from 1183 our merchant bank account, so we cannot use this account with 1184 this exchange if it has any KYC requirements! */ 1185 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 1186 "KYC auth to `%s' impossible for merchant account `%s'\n", 1187 ekr->exchange_url, 1188 ekr->payto_uri.full_payto); 1189 ekr->kyc_auth_conflict = true; 1190 } 1191 } 1192 ekr_finished (ekr); 1193 } 1194 1195 1196 /** 1197 * Closure for add_unreachable_status(). 1198 */ 1199 struct UnreachableContext 1200 { 1201 /** 1202 * Where we are building the response. 1203 */ 1204 struct KycContext *kc; 1205 1206 /** 1207 * Pointer to our account hash. 1208 */ 1209 const struct TALER_MerchantWireHashP *h_wire; 1210 1211 /** 1212 * Bank account for which we have no status from any exchange. 1213 */ 1214 struct TALER_FullPayto payto_uri; 1215 1216 }; 1217 1218 1219 /** 1220 * Add all trusted exchanges with "unknown" status for the 1221 * bank account given in the context. 1222 * 1223 * @param cls a `struct UnreachableContext` 1224 * @param url base URL of the exchange 1225 * @param exchange internal handle for the exchange 1226 */ 1227 static void 1228 add_unreachable_status (void *cls, 1229 const char *url, 1230 const struct TMH_Exchange *exchange) 1231 { 1232 struct UnreachableContext *uc = cls; 1233 struct KycContext *kc = uc->kc; 1234 1235 clear_status (kc, 1236 "exchange-unreachable"); 1237 GNUNET_assert ( 1238 0 == 1239 json_array_append_new ( 1240 kc->kycs_data, 1241 GNUNET_JSON_PACK ( 1242 TALER_JSON_pack_full_payto ( 1243 "payto_uri", 1244 uc->payto_uri), 1245 GNUNET_JSON_pack_data_auto ( 1246 "h_wire", 1247 uc->h_wire), 1248 GNUNET_JSON_pack_string ( 1249 "exchange_currency", 1250 TMH_EXCHANGES_get_currency (exchange)), 1251 GNUNET_JSON_pack_string ( 1252 "status", 1253 "exchange-unreachable"), 1254 GNUNET_JSON_pack_string ( 1255 "exchange_url", 1256 url), 1257 GNUNET_JSON_pack_bool ("no_keys", 1258 true), 1259 GNUNET_JSON_pack_bool ("auth_conflict", 1260 false), 1261 GNUNET_JSON_pack_uint64 ("exchange_http_status", 1262 0) 1263 ))); 1264 1265 } 1266 1267 1268 /** 1269 * Function called from account_kyc_get_status() with KYC status information 1270 * for this merchant. 1271 * 1272 * @param cls our `struct KycContext *` 1273 * @param h_wire hash of the wire account 1274 * @param payto_uri payto:// URI of the merchant's bank account 1275 * @param exchange_url base URL of the exchange for which this is a status 1276 * @param last_check when did we last get an update on our KYC status from the exchange 1277 * @param kyc_ok true if we satisfied the KYC requirements 1278 * @param access_token access token for the KYC SPA, NULL if we cannot access it yet (need KYC auth wire transfer) 1279 * @param last_http_status last HTTP status from /kyc-check 1280 * @param last_ec last Taler error code from /kyc-check 1281 * @param in_aml_review true if the account is pending review 1282 * @param jlimits JSON array of applicable AccountLimits, or NULL if unknown (like defaults apply) 1283 */ 1284 static void 1285 kyc_status_cb ( 1286 void *cls, 1287 const struct TALER_MerchantWireHashP *h_wire, 1288 struct TALER_FullPayto payto_uri, 1289 const char *exchange_url, 1290 struct GNUNET_TIME_Timestamp last_check, 1291 bool kyc_ok, 1292 const struct TALER_AccountAccessTokenP *access_token, 1293 unsigned int last_http_status, 1294 enum TALER_ErrorCode last_ec, 1295 bool in_aml_review, 1296 const json_t *jlimits) 1297 { 1298 struct KycContext *kc = cls; 1299 struct ExchangeKycRequest *ekr; 1300 1301 if (NULL == exchange_url) 1302 { 1303 struct UnreachableContext uc = { 1304 .kc = kc, 1305 .h_wire = h_wire, 1306 .payto_uri = payto_uri 1307 }; 1308 1309 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 1310 "Account has unknown KYC status for all exchanges.\n"); 1311 TMH_exchange_get_trusted (&add_unreachable_status, 1312 &uc); 1313 return; 1314 } 1315 if (! TMH_EXCHANGES_check_trusted (exchange_url)) 1316 { 1317 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 1318 "Skipping exchange `%s': not trusted\n", 1319 exchange_url); 1320 return; 1321 } 1322 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 1323 "KYC status for `%s' at `%s' is %u/%s/%s/%s\n", 1324 payto_uri.full_payto, 1325 exchange_url, 1326 last_http_status, 1327 kyc_ok ? "KYC OK" : "KYC NEEDED", 1328 in_aml_review ? "IN AML REVIEW" : "NO AML REVIEW", 1329 NULL == jlimits ? "DEFAULT LIMITS" : "CUSTOM LIMITS"); 1330 switch (kc->lpt) 1331 { 1332 case TALER_EXCHANGE_KLPT_NONE: 1333 break; 1334 case TALER_EXCHANGE_KLPT_KYC_AUTH_TRANSFER: 1335 if (NULL != access_token) 1336 kc->return_immediately = true; 1337 break; 1338 case TALER_EXCHANGE_KLPT_INVESTIGATION_DONE: 1339 if (! in_aml_review) 1340 kc->return_immediately = true; 1341 break; 1342 case TALER_EXCHANGE_KLPT_KYC_OK: 1343 if (kyc_ok) 1344 kc->return_immediately = true; 1345 break; 1346 } 1347 ekr = GNUNET_new (struct ExchangeKycRequest); 1348 GNUNET_CONTAINER_DLL_insert (kc->exchange_pending_head, 1349 kc->exchange_pending_tail, 1350 ekr); 1351 ekr->last_http_status = last_http_status; 1352 ekr->last_ec = last_ec; 1353 if (NULL != jlimits) 1354 ekr->jlimits = json_incref ((json_t *) jlimits); 1355 ekr->h_wire = *h_wire; 1356 ekr->exchange_url = GNUNET_strdup (exchange_url); 1357 ekr->payto_uri.full_payto 1358 = GNUNET_strdup (payto_uri.full_payto); 1359 ekr->last_check = last_check; 1360 ekr->kyc_ok = kyc_ok; 1361 ekr->kc = kc; 1362 ekr->in_aml_review = in_aml_review; 1363 ekr->auth_ok = (NULL != access_token); 1364 if ( (! ekr->auth_ok) || 1365 (NULL == ekr->jlimits) ) 1366 { 1367 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 1368 "Awaiting /keys from `%s'\n", 1369 exchange_url); 1370 /* Figure out wire transfer instructions */ 1371 ekr->fo = TMH_EXCHANGES_keys4exchange ( 1372 exchange_url, 1373 false, 1374 &kyc_with_exchange, 1375 ekr); 1376 if (NULL == ekr->fo) 1377 { 1378 GNUNET_break (0); 1379 ekr_finished (ekr); 1380 return; 1381 } 1382 return; 1383 } 1384 ekr->access_token = *access_token; 1385 ekr_finished (ekr); 1386 } 1387 1388 1389 /** 1390 * Check our database for the KYC status. Determines if we then 1391 * need to wait on exchange data or have no exchange and can 1392 * immediately proceed to return 204. 1393 * 1394 * @param[in,out] kc connection we are handling 1395 */ 1396 static void 1397 phase_database_kyc_check (struct KycContext *kc) 1398 { 1399 enum GNUNET_DB_QueryStatus qs; 1400 1401 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 1402 "Checking KYC status for %s (%d/%s)\n", 1403 kc->mi->settings.id, 1404 kc->have_h_wire, 1405 kc->exchange_url); 1406 /* We may run repeatedly due to long-polling; clear data 1407 from previous runs first */ 1408 GNUNET_break (0 == 1409 json_array_clear (kc->kycs_data)); 1410 kc->in_db = true; 1411 qs = TALER_MERCHANTDB_account_kyc_get_status ( 1412 TMH_db, 1413 kc->mi->settings.id, 1414 kc->have_h_wire 1415 ? &kc->h_wire 1416 : NULL, 1417 kc->exchange_url, 1418 &kyc_status_cb, 1419 kc); 1420 kc->in_db = false; 1421 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 1422 "account_kyc_get_status returned %d records\n", 1423 (int) qs); 1424 switch (qs) 1425 { 1426 case GNUNET_DB_STATUS_HARD_ERROR: 1427 case GNUNET_DB_STATUS_SOFT_ERROR: 1428 /* Database error */ 1429 GNUNET_break (0); 1430 finish_request (kc, 1431 TALER_MHD_reply_with_ec ( 1432 kc->connection, 1433 TALER_EC_GENERIC_DB_FETCH_FAILED, 1434 "account_kyc_get_status")); 1435 return; 1436 case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS: 1437 kc->phase = PHASE_NO_ACCOUNTS; 1438 return; 1439 case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT: 1440 /* Handled below */ 1441 break; 1442 } 1443 if (NULL == kc->exchange_pending_head) 1444 { 1445 kc->phase = PHASE_GENERATE_RESPONSE; 1446 return; 1447 } 1448 MHD_suspend_connection (kc->connection); 1449 kc->suspended = GNUNET_YES; 1450 kc->phase = PHASE_SUSPENDED_ON_EXCHANGE; 1451 } 1452 1453 1454 /* ********************* phase_no_accounts *********** */ 1455 1456 /** 1457 * We have no accounts, return a 204 No content, 1458 * or suspend if long-polling. 1459 * 1460 * @param[in,out] kc connection we are handling 1461 */ 1462 static void 1463 phase_no_accounts (struct KycContext *kc) 1464 { 1465 /* We use an Etag of all zeros for the 204 status code */ 1466 static struct GNUNET_ShortHashCode zero_etag; 1467 struct MHD_Response *response; 1468 1469 /* no matching accounts, could not have suspended */ 1470 GNUNET_assert (GNUNET_NO == kc->suspended); 1471 if (kc->have_lp_not_etag && 1472 (0 == GNUNET_memcmp (&zero_etag, 1473 &kc->lp_not_etag)) && 1474 (! GNUNET_TIME_absolute_is_past (kc->timeout)) ) 1475 { 1476 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 1477 "No matching accounts, suspending to wait for this to change\n"); 1478 MHD_suspend_connection (kc->connection); 1479 kc->suspended = GNUNET_YES; 1480 kc->phase = PHASE_SUSPENDED_ON_ACCOUNT; 1481 return; 1482 } 1483 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 1484 "No matching accounts, returning empty response\n"); 1485 response = MHD_create_response_from_buffer_static (0, 1486 NULL); 1487 TALER_MHD_add_global_headers (response, 1488 false); 1489 { 1490 char *etag; 1491 1492 etag = GNUNET_STRINGS_data_to_string_alloc (&zero_etag, 1493 sizeof (zero_etag)); 1494 GNUNET_break (MHD_YES == 1495 MHD_add_response_header (response, 1496 MHD_HTTP_HEADER_ETAG, 1497 etag)); 1498 GNUNET_free (etag); 1499 } 1500 finish_request (kc, 1501 MHD_queue_response (kc->connection, 1502 MHD_HTTP_NO_CONTENT, 1503 response)); 1504 MHD_destroy_response (response); 1505 } 1506 1507 1508 /* ********************* phase_generate_response *********** */ 1509 1510 /** 1511 * Resume the given KYC context and send the final response. Stores the 1512 * response in the @a kc and signals MHD to resume the connection. Also 1513 * ensures MHD runs immediately. 1514 * 1515 * @param kc KYC context 1516 */ 1517 static void 1518 resume_kyc_with_response (struct KycContext *kc) 1519 { 1520 struct GNUNET_ShortHashCode sh; 1521 bool not_modified; 1522 char *can; 1523 unsigned int response_code; 1524 struct MHD_Response *response; 1525 1526 can = TALER_JSON_canonicalize (kc->kycs_data); 1527 GNUNET_assert (GNUNET_YES == 1528 GNUNET_CRYPTO_hkdf_gnunet (&sh, 1529 sizeof (sh), 1530 "KYC-SALT", 1531 strlen ("KYC-SALT"), 1532 can, 1533 strlen (can))); 1534 not_modified = kc->have_lp_not_etag && 1535 (0 == GNUNET_memcmp (&sh, 1536 &kc->lp_not_etag)); 1537 if (not_modified && 1538 (! GNUNET_TIME_absolute_is_past (kc->timeout)) ) 1539 { 1540 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 1541 "Status unchanged, not returning response yet\n"); 1542 wait_for_account (kc); 1543 GNUNET_free (can); 1544 return; 1545 } 1546 { 1547 const char *inm; 1548 1549 inm = MHD_lookup_connection_value (kc->connection, 1550 MHD_GET_ARGUMENT_KIND, 1551 MHD_HTTP_HEADER_IF_NONE_MATCH); 1552 if ( (NULL == inm) || 1553 ('"' != inm[0]) || 1554 ('"' != inm[strlen (inm) - 1]) || 1555 (0 != strncmp (inm + 1, 1556 can, 1557 strlen (can))) ) 1558 not_modified = false; /* must return full response */ 1559 } 1560 GNUNET_free (can); 1561 response_code = not_modified 1562 ? MHD_HTTP_NOT_MODIFIED 1563 : MHD_HTTP_OK; 1564 switch (kc->format) 1565 { 1566 case POF_JSON: 1567 response = TALER_MHD_MAKE_JSON_PACK ( 1568 GNUNET_JSON_pack_array_incref ("kyc_data", 1569 kc->kycs_data)); 1570 break; 1571 case POF_TEXT: 1572 { 1573 enum GNUNET_GenericReturnValue ret; 1574 json_t *obj; 1575 1576 obj = GNUNET_JSON_PACK ( 1577 GNUNET_JSON_pack_array_incref ("kyc_data", 1578 kc->kycs_data)); 1579 ret = TALER_TEMPLATING_build (kc->connection, 1580 &response_code, 1581 "kyc_text", 1582 kc->mi->settings.id, 1583 NULL, 1584 obj, 1585 &response); 1586 json_decref (obj); 1587 switch (ret) 1588 { 1589 case GNUNET_SYSERR: 1590 /* failed to even produce a response */ 1591 GNUNET_break (0); 1592 kc->phase = PHASE_RETURN_NO; 1593 return; 1594 case GNUNET_NO: 1595 finish_request (kc, 1596 MHD_queue_response ( 1597 kc->connection, 1598 response_code, 1599 response)); 1600 MHD_destroy_response (response); 1601 return; 1602 case GNUNET_OK: 1603 TALER_MHD_add_global_headers (response, 1604 false); 1605 GNUNET_break (MHD_YES == 1606 MHD_add_response_header (response, 1607 MHD_HTTP_HEADER_CONTENT_TYPE, 1608 "text/plain")); 1609 break; 1610 } /* switch (ret) */ 1611 } 1612 break; 1613 case POF_PDF: 1614 // not yet implemented 1615 GNUNET_assert (0); 1616 break; 1617 } 1618 { 1619 char *etag; 1620 char *qetag; 1621 1622 etag = GNUNET_STRINGS_data_to_string_alloc (&sh, 1623 sizeof (sh)); 1624 GNUNET_asprintf (&qetag, 1625 "\"%s\"", 1626 etag); 1627 GNUNET_break (MHD_YES == 1628 MHD_add_response_header (response, 1629 MHD_HTTP_HEADER_ETAG, 1630 qetag)); 1631 GNUNET_free (qetag); 1632 GNUNET_free (etag); 1633 } 1634 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 1635 "Resuming /kyc handling as exchange interaction is done (%u)\n", 1636 MHD_HTTP_OK); 1637 finish_request (kc, 1638 MHD_queue_response ( 1639 kc->connection, 1640 response_code, 1641 response)); 1642 MHD_destroy_response (response); 1643 } 1644 1645 1646 /** 1647 * We are done with asynchronous processing, generate the 1648 * response for the @e kc. 1649 * 1650 * @param[in,out] kc KYC context to respond for 1651 */ 1652 static void 1653 phase_generate_response (struct KycContext *kc) 1654 { 1655 GNUNET_assert (NULL == kc->exchange_pending_head); 1656 GNUNET_assert (GNUNET_NO == kc->suspended); 1657 /* FIXME: mixing these two suspend conditions like this 1658 does not seem sane */ 1659 if ( (! kc->return_immediately) && 1660 (! GNUNET_TIME_absolute_is_past (kc->timeout)) ) 1661 { 1662 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 1663 "Suspending: long poll target %d not reached\n", 1664 kc->lpt); 1665 wait_for_account (kc); 1666 return; 1667 } 1668 if ( (! GNUNET_TIME_absolute_is_past (kc->timeout)) && 1669 ( (NULL != kc->lp_not_status) || 1670 (NULL != kc->lp_status) ) ) 1671 { 1672 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 1673 "Long-poll target status not reached, not returning response yet\n"); 1674 wait_for_account (kc); 1675 return; 1676 } 1677 /* All exchange requests done, create final 1678 big response from cumulated replies */ 1679 resume_kyc_with_response (kc); 1680 } 1681 1682 1683 /* ******************* main logic ***************** */ 1684 1685 /** 1686 * Check the KYC status of an instance. 1687 * 1688 * @param mi instance to check KYC status of 1689 * @param connection the MHD connection to handle 1690 * @param[in,out] hc context with further information about the request 1691 * @return MHD result code 1692 */ 1693 static enum MHD_Result 1694 get_instances_ID_kyc ( 1695 struct TMH_MerchantInstance *mi, 1696 struct MHD_Connection *connection, 1697 struct TMH_HandlerContext *hc) 1698 { 1699 struct KycContext *kc = hc->ctx; 1700 1701 if (NULL == kc) 1702 { 1703 kc = GNUNET_new (struct KycContext); 1704 kc->mi = mi; 1705 hc->ctx = kc; 1706 hc->cc = &kyc_context_cleanup; 1707 GNUNET_CONTAINER_DLL_insert (kc_head, 1708 kc_tail, 1709 kc); 1710 kc->connection = connection; 1711 kc->hc = hc; 1712 TALER_MHD_parse_request_timeout (connection, 1713 &kc->timeout); 1714 { 1715 uint64_t num = 0; 1716 int val; 1717 1718 TALER_MHD_parse_request_number (connection, 1719 "lpt", 1720 &num); 1721 val = (int) num; 1722 if ( (val < 0) || 1723 (val > TALER_EXCHANGE_KLPT_MAX) ) 1724 { 1725 /* Protocol violation, but we can be graceful and 1726 just ignore the long polling! */ 1727 GNUNET_break_op (0); 1728 val = TALER_EXCHANGE_KLPT_NONE; 1729 } 1730 kc->lpt = (enum TALER_EXCHANGE_KycLongPollTarget) val; 1731 } 1732 kc->return_immediately 1733 = (TALER_EXCHANGE_KLPT_NONE == kc->lpt); 1734 kc->lp_status = MHD_lookup_connection_value ( 1735 connection, 1736 MHD_GET_ARGUMENT_KIND, 1737 "lp_status"); 1738 kc->lp_not_status = MHD_lookup_connection_value ( 1739 connection, 1740 MHD_GET_ARGUMENT_KIND, 1741 "lp_not_status"); 1742 TALER_MHD_parse_request_arg_auto (connection, 1743 "h_wire", 1744 &kc->h_wire, 1745 kc->have_h_wire); 1746 TALER_MHD_parse_request_arg_auto (connection, 1747 "lp_not_etag", 1748 &kc->lp_not_etag, 1749 kc->have_lp_not_etag); 1750 } 1751 while (1) 1752 { 1753 switch (kc->phase) 1754 { 1755 case PHASE_INIT: 1756 phase_init (kc); 1757 break; 1758 case PHASE_DETERMINE_LONG_POLL: 1759 phase_determine_long_poll (kc); 1760 break; 1761 case PHASE_DATABASE_KYC_CHECK: 1762 phase_database_kyc_check (kc); 1763 break; 1764 case PHASE_NO_ACCOUNTS: 1765 phase_no_accounts (kc); 1766 break; 1767 case PHASE_GENERATE_RESPONSE: 1768 phase_generate_response (kc); 1769 break; 1770 case PHASE_IN_SHUTDOWN: 1771 /* during shutdown, we don't generate any more replies */ 1772 GNUNET_assert (GNUNET_SYSERR == kc->suspended); 1773 return MHD_NO; 1774 case PHASE_RETURN_YES: 1775 return MHD_YES; 1776 case PHASE_RETURN_NO: 1777 return MHD_NO; 1778 case PHASE_SUSPENDED_ON_ACCOUNT: 1779 /* suspended */ 1780 GNUNET_assert (GNUNET_YES == kc->suspended); 1781 return MHD_YES; 1782 case PHASE_SUSPENDED_ON_EXCHANGE: 1783 /* suspended */ 1784 GNUNET_assert (GNUNET_YES == kc->suspended); 1785 return MHD_YES; 1786 } 1787 } 1788 } 1789 1790 1791 enum MHD_Result 1792 TMH_private_get_instances_ID_kyc ( 1793 const struct TMH_RequestHandler *rh, 1794 struct MHD_Connection *connection, 1795 struct TMH_HandlerContext *hc) 1796 { 1797 struct TMH_MerchantInstance *mi = hc->instance; 1798 1799 (void) rh; 1800 return get_instances_ID_kyc (mi, 1801 connection, 1802 hc); 1803 } 1804 1805 1806 enum MHD_Result 1807 TMH_private_get_instances_default_ID_kyc ( 1808 const struct TMH_RequestHandler *rh, 1809 struct MHD_Connection *connection, 1810 struct TMH_HandlerContext *hc) 1811 { 1812 struct TMH_MerchantInstance *mi; 1813 1814 (void) rh; 1815 mi = TMH_lookup_instance (hc->infix); 1816 if (NULL == mi) 1817 { 1818 return TALER_MHD_reply_with_error ( 1819 connection, 1820 MHD_HTTP_NOT_FOUND, 1821 TALER_EC_MERCHANT_GENERIC_INSTANCE_UNKNOWN, 1822 hc->infix); 1823 } 1824 return get_instances_ID_kyc (mi, 1825 connection, 1826 hc); 1827 } 1828 1829 1830 /* end of taler-merchant-httpd_get-private-kyc.c */