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