taler-merchant-kyccheck.c (67663B)
1 /* 2 This file is part of TALER 3 Copyright (C) 2024 Taler Systems SA 4 5 TALER is free software; you can redistribute it and/or modify it under the 6 terms of the GNU Affero General Public License as published by the Free Software 7 Foundation; either version 3, or (at your option) any later version. 8 9 TALER is distributed in the hope that it will be useful, but WITHOUT ANY 10 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR 11 A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. 12 13 You should have received a copy of the GNU Affero General Public License along with 14 TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/> 15 */ 16 /** 17 * @file src/backend/taler-merchant-kyccheck.c 18 * @brief Process that check the KYC status of our bank accounts at all exchanges 19 * @author Christian Grothoff 20 */ 21 #include "platform.h" 22 struct Inquiry; 23 #define TALER_EXCHANGE_GET_KYC_CHECK_RESULT_CLOSURE struct Inquiry 24 #define TALER_EXCHANGE_GET_KYC_INFO_RESULT_CLOSURE struct Inquiry 25 #define TALER_EXCHANGE_POST_KYC_UPLOAD_RESULT_CLOSURE struct Inquiry 26 #include "microhttpd.h" 27 #include <gnunet/gnunet_util_lib.h> 28 #include <jansson.h> 29 #include <pthread.h> 30 #include <regex.h> 31 #include <taler/taler_dbevents.h> 32 #include <taler/taler_json_lib.h> 33 #include <taler/taler_exchange_service.h> 34 #include <taler/exchange/post-kyc-upload-ID.h> 35 #include "taler/taler_merchant_util.h" 36 #include "taler/taler_merchant_bank_lib.h" 37 #include "merchantdb_lib.h" 38 #include "merchantdb_lib.h" 39 #include "merchant-database/iterate_outdated_kyc_statuses.h" 40 #include "merchant-database/insert_kyc_status.h" 41 #include "merchant-database/delete_tos_accepted_early.h" 42 #include "merchant-database/get_kyc_status.h" 43 #include "merchant-database/get_tos_accepted_early.h" 44 #include "merchant-database/set_instance.h" 45 #include "merchant-database/iterate_accounts.h" 46 #include "merchant-database/get_exchange_keys.h" 47 #include "merchant-database/event_listen.h" 48 #include "merchant-database/preflight.h" 49 #include "merchant-database/start.h" 50 51 52 /** 53 * Timeout for the exchange interaction. Rather long as we should do 54 * long-polling and do not want to wake up too often. 55 */ 56 #define EXCHANGE_TIMEOUT GNUNET_TIME_relative_multiply ( \ 57 GNUNET_TIME_UNIT_MINUTES, \ 58 30) 59 60 /** 61 * How long do we wait between requests if all we wait 62 * for is a change in the AML investigation status? 63 * Default value. 64 */ 65 #define AML_FREQ GNUNET_TIME_relative_multiply ( \ 66 GNUNET_TIME_UNIT_HOURS, \ 67 6) 68 69 /** 70 * How long do we wait between requests if all we wait 71 * for is a change in the AML investigation status? 72 */ 73 static struct GNUNET_TIME_Relative aml_freq; 74 75 /** 76 * How frequently do we check for updates to our KYC status 77 * if there is no actual reason to check? Set to a very low 78 * frequency, just to ensure we eventually notice. 79 * Default value. 80 */ 81 #define AML_LOW_FREQ GNUNET_TIME_relative_multiply ( \ 82 GNUNET_TIME_UNIT_DAYS, \ 83 7) 84 85 /** 86 * How frequently do we check for updates to our KYC status 87 * if there is no actual reason to check? Set to a very low 88 * frequency, just to ensure we eventually notice. 89 */ 90 static struct GNUNET_TIME_Relative aml_low_freq; 91 92 93 /** 94 * How many inquiries do we process concurrently at most. 95 */ 96 #define OPEN_INQUIRY_LIMIT 1024 97 98 /** 99 * Name of the KYC form (``FORM_ID``) the exchange uses to affirm 100 * acceptance of the terms of service. Must match the value submitted 101 * by #TALER_EXCHANGE_post_kyc_upload_accept_tos_create(). 102 */ 103 #define ACCEPT_TOS_FORM "accept-tos" 104 105 /** 106 * Minimum delay before we retry after the exchange returned an 107 * internal error to our attempt to automatically accept the terms 108 * of service on behalf of the user. 109 */ 110 #define TOS_ERROR_RETRY_DELAY GNUNET_TIME_UNIT_HOURS 111 112 113 /** 114 * Information about an exchange. 115 */ 116 struct Exchange 117 { 118 /** 119 * Kept in a DLL. 120 */ 121 struct Exchange *next; 122 123 /** 124 * Kept in a DLL. 125 */ 126 struct Exchange *prev; 127 128 /** 129 * The keys of this exchange 130 */ 131 struct TALER_EXCHANGE_Keys *keys; 132 133 }; 134 135 136 /** 137 * Information about an Account. 138 */ 139 struct Account 140 { 141 /** 142 * Kept in a DLL. 143 */ 144 struct Account *next; 145 146 /** 147 * Kept in a DLL. 148 */ 149 struct Account *prev; 150 151 /** 152 * Head of inquiries for this account. 153 */ 154 struct Inquiry *i_head; 155 156 /** 157 * Tail of inquiries for this account. 158 */ 159 struct Inquiry *i_tail; 160 161 /** 162 * Merchant instance this account belongs to. 163 */ 164 char *instance_id; 165 166 /** 167 * The payto-URI of this account. 168 */ 169 struct TALER_FullPayto merchant_account_uri; 170 171 /** 172 * Wire hash of the merchant bank account (with the 173 * respective salt). 174 */ 175 struct TALER_MerchantWireHashP h_wire; 176 177 /** 178 * Private key of the instance. 179 */ 180 union TALER_AccountPrivateKeyP ap; 181 182 /** 183 * Hash of the @e merchant_account_uri. 184 */ 185 struct TALER_NormalizedPaytoHashP h_payto; 186 187 /** 188 * Database generation when this account 189 * was last active. 190 */ 191 uint64_t account_gen; 192 193 }; 194 195 196 /** 197 * Information about an inquiry job. 198 */ 199 struct Inquiry 200 { 201 /** 202 * Key in the index of inquiries by instance, account and exchange. 203 */ 204 struct GNUNET_HashCode key; 205 206 /** 207 * Kept in a DLL. 208 */ 209 struct Inquiry *next; 210 211 /** 212 * Kept in a DLL. 213 */ 214 struct Inquiry *prev; 215 216 /** 217 * Main task for this inquiry. 218 */ 219 struct GNUNET_SCHEDULER_Task *task; 220 221 /** 222 * Which exchange is this inquiry about. 223 */ 224 struct Exchange *e; 225 226 /** 227 * Which account is this inquiry about. 228 */ 229 struct Account *a; 230 231 /** 232 * AccountLimits that apply to the account, NULL 233 * if unknown. 234 */ 235 json_t *jlimits; 236 237 /** 238 * Handle for the actual HTTP request to the exchange. 239 */ 240 struct TALER_EXCHANGE_GetKycCheckHandle *kyc; 241 242 /** 243 * Handle for fetching /kyc-info to discover the upload ID used to 244 * automatically accept the terms of service, NULL if not active. 245 */ 246 struct TALER_EXCHANGE_GetKycInfoHandle *kyc_info; 247 248 /** 249 * Handle for the /kyc-upload request submitting the automatic 250 * terms-of-service acceptance, NULL if not active. 251 */ 252 struct TALER_EXCHANGE_PostKycUploadHandle *tos_upload; 253 254 /** 255 * If non-NULL, the ``Taler-Terms-Version`` of the terms of service 256 * that the user accepted early (via ``POST /private/accept-tos-early``) 257 * and that we are trying to submit to the exchange on their behalf. 258 * Owned by the inquiry. 259 */ 260 char *tos_etag; 261 262 /** 263 * Access token for the /kyc-info API. 264 */ 265 struct TALER_AccountAccessTokenP access_token; 266 267 /** 268 * Last time we called the /kyc-check endpoint. 269 */ 270 struct GNUNET_TIME_Timestamp last_kyc_check; 271 272 /** 273 * When is the next KYC check due? 274 */ 275 struct GNUNET_TIME_Absolute due; 276 277 /** 278 * When should the current KYC time out? 279 */ 280 struct GNUNET_TIME_Absolute timeout; 281 282 /** 283 * Current exponential backoff. 284 */ 285 struct GNUNET_TIME_Relative backoff; 286 287 /** 288 * Rule generation known to the client, 0 for none. 289 * Corresponds to the decision row in the exchange. 290 */ 291 uint64_t rule_gen; 292 293 /** 294 * Last HTTP status returned by the exchange from 295 * the /kyc-check endpoint. 296 */ 297 unsigned int last_http_status; 298 299 /** 300 * Last Taler error code returned by the exchange from 301 * the /kyc-check endpoint. 302 */ 303 enum TALER_ErrorCode last_ec; 304 305 /** 306 * True if this is not our first time we make this request. 307 */ 308 bool not_first_time; 309 310 /** 311 * Do soft limits on transactions apply to this merchant for operations 312 * merchants care about? If so, we should increase our request frequency 313 * and ask more often to see if they were lifted. 314 */ 315 bool zero_limited; 316 317 /** 318 * Did we not run this inquiry due to limits? 319 */ 320 bool limited; 321 322 /** 323 * Do we believe this account's KYC is in good shape? 324 */ 325 bool kyc_ok; 326 327 /** 328 * True if merchant did perform this account's KYC AUTH transfer and @e access_token is set. 329 */ 330 bool auth_ok; 331 332 /** 333 * True if the account is known to be currently under 334 * investigation by AML staff. 335 */ 336 bool aml_review; 337 338 }; 339 340 341 /** 342 * Head of known exchanges. 343 */ 344 static struct Exchange *e_head; 345 346 /** 347 * Tail of known exchanges. 348 */ 349 static struct Exchange *e_tail; 350 351 /** 352 * Head of accounts. 353 */ 354 static struct Account *a_head; 355 356 /** 357 * Tail of accounts. 358 */ 359 static struct Account *a_tail; 360 361 /** 362 * The merchant's configuration. 363 */ 364 static const struct GNUNET_CONFIGURATION_Handle *cfg; 365 366 /** 367 * Our database connection. 368 */ 369 static struct TALER_MERCHANTDB_PostgresContext *pg; 370 371 /** 372 * Handle to the context for interacting with the bank. 373 */ 374 static struct GNUNET_CURL_Context *ctx; 375 376 /** 377 * Scheduler context for running the @e ctx. 378 */ 379 static struct GNUNET_CURL_RescheduleContext *rc; 380 381 /** 382 * Event handler to learn that there may be new bank 383 * accounts to check. 384 */ 385 static struct GNUNET_DB_EventHandler *eh_accounts; 386 387 /** 388 * Event handler to learn that there may be new exchange 389 * keys to check. 390 */ 391 static struct GNUNET_DB_EventHandler *eh_keys; 392 393 /** 394 * Event handler to learn that there was a KYC 395 * rule triggered and we need to check the KYC 396 * status for an account. 397 */ 398 static struct GNUNET_DB_EventHandler *eh_rule; 399 400 /** 401 * Event handler to learn that higher-frequency KYC 402 * checks were forced by an application actively inspecting 403 * some KYC status values. 404 */ 405 static struct GNUNET_DB_EventHandler *eh_update_forced; 406 407 /** 408 * Event handler to learn that we got new /keys 409 * from an exchange and should reconsider eligibility. 410 */ 411 static struct GNUNET_DB_EventHandler *keys_rule; 412 413 /** 414 * Main task to discover (new) accounts. 415 */ 416 static struct GNUNET_SCHEDULER_Task *account_task; 417 418 /** 419 * Pending refreshes, coalesced by instance serial. 420 */ 421 struct Refresh 422 { 423 struct Refresh *next; 424 struct Refresh *prev; 425 struct GNUNET_HashCode key; 426 uint64_t merchant_serial; 427 }; 428 429 static struct Refresh *refresh_head; 430 static struct Refresh *refresh_tail; 431 static struct GNUNET_CONTAINER_MultiHashMap *refresh_map; 432 static struct GNUNET_CONTAINER_MultiHashMap *inquiry_map; 433 static struct GNUNET_SCHEDULER_Task *refresh_task; 434 435 /** 436 * Counter determining how often we have called 437 * "iterate_accounts" on the database. 438 */ 439 static uint64_t database_gen; 440 441 /** 442 * How many active inquiries do we have right now. 443 */ 444 static unsigned int active_inquiries; 445 446 /** 447 * Value to return from main(). 0 on success, non-zero on errors. 448 */ 449 static int global_ret; 450 451 /** 452 * Should we enable HTTP/2 and HTTP/3 when talking to the exchange? 453 * Those are not expected to be terribly beneficial for a client with 454 * stable connections to a few servers, but they could cause stability 455 * issues with libcurl. Hence we *default* to HTTP/1.1-only, as that 456 * is the conservative and most tested code path. 457 */ 458 static int enable_h3; 459 460 /** 461 * #GNUNET_YES if we are in test mode and should exit when idle. 462 */ 463 static int test_mode; 464 465 /** 466 * True if the last DB query was limited by the 467 * #OPEN_INQUIRY_LIMIT and we thus should check again 468 * as soon as we are substantially below that limit, 469 * and not only when we get a DB notification. 470 */ 471 static bool at_limit; 472 473 474 /** 475 * Check about performing a /kyc-check request with the 476 * exchange for the given inquiry. 477 * 478 * @param cls a `struct Inquiry` to process 479 */ 480 static void 481 inquiry_work (void *cls); 482 483 484 /** 485 * Hash a fully qualified inquiry identity. Include string terminators to 486 * keep adjacent components unambiguous. 487 */ 488 static void 489 inquiry_key (const char *instance_id, 490 const struct TALER_MerchantWireHashP *h_wire, 491 const char *exchange_url, 492 struct GNUNET_HashCode *key) 493 { 494 struct GNUNET_HashContext *hc = GNUNET_CRYPTO_hash_context_start (); 495 496 GNUNET_CRYPTO_hash_context_read (hc, 497 instance_id, 498 strlen (instance_id) + 1); 499 GNUNET_CRYPTO_hash_context_read (hc, 500 h_wire, 501 sizeof (*h_wire)); 502 GNUNET_CRYPTO_hash_context_read (hc, 503 exchange_url, 504 strlen (exchange_url) + 1); 505 GNUNET_CRYPTO_hash_context_finish (hc, 506 key); 507 } 508 509 510 /** 511 * An inquiry keeps its active slot through automatic ToS acceptance. 512 */ 513 static bool 514 inquiry_busy (const struct Inquiry *i) 515 { 516 return (NULL != i->kyc) || 517 (NULL != i->kyc_info) || 518 (NULL != i->tos_upload); 519 } 520 521 522 /** 523 * Request an immediate check, sharing any active or queued work. 524 */ 525 static void 526 request_inquiry (struct Inquiry *i) 527 { 528 if (inquiry_busy (i)) 529 return; 530 i->due = GNUNET_TIME_UNIT_ZERO_ABS; 531 if (i->limited) 532 return; 533 if (NULL != i->task) 534 GNUNET_SCHEDULER_cancel (i->task); 535 i->task = GNUNET_SCHEDULER_add_now (&inquiry_work, 536 i); 537 } 538 539 540 /** 541 * An inquiry finished, check if we should resume others. 542 */ 543 static void 544 end_inquiry (void) 545 { 546 GNUNET_assert (active_inquiries > 0); 547 active_inquiries--; 548 if ( (active_inquiries < OPEN_INQUIRY_LIMIT / 2) && 549 (at_limit) ) 550 { 551 at_limit = false; 552 for (struct Account *a = a_head; 553 NULL != a; 554 a = a->next) 555 { 556 for (struct Inquiry *i = a->i_head; 557 NULL != i; 558 i = i->next) 559 { 560 if (! i->limited) 561 continue; 562 i->limited = false; 563 GNUNET_assert (NULL == i->task); 564 /* done synchronously so that the active_inquiries 565 is updated immediately */ 566 inquiry_work (i); 567 if (at_limit) 568 break; 569 } 570 if (at_limit) 571 break; 572 } 573 } 574 if ( (! at_limit) && 575 (0 == active_inquiries) && 576 (test_mode) ) 577 { 578 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 579 "No more open inquiries and in test mode. Existing.\n"); 580 GNUNET_SCHEDULER_shutdown (); 581 return; 582 } 583 } 584 585 586 /** 587 * Pack the given @a limit into the JSON @a limits array. 588 * 589 * @param limit account limit to pack 590 * @param[in,out] limits JSON array to extend 591 */ 592 static void 593 pack_limit (const struct TALER_EXCHANGE_AccountLimit *limit, 594 json_t *limits) 595 { 596 json_t *jl; 597 598 jl = GNUNET_JSON_PACK ( 599 TALER_JSON_pack_kycte ("operation_type", 600 limit->operation_type), 601 GNUNET_JSON_pack_time_rel ("timeframe", 602 limit->timeframe), 603 TALER_JSON_pack_amount ("threshold", 604 &limit->threshold), 605 GNUNET_JSON_pack_bool ("soft_limit", 606 limit->soft_limit) 607 ); 608 GNUNET_assert (0 == 609 json_array_append_new (limits, 610 jl)); 611 } 612 613 614 /** 615 * Update KYC status for @a i based on 616 * @a account_kyc_status 617 * 618 * @param[in,out] i inquiry context, jlimits is updated 619 * @param account_kyc_status account KYC status details 620 */ 621 static void 622 store_kyc_status ( 623 struct Inquiry *i, 624 const struct TALER_EXCHANGE_AccountKycStatus *account_kyc_status) 625 { 626 json_t *jlimits; 627 628 json_decref (i->jlimits); 629 jlimits = json_array (); 630 GNUNET_assert (NULL != jlimits); 631 i->zero_limited = false; 632 for (unsigned int j = 0; j<account_kyc_status->limits_length; j++) 633 { 634 const struct TALER_EXCHANGE_AccountLimit *limit 635 = &account_kyc_status->limits[j]; 636 637 pack_limit (limit, 638 jlimits); 639 if (TALER_amount_is_zero (&limit->threshold) && 640 limit->soft_limit && 641 ( (TALER_KYCLOGIC_KYC_TRIGGER_DEPOSIT == limit->operation_type) || 642 (TALER_KYCLOGIC_KYC_TRIGGER_AGGREGATE == limit->operation_type) || 643 (TALER_KYCLOGIC_KYC_TRIGGER_TRANSACTION == limit->operation_type) ) ) 644 { 645 i->zero_limited = true; 646 } 647 } 648 i->jlimits = jlimits; 649 GNUNET_break (! GNUNET_is_zero (&account_kyc_status->access_token)); 650 i->access_token = account_kyc_status->access_token; 651 i->aml_review = account_kyc_status->aml_review; 652 i->kyc_ok = (MHD_HTTP_OK == i->last_http_status); 653 } 654 655 656 /** 657 * The current interaction with the exchange for inquiry @a i is 658 * complete (or was aborted). Schedule the next periodic KYC check 659 * at @a i->due and release the active-inquiry slot. 660 * 661 * @param[in,out] i the inquiry to reschedule 662 */ 663 static void 664 finish_inquiry (struct Inquiry *i) 665 { 666 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 667 "Will repeat inquiry in %s\n", 668 GNUNET_TIME_relative2s ( 669 GNUNET_TIME_absolute_get_remaining (i->due), 670 true)); 671 if (! GNUNET_TIME_absolute_is_never (i->due)) 672 i->task = GNUNET_SCHEDULER_add_at (i->due, 673 &inquiry_work, 674 i); 675 end_inquiry (); 676 } 677 678 679 /** 680 * Clear the tos-accepted data from the user, we do not 681 * need the flag anymore, either because we passed it on 682 * to the exchange or because they are too old. 683 * 684 * @param i inquiry this is about 685 */ 686 static void 687 clear_tos (const struct Inquiry *i) 688 { 689 enum GNUNET_DB_QueryStatus qs; 690 691 qs = TALER_MERCHANTDB_set_instance (pg, 692 i->a->instance_id); 693 if (qs < 0) 694 { 695 GNUNET_break (0); 696 global_ret = EXIT_FAILURE; 697 GNUNET_SCHEDULER_shutdown (); 698 return; 699 } 700 if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs) 701 { 702 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 703 "Instance `%s' vanished, nothing to clear\n", 704 i->a->instance_id); 705 return; 706 } 707 qs = TALER_MERCHANTDB_delete_tos_accepted_early ( 708 pg, 709 i->a->instance_id, 710 i->e->keys->exchange_url); 711 GNUNET_break (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT == 712 TALER_MERCHANTDB_set_instance (pg, 713 NULL)); 714 if (qs < 0) 715 { 716 GNUNET_break (0); 717 global_ret = EXIT_FAILURE; 718 GNUNET_SCHEDULER_shutdown (); 719 return; 720 } 721 } 722 723 724 /** 725 * Function called with the result of submitting an automatic 726 * terms-of-service acceptance to the exchange via /kyc-upload. 727 * 728 * @param i the inquiry the acceptance was for 729 * @param pr the exchange's response 730 */ 731 static void 732 tos_upload_cb (struct Inquiry *i, 733 const struct TALER_EXCHANGE_PostKycUploadResponse *pr) 734 { 735 unsigned int http_status = pr->hr.http_status; 736 737 i->tos_upload = NULL; 738 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 739 "Automatic ToS acceptance for `%s' at `%s' returned HTTP %u\n", 740 i->a->merchant_account_uri.full_payto, 741 i->e->keys->exchange_url, 742 http_status); 743 switch (http_status) 744 { 745 case MHD_HTTP_OK: 746 case MHD_HTTP_NO_CONTENT: 747 /* Exchange accepted the terms of service: re-check KYC now. */ 748 i->due = GNUNET_TIME_UNIT_ZERO_ABS; 749 clear_tos (i); 750 break; 751 case 0: /* no answer, like network failure */ 752 case MHD_HTTP_INTERNAL_SERVER_ERROR: 753 case MHD_HTTP_BAD_GATEWAY: 754 case MHD_HTTP_REQUEST_ENTITY_TOO_LARGE: /* Wild error */ 755 /* Internal/transient error at the exchange: do NOT clear the early 756 acceptance, but back off for at least an hour before retrying 757 with a regular periodic KYC check. */ 758 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 759 "Exchange `%s' failed to process automatic ToS acceptance (HTTP %u); retrying later\n", 760 i->e->keys->exchange_url, 761 http_status); 762 i->due = GNUNET_TIME_relative_to_absolute ( 763 GNUNET_TIME_randomize (TOS_ERROR_RETRY_DELAY)); 764 break; 765 case MHD_HTTP_NOT_FOUND: 766 /* Something must have changed exchange-side, try again 767 immediately, but do not clear ToS acceptance */ 768 i->due = GNUNET_TIME_UNIT_ZERO_ABS; 769 clear_tos (i); 770 break; 771 case MHD_HTTP_BAD_REQUEST: 772 /* This should not happen, go back to manual KYC */ 773 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 774 "Exchange `%s' failed to process automatic ToS acceptance (HTTP %u); retrying later\n", 775 i->e->keys->exchange_url, 776 http_status); 777 i->due = GNUNET_TIME_relative_to_absolute ( 778 GNUNET_TIME_randomize (TOS_ERROR_RETRY_DELAY)); 779 break; 780 case MHD_HTTP_CONFLICT: 781 /* Exchange rejected the accepted ToS version (ETag not acceptable 782 or ToS acceptance disappeared): 783 clear the early acceptance so we do not loop, then re-check KYC 784 (the user will have to accept the ToS through the regular flow 785 if it still applies). */ 786 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 787 "Exchange `%s' rejected early ToS acceptance (version `%s', HTTP %u); clearing early acceptance\n", 788 i->e->keys->exchange_url, 789 i->tos_etag, 790 http_status); 791 clear_tos (i); 792 i->due = GNUNET_TIME_UNIT_ZERO_ABS; 793 break; 794 } 795 GNUNET_free (i->tos_etag); 796 finish_inquiry (i); 797 } 798 799 800 /** 801 * Submit an automatic terms-of-service acceptance for inquiry @a i to 802 * the exchange, using the @a id of the corresponding KYC requirement 803 * (obtained from /kyc-info) and the early-accepted version in 804 * @a i->tos_etag. 805 * 806 * @param[in,out] i inquiry to submit the ToS acceptance for 807 * @param id KYC requirement / upload ID for the terms-of-service form 808 */ 809 static void 810 start_tos_upload (struct Inquiry *i, 811 const char *id) 812 { 813 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 814 "Submitting automatic ToS acceptance (version `%s', id `%s') to `%s'\n", 815 i->tos_etag, 816 id, 817 i->e->keys->exchange_url); 818 i->tos_upload = TALER_EXCHANGE_post_kyc_upload_accept_tos_create ( 819 ctx, 820 i->e->keys->exchange_url, 821 id, 822 i->tos_etag); 823 if ( (NULL == i->tos_upload) || 824 (TALER_EC_NONE != 825 TALER_EXCHANGE_post_kyc_upload_start (i->tos_upload, 826 &tos_upload_cb, 827 i)) ) 828 { 829 GNUNET_break (0); 830 if (NULL != i->tos_upload) 831 { 832 TALER_EXCHANGE_post_kyc_upload_cancel (i->tos_upload); 833 i->tos_upload = NULL; 834 } 835 /* Could not even start the upload: treat as transient, keep the 836 early acceptance and retry with a regular periodic check. */ 837 GNUNET_free (i->tos_etag); 838 finish_inquiry (i); 839 } 840 } 841 842 843 /** 844 * Function called with the result of fetching /kyc-info while trying 845 * to automatically accept the terms of service. Finds the ID of the 846 * terms-of-service requirement and submits the acceptance. 847 * 848 * @param i the inquiry the lookup was for 849 * @param ir the exchange's response 850 */ 851 static void 852 tos_info_cb (struct Inquiry *i, 853 const struct TALER_EXCHANGE_GetKycInfoResponse *ir) 854 { 855 i->kyc_info = NULL; 856 if (MHD_HTTP_OK == ir->hr.http_status) 857 { 858 const char *id = NULL; 859 860 for (size_t j = 0; j < ir->details.ok.requirements_length; j++) 861 { 862 const struct TALER_EXCHANGE_RequirementInformation *req 863 = &ir->details.ok.requirements[j]; 864 865 if ( (NULL != req->form) && 866 (NULL != req->id) && 867 (0 == strcmp (req->form, 868 ACCEPT_TOS_FORM)) ) 869 { 870 id = req->id; 871 break; 872 } 873 } 874 if (NULL != id) 875 { 876 start_tos_upload (i, 877 id); 878 return; 879 } 880 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 881 "No `%s' requirement at `%s'; cannot auto-accept ToS, falling back to periodic check\n", 882 ACCEPT_TOS_FORM, 883 i->e->keys->exchange_url); 884 } 885 else 886 { 887 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 888 "GET /kyc-info at `%s' returned HTTP %u; cannot auto-accept ToS now\n", 889 i->e->keys->exchange_url, 890 ir->hr.http_status); 891 } 892 /* Could not determine the upload ID: keep the early acceptance and 893 retry on the next regular periodic KYC check. */ 894 GNUNET_free (i->tos_etag); 895 finish_inquiry (i); 896 } 897 898 899 /** 900 * Start the automatic terms-of-service acceptance for inquiry @a i by 901 * fetching /kyc-info to discover the ID of the terms-of-service 902 * requirement. The early-accepted version is in @a i->tos_etag. 903 * 904 * @param[in,out] i inquiry to auto-accept the terms of service for 905 */ 906 static void 907 start_tos_info (struct Inquiry *i) 908 { 909 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 910 "Fetching /kyc-info from `%s' to auto-accept ToS for `%s'\n", 911 i->e->keys->exchange_url, 912 i->a->merchant_account_uri.full_payto); 913 i->kyc_info = TALER_EXCHANGE_get_kyc_info_create (ctx, 914 i->e->keys->exchange_url, 915 &i->access_token); 916 if ( (NULL == i->kyc_info) || 917 (TALER_EC_NONE != 918 TALER_EXCHANGE_get_kyc_info_start (i->kyc_info, 919 &tos_info_cb, 920 i)) ) 921 { 922 GNUNET_break (0); 923 if (NULL != i->kyc_info) 924 { 925 TALER_EXCHANGE_get_kyc_info_cancel (i->kyc_info); 926 i->kyc_info = NULL; 927 } 928 /* Could not start the lookup: keep the early acceptance and retry 929 with a regular periodic check. */ 930 GNUNET_free (i->tos_etag); 931 finish_inquiry (i); 932 } 933 } 934 935 936 /** 937 * The exchange asked us (via @a tos_required) to accept its terms of 938 * service. Check whether the user already accepted the terms of 939 * service early (via ``POST /private/accept-tos-early``). If so, 940 * remember the accepted version in @a i->tos_etag so that we will try 941 * to submit it to the exchange automatically. 942 * 943 * @param[in,out] i inquiry for which the exchange requires ToS acceptance 944 * @param req required ETag for the accepted ToS 945 */ 946 static void 947 check_early_tos_acceptance (struct Inquiry *i, 948 const char *req) 949 { 950 enum GNUNET_DB_QueryStatus qs; 951 char *tos_version = NULL; 952 953 qs = TALER_MERCHANTDB_set_instance (pg, 954 i->a->instance_id); 955 if (qs < 0) 956 { 957 GNUNET_break (0); 958 global_ret = EXIT_FAILURE; 959 GNUNET_SCHEDULER_shutdown (); 960 return; 961 } 962 if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs) 963 { 964 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 965 "Instance `%s' vanished, skipping ToS check\n", 966 i->a->instance_id); 967 return; 968 } 969 qs = TALER_MERCHANTDB_get_tos_accepted_early (pg, 970 i->a->instance_id, 971 i->e->keys->exchange_url, 972 &tos_version); 973 GNUNET_break (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT == 974 TALER_MERCHANTDB_set_instance (pg, 975 NULL)); 976 if (qs < 0) 977 { 978 GNUNET_break (0); 979 global_ret = EXIT_FAILURE; 980 GNUNET_SCHEDULER_shutdown (); 981 return; 982 } 983 if (NULL == tos_version) 984 { 985 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 986 "Exchange `%s' supports early ToS acceptance, but user did not accept ToS early\n", 987 i->e->keys->exchange_url); 988 return; 989 } 990 if (0 != strcmp (tos_version, 991 req)) 992 { 993 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 994 "User accepted outdated ToS version `%s' early, but exchange wants `%s'. User will need to accept the ToS again!\n", 995 tos_version, 996 req); 997 GNUNET_free (tos_version); 998 return; 999 } 1000 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 1001 "User accepted ToS version `%s' early; will submit to `%s'\n", 1002 tos_version, 1003 i->e->keys->exchange_url); 1004 GNUNET_free (i->tos_etag); 1005 i->tos_etag = tos_version; 1006 } 1007 1008 1009 /** 1010 * Function called with the result of a KYC check. 1011 * 1012 * @param cls a `struct Inquiry *` 1013 * @param ks the account's KYC status details 1014 */ 1015 static void 1016 exchange_check_cb ( 1017 struct Inquiry *i, 1018 const struct TALER_EXCHANGE_GetKycCheckResponse *ks) 1019 { 1020 bool progress = false; 1021 1022 i->kyc = NULL; 1023 if (! i->not_first_time) 1024 progress = true; 1025 if ( (i->last_http_status != ks->hr.http_status) && 1026 (0 != ks->hr.http_status) ) 1027 progress = true; 1028 if (0 != ks->hr.http_status) 1029 { 1030 i->last_http_status = ks->hr.http_status; 1031 i->last_ec = ks->hr.ec; 1032 } 1033 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 1034 "KYC status of `%s' / %s at `%s' is %u\n", 1035 i->a->merchant_account_uri.full_payto, 1036 i->a->instance_id, 1037 i->e->keys->exchange_url, 1038 ks->hr.http_status); 1039 switch (ks->hr.http_status) 1040 { 1041 case 0: 1042 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 1043 "Exchange did not responded to /kyc-check request!\n"); 1044 i->backoff 1045 = GNUNET_TIME_randomized_backoff (i->backoff, 1046 EXCHANGE_TIMEOUT); 1047 i->due = GNUNET_TIME_relative_to_absolute (i->backoff); 1048 break; 1049 case MHD_HTTP_OK: 1050 if (i->rule_gen != ks->details.ok.rule_gen) 1051 progress = true; 1052 i->rule_gen = ks->details.ok.rule_gen; 1053 i->last_kyc_check = GNUNET_TIME_timestamp_get (); 1054 /* exchange says KYC is OK, gives status information */ 1055 i->auth_ok = true; 1056 store_kyc_status (i, 1057 &ks->details.ok); 1058 i->backoff = GNUNET_TIME_UNIT_MINUTES; 1059 if (i->aml_review || i->zero_limited) 1060 { 1061 if (! progress) 1062 i->due = GNUNET_TIME_relative_to_absolute ( 1063 GNUNET_TIME_randomize (GNUNET_TIME_relative_max (aml_freq, 1064 i->backoff))); 1065 } 1066 else 1067 { 1068 /* KYC is OK, only check again if triggered */ 1069 if (! progress) 1070 i->due = GNUNET_TIME_relative_to_absolute ( 1071 GNUNET_TIME_randomize (GNUNET_TIME_relative_max (aml_low_freq, 1072 i->backoff))); 1073 } 1074 break; 1075 case MHD_HTTP_ACCEPTED: 1076 if (i->rule_gen != ks->details.accepted.rule_gen) 1077 progress = true; 1078 i->rule_gen = ks->details.accepted.rule_gen; 1079 i->last_kyc_check = GNUNET_TIME_timestamp_get (); 1080 /* exchange says KYC is required */ 1081 i->auth_ok = true; 1082 store_kyc_status (i, 1083 &ks->details.accepted); 1084 i->backoff = GNUNET_TIME_UNIT_MINUTES; 1085 /* Start immediately with long-polling */ 1086 if (! progress) 1087 i->due = GNUNET_TIME_absolute_max (i->last_kyc_check.abs_time, 1088 i->timeout); 1089 if (NULL != ks->details.accepted.tos_required) 1090 { 1091 /* Exchange wants the user to accept its terms of service. 1092 If the user already accepted them early, try to submit that 1093 acceptance to the exchange automatically. */ 1094 check_early_tos_acceptance (i, 1095 ks->details.accepted.tos_required); 1096 } 1097 break; 1098 case MHD_HTTP_NO_CONTENT: 1099 i->rule_gen = 0; 1100 i->last_kyc_check = GNUNET_TIME_timestamp_get (); 1101 i->backoff = GNUNET_TIME_UNIT_MINUTES; 1102 /* exchange claims KYC is off! */ 1103 i->kyc_ok = true; 1104 i->aml_review = false; 1105 /* Clear limits, in case exchange had KYC on previously */ 1106 json_decref (i->jlimits); 1107 i->jlimits = NULL; 1108 /* KYC is OK, only check again if triggered */ 1109 i->due = GNUNET_TIME_relative_to_absolute ( 1110 GNUNET_TIME_randomize (GNUNET_TIME_relative_max (aml_low_freq, 1111 i->backoff))); 1112 break; 1113 case MHD_HTTP_FORBIDDEN: /* bad signature */ 1114 i->rule_gen = 0; 1115 i->last_kyc_check = GNUNET_TIME_timestamp_get (); 1116 /* Forbidden => KYC auth must be wrong */ 1117 i->auth_ok = false; 1118 /* Start with long-polling */ 1119 if (! progress) 1120 i->due = GNUNET_TIME_absolute_max (i->last_kyc_check.abs_time, 1121 i->timeout); 1122 i->backoff = GNUNET_TIME_UNIT_MINUTES; 1123 break; 1124 case MHD_HTTP_NOT_FOUND: /* account unknown */ 1125 i->rule_gen = 0; 1126 i->last_kyc_check = GNUNET_TIME_timestamp_get (); 1127 /* Account unknown => no KYC auth yet */ 1128 i->auth_ok = false; 1129 /* unknown account => wire transfer required! */ 1130 i->kyc_ok = false; 1131 /* There should not be any limits yet, but clear them 1132 just in case the exchange has amnesia */ 1133 json_decref (i->jlimits); 1134 i->jlimits = NULL; 1135 /* Start immediately with Long-polling */ 1136 if (! progress) 1137 i->due = GNUNET_TIME_absolute_max (i->last_kyc_check.abs_time, 1138 i->timeout); 1139 i->backoff = GNUNET_TIME_UNIT_MINUTES; 1140 break; 1141 case MHD_HTTP_CONFLICT: /* no account_pub known */ 1142 i->rule_gen = 0; 1143 i->last_kyc_check = GNUNET_TIME_timestamp_get (); 1144 /* Conflict => KYC auth wire transfer missing! */ 1145 i->auth_ok = false; 1146 /* Start immediately with Long-polling */ 1147 if (! progress) 1148 i->due = GNUNET_TIME_absolute_max (i->last_kyc_check.abs_time, 1149 i->timeout); 1150 i->backoff = GNUNET_TIME_UNIT_MINUTES; 1151 break; 1152 default: 1153 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 1154 "Exchange responded with HTTP status %u (%d) to /kyc-check request!\n", 1155 ks->hr.http_status, 1156 ks->hr.ec); 1157 i->backoff 1158 = GNUNET_TIME_randomized_backoff (i->backoff, 1159 EXCHANGE_TIMEOUT); 1160 i->last_kyc_check = GNUNET_TIME_timestamp_get (); 1161 i->due = GNUNET_TIME_relative_to_absolute (i->backoff); 1162 i->auth_ok = false; 1163 break; 1164 } 1165 1166 { 1167 enum GNUNET_DB_QueryStatus qs; 1168 1169 qs = TALER_MERCHANTDB_set_instance (pg, 1170 i->a->instance_id); 1171 if (qs < 0) 1172 { 1173 GNUNET_break (0); 1174 global_ret = EXIT_FAILURE; 1175 GNUNET_SCHEDULER_shutdown (); 1176 return; 1177 } 1178 if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs) 1179 { 1180 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 1181 "Instance `%s' vanished, discarding KYC status\n", 1182 i->a->instance_id); 1183 finish_inquiry (i); 1184 return; 1185 } 1186 qs = TALER_MERCHANTDB_insert_kyc_status ( 1187 pg, 1188 i->a->instance_id, 1189 &i->a->h_wire, 1190 i->e->keys->exchange_url, 1191 i->last_kyc_check, 1192 i->due, 1193 i->backoff, 1194 i->last_http_status, 1195 i->last_ec, 1196 i->rule_gen, 1197 (i->auth_ok) 1198 ? &i->access_token 1199 : NULL, 1200 i->jlimits, 1201 i->aml_review, 1202 i->kyc_ok); 1203 GNUNET_break (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT == 1204 TALER_MERCHANTDB_set_instance ( 1205 pg, 1206 NULL)); 1207 if (qs < 0) 1208 { 1209 GNUNET_break (0); 1210 global_ret = EXIT_FAILURE; 1211 GNUNET_SCHEDULER_shutdown (); 1212 return; 1213 } 1214 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 1215 "insert_kyc_status (%s, %s, %u, %s, %s) returned %d\n", 1216 i->a->instance_id, 1217 i->e->keys->exchange_url, 1218 i->last_http_status, 1219 i->auth_ok ? "auth OK" : "auth needed", 1220 NULL == i->jlimits ? "default limits" : "custom limits", 1221 (int) qs); 1222 i->not_first_time = true; 1223 } 1224 if (NULL != i->tos_etag) 1225 { 1226 /* The user accepted the terms of service early and the exchange now 1227 requires acceptance: try to submit it automatically (this keeps 1228 the active-inquiry slot) instead of waiting for the next check. */ 1229 start_tos_info (i); 1230 return; 1231 } 1232 finish_inquiry (i); 1233 } 1234 1235 1236 static void 1237 inquiry_work (void *cls) 1238 { 1239 struct Inquiry *i = cls; 1240 enum TALER_EXCHANGE_KycLongPollTarget lpt; 1241 1242 i->task = NULL; 1243 if (! GNUNET_TIME_absolute_is_past (i->due)) 1244 { 1245 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 1246 "Will start inquiry on %s for %s in %s\n", 1247 i->a->merchant_account_uri.full_payto, 1248 i->e->keys->exchange_url, 1249 GNUNET_TIME_relative2s ( 1250 GNUNET_TIME_absolute_get_remaining (i->due), 1251 true)); 1252 i->task 1253 = GNUNET_SCHEDULER_add_at (i->due, 1254 &inquiry_work, 1255 i); 1256 goto finish; 1257 } 1258 1259 GNUNET_assert (OPEN_INQUIRY_LIMIT >= active_inquiries); 1260 if (OPEN_INQUIRY_LIMIT <= active_inquiries) 1261 { 1262 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 1263 "Not looking for work: at limit\n"); 1264 i->limited = true; 1265 at_limit = true; 1266 return; 1267 } 1268 at_limit = false; 1269 i->timeout 1270 = GNUNET_TIME_relative_to_absolute (EXCHANGE_TIMEOUT); 1271 lpt = TALER_EXCHANGE_KLPT_NONE; 1272 if (! i->auth_ok) 1273 lpt = TALER_EXCHANGE_KLPT_KYC_AUTH_TRANSFER; 1274 else if (! i->kyc_ok) 1275 lpt = TALER_EXCHANGE_KLPT_KYC_OK; 1276 else if (i->aml_review) 1277 lpt = TALER_EXCHANGE_KLPT_INVESTIGATION_DONE; 1278 if (! i->not_first_time) 1279 lpt = TALER_EXCHANGE_KLPT_NONE; /* no long polling on 1st call */ 1280 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 1281 "Starting KYC status of `%s' for %s at `%s' (%d, %d, %d) using LPT %d\n", 1282 i->a->merchant_account_uri.full_payto, 1283 i->a->instance_id, 1284 i->e->keys->exchange_url, 1285 i->not_first_time, 1286 i->auth_ok, 1287 i->kyc_ok, 1288 lpt); 1289 i->kyc = TALER_EXCHANGE_get_kyc_check_create ( 1290 ctx, 1291 i->e->keys->exchange_url, 1292 &i->a->h_payto, 1293 &i->a->ap); 1294 if (NULL == i->kyc) 1295 { 1296 GNUNET_break (0); 1297 i->due = i->timeout; 1298 i->task 1299 = GNUNET_SCHEDULER_add_at (i->due, 1300 &inquiry_work, 1301 i); 1302 goto finish; 1303 } 1304 GNUNET_assert (GNUNET_OK == 1305 TALER_EXCHANGE_get_kyc_check_set_options ( 1306 i->kyc, 1307 TALER_EXCHANGE_get_kyc_check_option_known_rule_gen ( 1308 i->rule_gen), 1309 TALER_EXCHANGE_get_kyc_check_option_lpt (lpt), 1310 TALER_EXCHANGE_get_kyc_check_option_timeout ( 1311 i->not_first_time && (! test_mode) 1312 ? EXCHANGE_TIMEOUT 1313 : GNUNET_TIME_UNIT_ZERO))); 1314 GNUNET_assert (TALER_EC_NONE == 1315 TALER_EXCHANGE_get_kyc_check_start (i->kyc, 1316 &exchange_check_cb, 1317 i)); 1318 active_inquiries++; 1319 finish: 1320 if ( (0 == active_inquiries) && 1321 (test_mode) ) 1322 { 1323 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 1324 "No more open inquiries and in test mode. Existing.\n"); 1325 GNUNET_SCHEDULER_shutdown (); 1326 return; 1327 } 1328 } 1329 1330 1331 /** 1332 * Check if the account @a could work with exchange that 1333 * has keys @a keys. 1334 * 1335 * @param keys the keys of an exchange 1336 * @param a an account 1337 */ 1338 static bool 1339 is_eligible (const struct TALER_EXCHANGE_Keys *keys, 1340 const struct Account *a) 1341 { 1342 struct TALER_NormalizedPayto np; 1343 bool ret; 1344 1345 np = TALER_payto_normalize (a->merchant_account_uri); 1346 ret = TALER_EXCHANGE_keys_test_account_allowed (keys, 1347 true, 1348 np); 1349 GNUNET_free (np.normalized_payto); 1350 return ret; 1351 } 1352 1353 1354 /** 1355 * Start the KYC checking for account @a at exchange @a e. 1356 * 1357 * @param e an exchange 1358 * @param a an account 1359 */ 1360 static void 1361 start_inquiry (struct Exchange *e, 1362 struct Account *a) 1363 { 1364 struct Inquiry *i; 1365 enum GNUNET_DB_QueryStatus qs; 1366 1367 i = GNUNET_new (struct Inquiry); 1368 i->e = e; 1369 i->a = a; 1370 inquiry_key (a->instance_id, 1371 &a->h_wire, 1372 e->keys->exchange_url, 1373 &i->key); 1374 GNUNET_assert (GNUNET_OK == 1375 GNUNET_CONTAINER_multihashmap_put ( 1376 inquiry_map, 1377 &i->key, 1378 i, 1379 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)); 1380 GNUNET_CONTAINER_DLL_insert (a->i_head, 1381 a->i_tail, 1382 i); 1383 qs = TALER_MERCHANTDB_set_instance (pg, 1384 a->instance_id); 1385 if (qs < 0) 1386 { 1387 GNUNET_break (0); 1388 global_ret = EXIT_FAILURE; 1389 GNUNET_SCHEDULER_shutdown (); 1390 return; 1391 } 1392 if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs) 1393 { 1394 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 1395 "Instance `%s' vanished, not starting inquiry\n", 1396 a->instance_id); 1397 return; 1398 } 1399 qs = TALER_MERCHANTDB_get_kyc_status (pg, 1400 a->merchant_account_uri, 1401 a->instance_id, 1402 e->keys->exchange_url, 1403 &i->auth_ok, 1404 &i->access_token, 1405 &i->kyc_ok, 1406 &i->last_http_status, 1407 &i->last_ec, 1408 &i->rule_gen, 1409 &i->last_kyc_check, 1410 &i->due, 1411 &i->backoff, 1412 &i->aml_review, 1413 &i->jlimits); 1414 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 1415 "iterate_kyc_statuses (%s, %s, %s) returned %d (%u, #%llu)\n", 1416 i->a->instance_id, 1417 e->keys->exchange_url, 1418 a->merchant_account_uri.full_payto, 1419 (int) qs, 1420 i->last_http_status, 1421 (unsigned long long) i->rule_gen); 1422 if (qs < 0) 1423 { 1424 GNUNET_break (0); 1425 global_ret = EXIT_FAILURE; 1426 GNUNET_SCHEDULER_shutdown (); 1427 return; 1428 } 1429 if (qs > 0) 1430 i->not_first_time = true; 1431 if (TALER_EC_MERCHANT_PRIVATE_ACCOUNT_NOT_ELIGIBLE_FOR_EXCHANGE == i->last_ec) 1432 { 1433 /* Eligibility was restored. Do not retain the ineligible status's 1434 infinite delay or backoff. */ 1435 i->due = GNUNET_TIME_UNIT_ZERO_ABS; 1436 i->backoff = GNUNET_TIME_UNIT_ZERO; 1437 i->not_first_time = false; 1438 } 1439 if (GNUNET_YES == test_mode) 1440 i->due = GNUNET_TIME_UNIT_ZERO_ABS; /* immediately */ 1441 inquiry_work (i); 1442 } 1443 1444 1445 /** 1446 * Stop KYC inquiry @a i. 1447 * 1448 * @param[in] i the inquiry to stop 1449 */ 1450 static void 1451 stop_inquiry (struct Inquiry *i) 1452 { 1453 struct Account *a = i->a; 1454 1455 GNUNET_assert (GNUNET_YES == 1456 GNUNET_CONTAINER_multihashmap_remove (inquiry_map, 1457 &i->key, 1458 i)); 1459 GNUNET_CONTAINER_DLL_remove (a->i_head, 1460 a->i_tail, 1461 i); 1462 if (NULL != i->task) 1463 { 1464 GNUNET_SCHEDULER_cancel (i->task); 1465 i->task = NULL; 1466 } 1467 if (NULL != i->kyc) 1468 { 1469 TALER_EXCHANGE_get_kyc_check_cancel (i->kyc); 1470 i->kyc = NULL; 1471 } 1472 if (NULL != i->kyc_info) 1473 { 1474 TALER_EXCHANGE_get_kyc_info_cancel (i->kyc_info); 1475 i->kyc_info = NULL; 1476 } 1477 if (NULL != i->tos_upload) 1478 { 1479 TALER_EXCHANGE_post_kyc_upload_cancel (i->tos_upload); 1480 i->tos_upload = NULL; 1481 } 1482 GNUNET_free (i->tos_etag); 1483 if (NULL != i->jlimits) 1484 { 1485 json_decref (i->jlimits); 1486 i->jlimits = NULL; 1487 } 1488 GNUNET_free (i); 1489 } 1490 1491 1492 /** 1493 * Stop KYC inquiry for account @a at exchange @a e. 1494 * 1495 * @param e an exchange 1496 * @param a an account 1497 */ 1498 static void 1499 stop_inquiry_at (struct Exchange *e, 1500 struct Account *a) 1501 { 1502 for (struct Inquiry *i = a->i_head; 1503 NULL != i; 1504 i = i->next) 1505 { 1506 if (e == i->e) 1507 { 1508 stop_inquiry (i); 1509 return; 1510 } 1511 } 1512 /* strange, there should have been a match! */ 1513 GNUNET_break (0); 1514 } 1515 1516 1517 /** 1518 * Set the account @a h_wire of @a instance_id to be ineligible 1519 * for the exchange at @a exchange_url and thus no need to do KYC checks. 1520 * 1521 * @param instance_id instance that has the account 1522 * @param exchange_url base URL of the exchange 1523 * @param h_wire hash of the merchant bank account that is ineligible 1524 */ 1525 static void 1526 flag_ineligible (const char *instance_id, 1527 const char *exchange_url, 1528 const struct TALER_MerchantWireHashP *h_wire) 1529 { 1530 enum GNUNET_DB_QueryStatus qs; 1531 1532 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 1533 "Account %s not eligible at exchange %s\n", 1534 TALER_B2S (h_wire), 1535 exchange_url); 1536 qs = TALER_MERCHANTDB_set_instance (pg, 1537 instance_id); 1538 if (qs < 0) 1539 { 1540 GNUNET_break (0); 1541 global_ret = EXIT_FAILURE; 1542 GNUNET_SCHEDULER_shutdown (); 1543 return; 1544 } 1545 if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs) 1546 { 1547 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 1548 "Instance `%s' vanished, not flagging account\n", 1549 instance_id); 1550 return; 1551 } 1552 qs = TALER_MERCHANTDB_insert_kyc_status ( 1553 pg, 1554 instance_id, 1555 h_wire, 1556 exchange_url, 1557 GNUNET_TIME_timestamp_get (), 1558 GNUNET_TIME_UNIT_FOREVER_ABS, 1559 GNUNET_TIME_UNIT_FOREVER_REL, 1560 0, 1561 TALER_EC_MERCHANT_PRIVATE_ACCOUNT_NOT_ELIGIBLE_FOR_EXCHANGE, 1562 0, 1563 NULL, 1564 NULL, 1565 false, 1566 false); 1567 GNUNET_break (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT == 1568 TALER_MERCHANTDB_set_instance ( 1569 pg, 1570 NULL)); 1571 if (qs < 0) 1572 { 1573 GNUNET_break (0); 1574 global_ret = EXIT_FAILURE; 1575 GNUNET_SCHEDULER_shutdown (); 1576 return; 1577 } 1578 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 1579 "insert_kyc_status (%s) returned %d\n", 1580 exchange_url, 1581 (int) qs); 1582 } 1583 1584 1585 /** 1586 * Start inquries for all exchanges on account @a a. 1587 * 1588 * @param a an account 1589 */ 1590 static void 1591 start_inquiries (struct Account *a) 1592 { 1593 for (struct Exchange *e = e_head; 1594 NULL != e; 1595 e = e->next) 1596 { 1597 if (is_eligible (e->keys, 1598 a)) 1599 { 1600 start_inquiry (e, 1601 a); 1602 } 1603 else 1604 { 1605 flag_ineligible (a->instance_id, 1606 e->keys->exchange_url, 1607 &a->h_wire); 1608 } 1609 } 1610 } 1611 1612 1613 /** 1614 * Stop all inquries involving account @a a. 1615 * 1616 * @param a an account 1617 */ 1618 static void 1619 stop_inquiries (struct Account *a) 1620 { 1621 struct Inquiry *i; 1622 1623 while (NULL != (i = a->i_head)) 1624 stop_inquiry (i); 1625 } 1626 1627 1628 /** 1629 * Callback invoked with information about a bank account. 1630 * 1631 * @param cls closure 1632 * @param merchant_priv private key of the merchant instance 1633 * @param ad details about the account 1634 */ 1635 static void 1636 account_cb ( 1637 void *cls, 1638 const struct TALER_MerchantPrivateKeyP *merchant_priv, 1639 const struct TALER_MERCHANTDB_AccountDetails *ad) 1640 { 1641 struct TALER_FullPayto payto_uri = ad->payto_uri; 1642 1643 if (! ad->active) 1644 return; 1645 if (NULL == merchant_priv) 1646 return; /* instance was deleted */ 1647 for (struct Account *a = a_head; 1648 NULL != a; 1649 a = a->next) 1650 { 1651 if ( (0 == 1652 TALER_full_payto_cmp (payto_uri, 1653 a->merchant_account_uri)) && 1654 (0 == 1655 GNUNET_memcmp (&a->h_wire, 1656 &ad->h_wire)) && 1657 (0 == 1658 strcmp (ad->instance_id, 1659 a->instance_id)) ) 1660 { 1661 a->account_gen = database_gen; 1662 return; 1663 } 1664 } 1665 { 1666 struct Account *a = GNUNET_new (struct Account); 1667 1668 a->account_gen = database_gen; 1669 a->merchant_account_uri.full_payto 1670 = GNUNET_strdup (ad->payto_uri.full_payto); 1671 a->instance_id 1672 = GNUNET_strdup (ad->instance_id); 1673 a->h_wire 1674 = ad->h_wire; 1675 a->ap.merchant_priv 1676 = *merchant_priv; 1677 TALER_full_payto_normalize_and_hash (a->merchant_account_uri, 1678 &a->h_payto); 1679 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 1680 "Found account %s of instance %s with H_PAYTO %s\n", 1681 ad->payto_uri.full_payto, 1682 ad->instance_id, 1683 GNUNET_sh2s (&a->h_payto.hash)); 1684 GNUNET_CONTAINER_DLL_insert (a_head, 1685 a_tail, 1686 a); 1687 start_inquiries (a); 1688 } 1689 } 1690 1691 1692 /** 1693 * The set of bank accounts has changed, update our 1694 * list of active inquiries. 1695 * 1696 * @param cls unused 1697 */ 1698 static void 1699 find_accounts (void *cls) 1700 { 1701 enum GNUNET_DB_QueryStatus qs; 1702 1703 (void) cls; 1704 account_task = NULL; 1705 database_gen++; 1706 qs = TALER_MERCHANTDB_iterate_accounts (pg, 1707 &account_cb, 1708 NULL); 1709 if (qs < 0) 1710 { 1711 GNUNET_break (0); 1712 global_ret = EXIT_FAILURE; 1713 GNUNET_SCHEDULER_shutdown (); 1714 return; 1715 } 1716 for (struct Account *a = a_head; 1717 NULL != a; 1718 a = a->next) 1719 { 1720 if (a->account_gen < database_gen) 1721 stop_inquiries (a); 1722 } 1723 if ( (! at_limit) && 1724 (0 == active_inquiries) && 1725 (test_mode) ) 1726 { 1727 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 1728 "No more open inquiries and in test mode. Existing.\n"); 1729 GNUNET_SCHEDULER_shutdown (); 1730 return; 1731 } 1732 } 1733 1734 1735 /** 1736 * Function called when transfers are added to the merchant database. We look 1737 * for more work. 1738 * 1739 * @param cls closure (NULL) 1740 * @param extra additional event data provided 1741 * @param extra_size number of bytes in @a extra 1742 */ 1743 static void 1744 account_changed (void *cls, 1745 const void *extra, 1746 size_t extra_size) 1747 { 1748 (void) cls; 1749 (void) extra; 1750 (void) extra_size; 1751 if (NULL != account_task) 1752 return; 1753 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 1754 "Received account change notification: reloading accounts\n"); 1755 account_task 1756 = GNUNET_SCHEDULER_add_now (&find_accounts, 1757 NULL); 1758 } 1759 1760 1761 /** 1762 * Interact with the database to get the current set 1763 * of exchange keys known to us. 1764 * 1765 * @param exchange_url the exchange URL to check 1766 */ 1767 static void 1768 find_keys (const char *exchange_url) 1769 { 1770 enum GNUNET_DB_QueryStatus qs; 1771 struct TALER_EXCHANGE_Keys *keys; 1772 struct Exchange *e; 1773 struct GNUNET_TIME_Absolute first_retry; 1774 1775 qs = TALER_MERCHANTDB_get_exchange_keys (pg, 1776 exchange_url, 1777 &first_retry, 1778 &keys); 1779 if (qs < 0) 1780 { 1781 GNUNET_break (0); 1782 global_ret = EXIT_FAILURE; 1783 GNUNET_SCHEDULER_shutdown (); 1784 return; 1785 } 1786 if ( (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs) || 1787 (NULL == keys) ) 1788 { 1789 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 1790 "No %s/keys yet!\n", 1791 exchange_url); 1792 return; 1793 } 1794 for (e = e_head; NULL != e; e = e->next) 1795 { 1796 if (0 == strcmp (e->keys->exchange_url, 1797 keys->exchange_url)) 1798 { 1799 struct TALER_EXCHANGE_Keys *old_keys = e->keys; 1800 1801 e->keys = keys; 1802 for (struct Account *a = a_head; 1803 NULL != a; 1804 a = a->next) 1805 { 1806 bool was_eligible; 1807 bool now_eligible; 1808 1809 if (a->account_gen != database_gen) 1810 continue; 1811 was_eligible = is_eligible (old_keys, 1812 a); 1813 now_eligible = is_eligible (keys, 1814 a); 1815 1816 if (was_eligible == now_eligible) 1817 continue; /* no change, do nothing */ 1818 if (was_eligible) 1819 { 1820 flag_ineligible (a->instance_id, 1821 keys->exchange_url, 1822 &a->h_wire); 1823 stop_inquiry_at (e, 1824 a); 1825 } 1826 else /* is_eligible */ 1827 start_inquiry (e, 1828 a); 1829 } 1830 TALER_EXCHANGE_keys_decref (old_keys); 1831 return; 1832 } 1833 } 1834 e = GNUNET_new (struct Exchange); 1835 e->keys = keys; 1836 GNUNET_CONTAINER_DLL_insert (e_head, 1837 e_tail, 1838 e); 1839 for (struct Account *a = a_head; 1840 NULL != a; 1841 a = a->next) 1842 { 1843 if (a->account_gen != database_gen) 1844 continue; 1845 if (is_eligible (e->keys, 1846 a)) 1847 { 1848 start_inquiry (e, 1849 a); 1850 } 1851 else 1852 { 1853 flag_ineligible (a->instance_id, 1854 e->keys->exchange_url, 1855 &a->h_wire); 1856 } 1857 } 1858 } 1859 1860 1861 /** 1862 * Function called when keys were changed in the 1863 * merchant database. Updates ours. 1864 * 1865 * @param cls closure (NULL) 1866 * @param extra additional event data provided 1867 * @param extra_size number of bytes in @a extra 1868 */ 1869 static void 1870 keys_changed (void *cls, 1871 const void *extra, 1872 size_t extra_size) 1873 { 1874 const char *url = extra; 1875 1876 (void) cls; 1877 if ( (NULL == extra) || 1878 (0 == extra_size) ) 1879 { 1880 GNUNET_break (0); 1881 global_ret = EXIT_FAILURE; 1882 GNUNET_SCHEDULER_shutdown (); 1883 return; 1884 } 1885 if ('\0' != url[extra_size - 1]) 1886 { 1887 GNUNET_break (0); 1888 global_ret = EXIT_FAILURE; 1889 GNUNET_SCHEDULER_shutdown (); 1890 return; 1891 } 1892 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 1893 "Received keys change notification: reload `%s'\n", 1894 url); 1895 find_keys (url); 1896 } 1897 1898 1899 /** 1900 * Function called when a KYC rule was triggered by 1901 * a transaction and we need to get the latest KYC 1902 * status immediately. 1903 * 1904 * @param cls closure (NULL) 1905 * @param extra additional event data provided 1906 * @param extra_size number of bytes in @a extra 1907 */ 1908 static void 1909 rule_triggered (void *cls, 1910 const void *extra, 1911 size_t extra_size) 1912 { 1913 const char *text = extra; 1914 const char *space; 1915 struct TALER_MerchantWireHashP h_wire; 1916 const char *exchange_url; 1917 1918 (void) cls; 1919 if ( (NULL == extra) || 1920 (0 == extra_size) ) 1921 { 1922 GNUNET_break (0); 1923 global_ret = EXIT_FAILURE; 1924 GNUNET_SCHEDULER_shutdown (); 1925 return; 1926 } 1927 if ('\0' != text[extra_size - 1]) 1928 { 1929 GNUNET_break (0); 1930 global_ret = EXIT_FAILURE; 1931 GNUNET_SCHEDULER_shutdown (); 1932 return; 1933 } 1934 space = memchr (extra, 1935 ' ', 1936 extra_size); 1937 if (NULL == space) 1938 { 1939 GNUNET_break (0); 1940 global_ret = EXIT_FAILURE; 1941 GNUNET_SCHEDULER_shutdown (); 1942 return; 1943 } 1944 if (GNUNET_OK != 1945 GNUNET_STRINGS_string_to_data (extra, 1946 space - text, 1947 &h_wire, 1948 sizeof (h_wire))) 1949 { 1950 GNUNET_break (0); 1951 global_ret = EXIT_FAILURE; 1952 GNUNET_SCHEDULER_shutdown (); 1953 return; 1954 } 1955 exchange_url = &space[1]; 1956 if (! TALER_is_web_url (exchange_url)) 1957 { 1958 GNUNET_break (0); 1959 global_ret = EXIT_FAILURE; 1960 GNUNET_SCHEDULER_shutdown (); 1961 return; 1962 } 1963 1964 for (struct Account *a = a_head; 1965 NULL != a; 1966 a = a->next) 1967 { 1968 if (0 != 1969 GNUNET_memcmp (&h_wire, 1970 &a->h_wire)) 1971 continue; 1972 for (struct Inquiry *i = a->i_head; 1973 NULL != i; 1974 i = i->next) 1975 { 1976 if (0 != strcmp (exchange_url, 1977 i->e->keys->exchange_url)) 1978 continue; 1979 i->kyc_ok = false; 1980 if (inquiry_busy (i)) 1981 { 1982 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 1983 "/kyc-check already running for %s\n", 1984 text); 1985 return; 1986 } 1987 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 1988 "Starting %skyc-check for `%s' due to KYC rule trigger\n", 1989 exchange_url, 1990 i->a->merchant_account_uri.full_payto); 1991 request_inquiry (i); 1992 return; 1993 } 1994 } 1995 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 1996 "KYC rule trigger notification `%s' matches none of our accounts\n", 1997 text); 1998 } 1999 2000 2001 /** 2002 * Function called on each configuration section. Finds sections 2003 * about exchanges, parses the entries. 2004 * 2005 * @param cls NULL 2006 * @param section name of the section 2007 */ 2008 static void 2009 accept_exchanges (void *cls, 2010 const char *section) 2011 { 2012 char *url; 2013 2014 (void) cls; 2015 if (0 != 2016 strncasecmp (section, 2017 "merchant-exchange-", 2018 strlen ("merchant-exchange-"))) 2019 return; 2020 if (GNUNET_YES == 2021 GNUNET_CONFIGURATION_get_value_yesno (cfg, 2022 section, 2023 "DISABLED")) 2024 return; 2025 if (GNUNET_OK != 2026 GNUNET_CONFIGURATION_get_value_string (cfg, 2027 section, 2028 "EXCHANGE_BASE_URL", 2029 &url)) 2030 { 2031 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, 2032 section, 2033 "EXCHANGE_BASE_URL"); 2034 global_ret = EXIT_NOTCONFIGURED; 2035 GNUNET_SCHEDULER_shutdown (); 2036 return; 2037 } 2038 find_keys (url); 2039 GNUNET_free (url); 2040 } 2041 2042 2043 /** 2044 * We're being aborted with CTRL-C (or SIGTERM). Shut down. 2045 * 2046 * @param cls closure (NULL) 2047 */ 2048 static void 2049 shutdown_task (void *cls) 2050 { 2051 (void) cls; 2052 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 2053 "Running shutdown\n"); 2054 if (NULL != refresh_task) 2055 { 2056 GNUNET_SCHEDULER_cancel (refresh_task); 2057 refresh_task = NULL; 2058 } 2059 while (NULL != refresh_head) 2060 { 2061 struct Refresh *r = refresh_head; 2062 2063 GNUNET_CONTAINER_DLL_remove (refresh_head, refresh_tail, r); 2064 GNUNET_free (r); 2065 } 2066 GNUNET_CONTAINER_multihashmap_destroy (refresh_map); 2067 while (NULL != e_head) 2068 { 2069 struct Exchange *e = e_head; 2070 2071 if (NULL != e->keys) 2072 { 2073 TALER_EXCHANGE_keys_decref (e->keys); 2074 e->keys = NULL; 2075 } 2076 GNUNET_CONTAINER_DLL_remove (e_head, 2077 e_tail, 2078 e); 2079 GNUNET_free (e); 2080 } 2081 while (NULL != a_head) 2082 { 2083 struct Account *a = a_head; 2084 2085 stop_inquiries (a); 2086 GNUNET_CONTAINER_DLL_remove (a_head, 2087 a_tail, 2088 a); 2089 GNUNET_free (a->merchant_account_uri.full_payto); 2090 GNUNET_free (a->instance_id); 2091 GNUNET_free (a); 2092 } 2093 GNUNET_CONTAINER_multihashmap_destroy (inquiry_map); 2094 if (NULL != eh_accounts) 2095 { 2096 TALER_MERCHANTDB_event_listen_cancel (eh_accounts); 2097 eh_accounts = NULL; 2098 } 2099 if (NULL != account_task) 2100 { 2101 GNUNET_SCHEDULER_cancel (account_task); 2102 account_task = NULL; 2103 } 2104 if (NULL != eh_keys) 2105 { 2106 TALER_MERCHANTDB_event_listen_cancel (eh_keys); 2107 eh_keys = NULL; 2108 } 2109 if (NULL != eh_rule) 2110 { 2111 TALER_MERCHANTDB_event_listen_cancel (eh_rule); 2112 eh_rule = NULL; 2113 } 2114 if (NULL != eh_update_forced) 2115 { 2116 TALER_MERCHANTDB_event_listen_cancel (eh_update_forced); 2117 eh_update_forced = NULL; 2118 } 2119 if (NULL != keys_rule) 2120 { 2121 TALER_MERCHANTDB_event_listen_cancel (keys_rule); 2122 keys_rule = NULL; 2123 } 2124 if (NULL != pg) 2125 { 2126 TALER_MERCHANTDB_disconnect (pg); 2127 pg = NULL; 2128 } 2129 cfg = NULL; 2130 if (NULL != ctx) 2131 { 2132 GNUNET_CURL_fini (ctx); 2133 ctx = NULL; 2134 } 2135 if (NULL != rc) 2136 { 2137 GNUNET_CURL_gnunet_rc_destroy (rc); 2138 rc = NULL; 2139 } 2140 } 2141 2142 2143 /** 2144 * Function called when we urgently need to re-check the KYC status 2145 * of some account. Finds the respective inquiry and re-launches 2146 * the check, unless we are already doing it. 2147 * 2148 * @param cls NULL 2149 * @param instance_id instance for which to force the check 2150 * @param exchange_url base URL of the exchange to check 2151 * @param h_wire hash of the wire account to check KYC status for 2152 */ 2153 static void 2154 force_check_now (void *cls, 2155 const char *instance_id, 2156 const char *exchange_url, 2157 const struct TALER_MerchantWireHashP *h_wire) 2158 { 2159 struct GNUNET_HashCode key; 2160 struct Inquiry *i; 2161 2162 (void) cls; 2163 inquiry_key (instance_id, h_wire, exchange_url, &key); 2164 i = GNUNET_CONTAINER_multihashmap_get (inquiry_map, &key); 2165 if (NULL == i) 2166 { 2167 /* Account discovery and exchange-key loading recover the persisted due 2168 time. Absence from the index does not prove the account ineligible. */ 2169 return; 2170 } 2171 GNUNET_assert (0 == strcmp (instance_id, i->a->instance_id)); 2172 GNUNET_assert (0 == GNUNET_memcmp (h_wire, &i->a->h_wire)); 2173 GNUNET_assert (0 == strcmp (exchange_url, i->e->keys->exchange_url)); 2174 if (i->a->account_gen != database_gen) 2175 return; 2176 request_inquiry (i); 2177 } 2178 2179 2180 /** 2181 * Process one instance per scheduler turn, after pending account discovery. 2182 */ 2183 static void 2184 process_refresh (void *cls) 2185 { 2186 struct Refresh *r = refresh_head; 2187 enum GNUNET_DB_QueryStatus qs; 2188 2189 (void) cls; 2190 refresh_task = NULL; 2191 if (NULL != account_task) 2192 { 2193 refresh_task = GNUNET_SCHEDULER_add_now (&process_refresh, NULL); 2194 return; 2195 } 2196 GNUNET_assert (NULL != r); 2197 GNUNET_CONTAINER_DLL_remove (refresh_head, refresh_tail, r); 2198 GNUNET_assert (GNUNET_YES == 2199 GNUNET_CONTAINER_multihashmap_remove (refresh_map, 2200 &r->key, 2201 r)); 2202 qs = TALER_MERCHANTDB_iterate_outdated_kyc_statuses ( 2203 pg, 2204 r->merchant_serial, 2205 &force_check_now, 2206 NULL); 2207 GNUNET_free (r); 2208 if (qs < 0) 2209 { 2210 GNUNET_break (0); 2211 global_ret = EXIT_FAILURE; 2212 GNUNET_SCHEDULER_shutdown (); 2213 return; 2214 } 2215 if (NULL != refresh_head) 2216 refresh_task = GNUNET_SCHEDULER_add_now (&process_refresh, NULL); 2217 } 2218 2219 2220 /** 2221 * Queue an instance refresh. The notification payload is exactly one 2222 * unsigned 64-bit merchant serial in network byte order. 2223 */ 2224 static void 2225 update_forced (void *cls, 2226 const void *extra, 2227 size_t extra_size) 2228 { 2229 uint64_t serial; 2230 struct GNUNET_HashCode key; 2231 struct Refresh *r; 2232 2233 (void) cls; 2234 if ( (NULL == extra) || (sizeof (serial) != extra_size) ) 2235 { 2236 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 2237 "Ignoring KYC refresh notification with invalid payload size\n"); 2238 return; 2239 } 2240 memcpy (&serial, extra, sizeof (serial)); 2241 GNUNET_CRYPTO_hash (&serial, sizeof (serial), &key); 2242 serial = GNUNET_ntohll (serial); 2243 if ( (0 == serial) || (serial > INT64_MAX) ) 2244 { 2245 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 2246 "Ignoring KYC refresh notification with invalid instance serial\n"); 2247 return; 2248 } 2249 if (GNUNET_CONTAINER_multihashmap_contains (refresh_map, &key)) 2250 return; 2251 r = GNUNET_new (struct Refresh); 2252 r->key = key; 2253 r->merchant_serial = serial; 2254 GNUNET_CONTAINER_DLL_insert_tail (refresh_head, refresh_tail, r); 2255 GNUNET_assert (GNUNET_OK == 2256 GNUNET_CONTAINER_multihashmap_put ( 2257 refresh_map, &r->key, r, 2258 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)); 2259 if (NULL == refresh_task) 2260 refresh_task = GNUNET_SCHEDULER_add_now (&process_refresh, NULL); 2261 } 2262 2263 /** 2264 * First task. 2265 * 2266 * @param cls closure, NULL 2267 * @param args remaining command-line arguments 2268 * @param cfgfile name of the configuration file used (for saving, can be NULL!) 2269 * @param c configuration 2270 */ 2271 static void 2272 run (void *cls, 2273 char *const *args, 2274 const char *cfgfile, 2275 const struct GNUNET_CONFIGURATION_Handle *c) 2276 { 2277 (void) args; 2278 (void) cfgfile; 2279 2280 cfg = c; 2281 inquiry_map = GNUNET_CONTAINER_multihashmap_create (256, GNUNET_YES); 2282 refresh_map = GNUNET_CONTAINER_multihashmap_create (32, GNUNET_YES); 2283 TALER_EXCHANGE_setup (enable_h3 2284 ? TALER_EXCHANGE_GO_ENABLE_HTTP3 2285 : TALER_EXCHANGE_GO_FORCE_HTTP1_1); 2286 if (GNUNET_OK != 2287 GNUNET_CONFIGURATION_get_value_time (cfg, 2288 "merchant-kyccheck", 2289 "AML_FREQ", 2290 &aml_freq)) 2291 { 2292 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_WARNING, 2293 "merchant-kyccheck", 2294 "AML_FREQ"); 2295 /* use default */ 2296 aml_freq = AML_FREQ; 2297 } 2298 if (GNUNET_OK != 2299 GNUNET_CONFIGURATION_get_value_time (cfg, 2300 "merchant-kyccheck", 2301 "AML_LOW_FREQ", 2302 &aml_low_freq)) 2303 { 2304 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_WARNING, 2305 "merchant-kyccheck", 2306 "AML_LOW_FREQ"); 2307 /* use default */ 2308 aml_low_freq = AML_LOW_FREQ; 2309 } 2310 if (GNUNET_TIME_relative_cmp (aml_low_freq, 2311 <, 2312 aml_freq)) 2313 { 2314 aml_low_freq = GNUNET_TIME_relative_multiply (aml_freq, 2315 10); 2316 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 2317 "AML_LOW_FREQ was set to less than AML_FREQ. Using %s instead\n", 2318 GNUNET_TIME_relative2s (aml_low_freq, 2319 true)); 2320 } 2321 GNUNET_SCHEDULER_add_shutdown (&shutdown_task, 2322 NULL); 2323 ctx = GNUNET_CURL_init (&GNUNET_CURL_gnunet_scheduler_reschedule, 2324 &rc); 2325 if (NULL == ctx) 2326 { 2327 GNUNET_break (0); 2328 GNUNET_SCHEDULER_shutdown (); 2329 global_ret = EXIT_FAILURE; 2330 return; 2331 } 2332 rc = GNUNET_CURL_gnunet_rc_create (ctx); 2333 if (NULL == 2334 (pg = TALER_MERCHANTDB_connect (cfg))) 2335 { 2336 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 2337 "Failed to initialize DB subsystem. Consider running taler-merchant-dbconfig.\n"); 2338 GNUNET_SCHEDULER_shutdown (); 2339 global_ret = EXIT_FAILURE; 2340 return; 2341 } 2342 { 2343 struct GNUNET_DB_EventHeaderP es = { 2344 .size = htons (sizeof (es)), 2345 .type = htons (TALER_DBEVENT_MERCHANT_EXCHANGE_KEYS) 2346 }; 2347 2348 eh_keys 2349 = TALER_MERCHANTDB_event_listen (pg, 2350 &es, 2351 GNUNET_TIME_UNIT_FOREVER_REL, 2352 &keys_changed, 2353 NULL); 2354 } 2355 { 2356 struct GNUNET_DB_EventHeaderP es = { 2357 .size = htons (sizeof (es)), 2358 .type = htons (TALER_DBEVENT_MERCHANT_EXCHANGE_KYC_UPDATE_FORCED) 2359 }; 2360 2361 eh_update_forced 2362 = TALER_MERCHANTDB_event_listen (pg, 2363 &es, 2364 GNUNET_TIME_UNIT_FOREVER_REL, 2365 &update_forced, 2366 NULL); 2367 } 2368 { 2369 struct GNUNET_DB_EventHeaderP es = { 2370 .size = htons (sizeof (es)), 2371 .type = htons (TALER_DBEVENT_MERCHANT_EXCHANGE_KYC_RULE_TRIGGERED) 2372 }; 2373 2374 eh_rule 2375 = TALER_MERCHANTDB_event_listen (pg, 2376 &es, 2377 GNUNET_TIME_UNIT_FOREVER_REL, 2378 &rule_triggered, 2379 NULL); 2380 } 2381 GNUNET_CONFIGURATION_iterate_sections (cfg, 2382 &accept_exchanges, 2383 NULL); 2384 { 2385 struct GNUNET_DB_EventHeaderP es = { 2386 .size = htons (sizeof (es)), 2387 .type = htons (TALER_DBEVENT_MERCHANT_ACCOUNTS_CHANGED) 2388 }; 2389 2390 eh_accounts 2391 = TALER_MERCHANTDB_event_listen (pg, 2392 &es, 2393 GNUNET_TIME_UNIT_FOREVER_REL, 2394 &account_changed, 2395 NULL); 2396 } 2397 GNUNET_assert (NULL == account_task); 2398 account_task 2399 = GNUNET_SCHEDULER_add_now (&find_accounts, 2400 NULL); 2401 } 2402 2403 2404 /** 2405 * The main function of taler-merchant-kyccheck 2406 * 2407 * @param argc number of arguments from the command line 2408 * @param argv command line arguments 2409 * @return 0 ok, 1 on error 2410 */ 2411 int 2412 main (int argc, 2413 char *const *argv) 2414 { 2415 struct GNUNET_GETOPT_CommandLineOption options[] = { 2416 GNUNET_GETOPT_option_flag ('3', 2417 "http3", 2418 "enable support for HTTP/2 and HTTP/3", 2419 &enable_h3), 2420 GNUNET_GETOPT_option_timetravel ('T', 2421 "timetravel"), 2422 GNUNET_GETOPT_option_flag ('t', 2423 "test", 2424 "run in test mode and exit when idle", 2425 &test_mode), 2426 GNUNET_GETOPT_option_version (VERSION), 2427 GNUNET_GETOPT_OPTION_END 2428 }; 2429 enum GNUNET_GenericReturnValue ret; 2430 2431 ret = GNUNET_PROGRAM_run ( 2432 TALER_MERCHANT_project_data (), 2433 argc, argv, 2434 "taler-merchant-kyccheck", 2435 gettext_noop ( 2436 "background process that checks the KYC state of our bank accounts at various exchanges"), 2437 options, 2438 &run, NULL); 2439 if (GNUNET_SYSERR == ret) 2440 return EXIT_NOTCONFIGURED; 2441 if (GNUNET_NO == ret) 2442 return EXIT_SUCCESS; 2443 return global_ret; 2444 } 2445 2446 2447 /* end of taler-merchant-kyccheck.c */