Line data Source code
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 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 : #include "microhttpd.h"
23 : #include <gnunet/gnunet_util_lib.h>
24 : #include <jansson.h>
25 : #include <pthread.h>
26 : #include <regex.h>
27 : #include <taler/taler_dbevents.h>
28 : #include <taler/taler_json_lib.h>
29 : #include <taler/taler_exchange_service.h>
30 : #include "taler_merchant_util.h"
31 : #include "taler_merchant_bank_lib.h"
32 : #include "taler_merchantdb_lib.h"
33 : #include "taler_merchantdb_plugin.h"
34 :
35 : /**
36 : * Timeout for the exchange interaction. Rather long as we should do
37 : * long-polling and do not want to wake up too often.
38 : */
39 : #define EXCHANGE_TIMEOUT GNUNET_TIME_relative_multiply ( \
40 : GNUNET_TIME_UNIT_MINUTES, \
41 : 30)
42 :
43 : /**
44 : * How long do we wait between requests if all we wait
45 : * for is a change in the AML investigation status?
46 : * Default value.
47 : */
48 : #define AML_FREQ GNUNET_TIME_relative_multiply ( \
49 : GNUNET_TIME_UNIT_HOURS, \
50 : 6)
51 :
52 : /**
53 : * How long do we wait between requests if all we wait
54 : * for is a change in the AML investigation status?
55 : */
56 : static struct GNUNET_TIME_Relative aml_freq;
57 :
58 : /**
59 : * How frequently do we check for updates to our KYC status
60 : * if there is no actual reason to check? Set to a very low
61 : * frequency, just to ensure we eventually notice.
62 : * Default value.
63 : */
64 : #define AML_LOW_FREQ GNUNET_TIME_relative_multiply ( \
65 : GNUNET_TIME_UNIT_DAYS, \
66 : 7)
67 :
68 : /**
69 : * How frequently do we check for updates to our KYC status
70 : * if there is no actual reason to check? Set to a very low
71 : * frequency, just to ensure we eventually notice.
72 : */
73 : static struct GNUNET_TIME_Relative aml_low_freq;
74 :
75 :
76 : /**
77 : * How many inquiries do we process concurrently at most.
78 : */
79 : #define OPEN_INQUIRY_LIMIT 1024
80 :
81 :
82 : /**
83 : * Information about an exchange.
84 : */
85 : struct Exchange
86 : {
87 : /**
88 : * Kept in a DLL.
89 : */
90 : struct Exchange *next;
91 :
92 : /**
93 : * Kept in a DLL.
94 : */
95 : struct Exchange *prev;
96 :
97 : /**
98 : * The keys of this exchange
99 : */
100 : struct TALER_EXCHANGE_Keys *keys;
101 :
102 : };
103 :
104 :
105 : /**
106 : * Information about an Account.
107 : */
108 : struct Account
109 : {
110 : /**
111 : * Kept in a DLL.
112 : */
113 : struct Account *next;
114 :
115 : /**
116 : * Kept in a DLL.
117 : */
118 : struct Account *prev;
119 :
120 : /**
121 : * Head of inquiries for this account.
122 : */
123 : struct Inquiry *i_head;
124 :
125 : /**
126 : * Tail of inquiries for this account.
127 : */
128 : struct Inquiry *i_tail;
129 :
130 : /**
131 : * Merchant instance this account belongs to.
132 : */
133 : char *instance_id;
134 :
135 : /**
136 : * The payto-URI of this account.
137 : */
138 : struct TALER_FullPayto merchant_account_uri;
139 :
140 : /**
141 : * Wire hash of the merchant bank account (with the
142 : * respective salt).
143 : */
144 : struct TALER_MerchantWireHashP h_wire;
145 :
146 : /**
147 : * Private key of the instance.
148 : */
149 : union TALER_AccountPrivateKeyP ap;
150 :
151 : /**
152 : * Hash of the @e merchant_account_uri.
153 : */
154 : struct TALER_NormalizedPaytoHashP h_payto;
155 :
156 : /**
157 : * Database generation when this account
158 : * was last active.
159 : */
160 : uint64_t account_gen;
161 :
162 : };
163 :
164 :
165 : /**
166 : * Information about an inquiry job.
167 : */
168 : struct Inquiry
169 : {
170 : /**
171 : * Kept in a DLL.
172 : */
173 : struct Inquiry *next;
174 :
175 : /**
176 : * Kept in a DLL.
177 : */
178 : struct Inquiry *prev;
179 :
180 : /**
181 : * Main task for this inquiry.
182 : */
183 : struct GNUNET_SCHEDULER_Task *task;
184 :
185 : /**
186 : * Which exchange is this inquiry about.
187 : */
188 : struct Exchange *e;
189 :
190 : /**
191 : * Which account is this inquiry about.
192 : */
193 : struct Account *a;
194 :
195 : /**
196 : * AccountLimits that apply to the account, NULL
197 : * if unknown.
198 : */
199 : json_t *jlimits;
200 :
201 : /**
202 : * Handle for the actual HTTP request to the exchange.
203 : */
204 : struct TALER_EXCHANGE_KycCheckHandle *kyc;
205 :
206 : /**
207 : * Access token for the /kyc-info API.
208 : */
209 : struct TALER_AccountAccessTokenP access_token;
210 :
211 : /**
212 : * Last time we called the /kyc-check endpoint.
213 : */
214 : struct GNUNET_TIME_Timestamp last_kyc_check;
215 :
216 : /**
217 : * When is the next KYC check due?
218 : */
219 : struct GNUNET_TIME_Absolute due;
220 :
221 : /**
222 : * When should the current KYC time out?
223 : */
224 : struct GNUNET_TIME_Absolute timeout;
225 :
226 : /**
227 : * Current exponential backoff.
228 : */
229 : struct GNUNET_TIME_Relative backoff;
230 :
231 : /**
232 : * Rule generation known to the client, 0 for none.
233 : * Corresponds to the decision row in the exchange.
234 : */
235 : uint64_t rule_gen;
236 :
237 : /**
238 : * Last HTTP status returned by the exchange from
239 : * the /kyc-check endpoint.
240 : */
241 : unsigned int last_http_status;
242 :
243 : /**
244 : * Last Taler error code returned by the exchange from
245 : * the /kyc-check endpoint.
246 : */
247 : enum TALER_ErrorCode last_ec;
248 :
249 : /**
250 : * True if this is not our first time we make this request.
251 : */
252 : bool not_first_time;
253 :
254 : /**
255 : * Do soft limits on transactions apply to this merchant for operations
256 : * merchants care about? If so, we should increase our request frequency
257 : * and ask more often to see if they were lifted.
258 : */
259 : bool zero_limited;
260 :
261 : /**
262 : * Did we not run this inquiry due to limits?
263 : */
264 : bool limited;
265 :
266 : /**
267 : * Do we believe this account's KYC is in good shape?
268 : */
269 : bool kyc_ok;
270 :
271 : /**
272 : * True if merchant did perform this account's KYC AUTH transfer and @e access_token is set.
273 : */
274 : bool auth_ok;
275 :
276 : /**
277 : * True if the account is known to be currently under
278 : * investigation by AML staff.
279 : */
280 : bool aml_review;
281 :
282 : };
283 :
284 :
285 : /**
286 : * Head of known exchanges.
287 : */
288 : static struct Exchange *e_head;
289 :
290 : /**
291 : * Tail of known exchanges.
292 : */
293 : static struct Exchange *e_tail;
294 :
295 : /**
296 : * Head of accounts.
297 : */
298 : static struct Account *a_head;
299 :
300 : /**
301 : * Tail of accounts.
302 : */
303 : static struct Account *a_tail;
304 :
305 : /**
306 : * The merchant's configuration.
307 : */
308 : static const struct GNUNET_CONFIGURATION_Handle *cfg;
309 :
310 : /**
311 : * Our database plugin.
312 : */
313 : static struct TALER_MERCHANTDB_Plugin *db_plugin;
314 :
315 : /**
316 : * Handle to the context for interacting with the bank.
317 : */
318 : static struct GNUNET_CURL_Context *ctx;
319 :
320 : /**
321 : * Scheduler context for running the @e ctx.
322 : */
323 : static struct GNUNET_CURL_RescheduleContext *rc;
324 :
325 : /**
326 : * Event handler to learn that there may be new bank
327 : * accounts to check.
328 : */
329 : static struct GNUNET_DB_EventHandler *eh_accounts;
330 :
331 : /**
332 : * Event handler to learn that there may be new exchange
333 : * keys to check.
334 : */
335 : static struct GNUNET_DB_EventHandler *eh_keys;
336 :
337 : /**
338 : * Event handler to learn that there was a KYC
339 : * rule triggered and we need to check the KYC
340 : * status for an account.
341 : */
342 : static struct GNUNET_DB_EventHandler *eh_rule;
343 :
344 : /**
345 : * Main task to discover (new) accounts.
346 : */
347 : static struct GNUNET_SCHEDULER_Task *account_task;
348 :
349 : /**
350 : * Counter determining how often we have called
351 : * "select_accounts" on the database.
352 : */
353 : static uint64_t database_gen;
354 :
355 : /**
356 : * How many active inquiries do we have right now.
357 : */
358 : static unsigned int active_inquiries;
359 :
360 : /**
361 : * Value to return from main(). 0 on success, non-zero on errors.
362 : */
363 : static int global_ret;
364 :
365 : /**
366 : * #GNUNET_YES if we are in test mode and should exit when idle.
367 : */
368 : static int test_mode;
369 :
370 : /**
371 : * True if the last DB query was limited by the
372 : * #OPEN_INQUIRY_LIMIT and we thus should check again
373 : * as soon as we are substantially below that limit,
374 : * and not only when we get a DB notification.
375 : */
376 : static bool at_limit;
377 :
378 :
379 : /**
380 : * Check about performing a /kyc-check request with the
381 : * exchange for the given inquiry.
382 : *
383 : * @param cls a `struct Inquiry` to process
384 : */
385 : static void
386 : inquiry_work (void *cls);
387 :
388 :
389 : /**
390 : * An inquiry finished, check if we should resume
391 : * others.
392 : */
393 : static void
394 14 : end_inquiry (void)
395 : {
396 14 : GNUNET_assert (active_inquiries > 0);
397 14 : active_inquiries--;
398 14 : if ( (active_inquiries < OPEN_INQUIRY_LIMIT / 2) &&
399 : (at_limit) )
400 : {
401 0 : at_limit = false;
402 0 : for (struct Account *a = a_head;
403 0 : NULL != a;
404 0 : a = a->next)
405 : {
406 0 : for (struct Inquiry *i = a->i_head;
407 0 : NULL != i;
408 0 : i = i->next)
409 : {
410 0 : if (! i->limited)
411 0 : continue;
412 0 : GNUNET_assert (NULL == i->task);
413 : /* done synchronously so that the active_inquiries
414 : is updated immediately */
415 0 : inquiry_work (i);
416 0 : if (at_limit)
417 0 : break;
418 : }
419 0 : if (at_limit)
420 0 : break;
421 : }
422 : }
423 14 : if ( (! at_limit) &&
424 14 : (0 == active_inquiries) &&
425 : (test_mode) )
426 : {
427 0 : GNUNET_log (GNUNET_ERROR_TYPE_INFO,
428 : "No more open inquiries and in test mode. Existing.\n");
429 0 : GNUNET_SCHEDULER_shutdown ();
430 0 : return;
431 : }
432 : }
433 :
434 :
435 : /**
436 : * Pack the given @a limit into the JSON @a limits array.
437 : *
438 : * @param limit account limit to pack
439 : * @param[in,out] limits JSON array to extend
440 : */
441 : static void
442 2 : pack_limit (const struct TALER_EXCHANGE_AccountLimit *limit,
443 : json_t *limits)
444 : {
445 : json_t *jl;
446 :
447 2 : jl = GNUNET_JSON_PACK (
448 : TALER_JSON_pack_kycte ("operation_type",
449 : limit->operation_type),
450 : GNUNET_JSON_pack_time_rel ("timeframe",
451 : limit->timeframe),
452 : TALER_JSON_pack_amount ("threshold",
453 : &limit->threshold),
454 : GNUNET_JSON_pack_bool ("soft_limit",
455 : limit->soft_limit)
456 : );
457 2 : GNUNET_assert (0 ==
458 : json_array_append_new (limits,
459 : jl));
460 2 : }
461 :
462 :
463 : /**
464 : * Update KYC status for @a i based on
465 : * @a account_kyc_status
466 : *
467 : * @param[in,out] i inquiry context, jlimits is updated
468 : * @param account_kyc_status account KYC status details
469 : */
470 : static void
471 2 : store_kyc_status (
472 : struct Inquiry *i,
473 : const struct TALER_EXCHANGE_AccountKycStatus *account_kyc_status)
474 : {
475 : json_t *jlimits;
476 :
477 2 : json_decref (i->jlimits);
478 2 : jlimits = json_array ();
479 2 : GNUNET_assert (NULL != jlimits);
480 2 : i->zero_limited = false;
481 4 : for (unsigned int j = 0; j<account_kyc_status->limits_length; j++)
482 : {
483 2 : const struct TALER_EXCHANGE_AccountLimit *limit
484 2 : = &account_kyc_status->limits[j];
485 :
486 2 : pack_limit (limit,
487 : jlimits);
488 2 : if (TALER_amount_is_zero (&limit->threshold) &&
489 2 : limit->soft_limit &&
490 2 : ( (TALER_KYCLOGIC_KYC_TRIGGER_DEPOSIT == limit->operation_type) ||
491 2 : (TALER_KYCLOGIC_KYC_TRIGGER_AGGREGATE == limit->operation_type) ||
492 0 : (TALER_KYCLOGIC_KYC_TRIGGER_TRANSACTION == limit->operation_type) ) )
493 : {
494 2 : i->zero_limited = true;
495 : }
496 : }
497 2 : i->jlimits = jlimits;
498 2 : GNUNET_break (! GNUNET_is_zero (&account_kyc_status->access_token));
499 2 : i->access_token = account_kyc_status->access_token;
500 2 : i->auth_ok = true;
501 2 : i->aml_review = account_kyc_status->aml_review;
502 2 : i->kyc_ok = (MHD_HTTP_OK == i->last_http_status);
503 2 : }
504 :
505 :
506 : /**
507 : * Function called with the result of a KYC check.
508 : *
509 : * @param cls a `struct Inquiry *`
510 : * @param ks the account's KYC status details
511 : */
512 : static void
513 14 : exchange_check_cb (
514 : void *cls,
515 : const struct TALER_EXCHANGE_KycStatus *ks)
516 : {
517 14 : struct Inquiry *i = cls;
518 14 : bool progress = false;
519 :
520 14 : if (! i->not_first_time)
521 12 : progress = true;
522 14 : i->kyc = NULL;
523 14 : i->last_http_status = ks->hr.http_status;
524 14 : i->last_ec = ks->hr.ec;
525 14 : i->rule_gen = 0;
526 14 : GNUNET_log (GNUNET_ERROR_TYPE_INFO,
527 : "Checking KYC status of `%s' at `%s' is %u\n",
528 : i->a->merchant_account_uri.full_payto,
529 : i->e->keys->exchange_url,
530 : ks->hr.http_status);
531 14 : switch (ks->hr.http_status)
532 : {
533 2 : case MHD_HTTP_OK:
534 2 : if (! i->kyc_ok)
535 1 : progress = true;
536 2 : i->rule_gen = ks->details.ok.rule_gen;
537 2 : i->last_kyc_check = GNUNET_TIME_timestamp_get ();
538 : /* exchange says KYC is OK, gives status information */
539 2 : store_kyc_status (i,
540 : &ks->details.ok);
541 2 : i->backoff = GNUNET_TIME_UNIT_ZERO;
542 2 : if (i->aml_review || i->zero_limited)
543 : {
544 2 : if (! progress)
545 1 : i->due = GNUNET_TIME_relative_to_absolute (
546 : GNUNET_TIME_randomize (aml_freq));
547 : }
548 : else
549 : {
550 : /* KYC is OK, only check again if triggered */
551 0 : i->due = GNUNET_TIME_relative_to_absolute (
552 : GNUNET_TIME_randomize (
553 : aml_low_freq));
554 : }
555 2 : break;
556 0 : case MHD_HTTP_ACCEPTED:
557 0 : progress = ! i->auth_ok;
558 0 : i->rule_gen = ks->details.ok.rule_gen;
559 0 : i->last_kyc_check = GNUNET_TIME_timestamp_get ();
560 :
561 : /* exchange says KYC is required */
562 0 : store_kyc_status (i,
563 : &ks->details.accepted);
564 0 : i->backoff = GNUNET_TIME_UNIT_ZERO;
565 : /* Start immediately with long-polling */
566 0 : if (! progress)
567 0 : i->due = GNUNET_TIME_absolute_max (i->last_kyc_check.abs_time,
568 : i->timeout);
569 0 : break;
570 11 : case MHD_HTTP_NO_CONTENT:
571 11 : i->last_kyc_check = GNUNET_TIME_timestamp_get ();
572 11 : i->backoff = GNUNET_TIME_UNIT_ZERO;
573 : /* exchange claims KYC is off! */
574 11 : i->kyc_ok = true;
575 11 : i->aml_review = false;
576 : /* Clear limits, in case exchange had KYC on previously */
577 11 : json_decref (i->jlimits);
578 11 : i->jlimits = NULL;
579 : /* KYC is OK, only check again if triggered */
580 11 : i->due = GNUNET_TIME_relative_to_absolute (
581 : GNUNET_TIME_randomize (aml_low_freq));
582 11 : break;
583 0 : case MHD_HTTP_FORBIDDEN: /* bad signature */
584 0 : i->last_kyc_check = GNUNET_TIME_timestamp_get ();
585 : /* Forbidden => KYC auth must be wrong */
586 0 : i->auth_ok = false;
587 : /* Start with long-polling */
588 0 : if (! progress)
589 0 : i->due = GNUNET_TIME_absolute_max (i->last_kyc_check.abs_time,
590 : i->timeout);
591 0 : i->backoff = GNUNET_TIME_UNIT_ZERO;
592 0 : break;
593 1 : case MHD_HTTP_NOT_FOUND: /* account unknown */
594 1 : i->last_kyc_check = GNUNET_TIME_timestamp_get ();
595 : /* Account unknown => no KYC auth yet */
596 1 : i->auth_ok = false;
597 : /* unknown account => wire transfer required! */
598 1 : i->kyc_ok = false;
599 : /* There should not be any limits yet, but clear them
600 : just in case the exchange has amnesia */
601 1 : json_decref (i->jlimits);
602 1 : i->jlimits = NULL;
603 : /* Start immediately with Long-polling */
604 1 : if (! progress)
605 0 : i->due = GNUNET_TIME_absolute_max (i->last_kyc_check.abs_time,
606 : i->timeout);
607 1 : i->backoff = GNUNET_TIME_UNIT_ZERO;
608 1 : break;
609 0 : case MHD_HTTP_CONFLICT: /* no account_pub known */
610 0 : i->last_kyc_check = GNUNET_TIME_timestamp_get ();
611 : /* Conflict => KYC auth wire transfer missing! */
612 0 : i->auth_ok = false;
613 : /* Start immediately with Long-polling */
614 0 : if (! progress)
615 0 : i->due = GNUNET_TIME_absolute_max (i->last_kyc_check.abs_time,
616 : i->timeout);
617 0 : i->backoff = GNUNET_TIME_UNIT_ZERO;
618 0 : break;
619 0 : default:
620 0 : GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
621 : "Exchange responded with HTTP status %u (%d) to /kyc-check request!\n",
622 : ks->hr.http_status,
623 : ks->hr.ec);
624 : i->backoff
625 0 : = GNUNET_TIME_randomized_backoff (i->backoff,
626 : EXCHANGE_TIMEOUT);
627 0 : i->last_kyc_check = GNUNET_TIME_timestamp_get ();
628 0 : i->due = GNUNET_TIME_relative_to_absolute (i->backoff);
629 0 : i->auth_ok = false;
630 0 : break;
631 : }
632 :
633 : {
634 : enum GNUNET_DB_QueryStatus qs;
635 :
636 14 : qs = db_plugin->account_kyc_set_status (
637 14 : db_plugin->cls,
638 14 : i->a->instance_id,
639 14 : &i->a->h_wire,
640 14 : i->e->keys->exchange_url,
641 : i->last_kyc_check,
642 : i->last_http_status,
643 : i->last_ec,
644 : i->rule_gen,
645 14 : (i->auth_ok)
646 : ? &i->access_token
647 : : NULL,
648 14 : i->jlimits,
649 14 : i->aml_review,
650 14 : i->kyc_ok);
651 14 : if (qs < 0)
652 : {
653 0 : GNUNET_break (0);
654 0 : global_ret = EXIT_FAILURE;
655 0 : GNUNET_SCHEDULER_shutdown ();
656 0 : return;
657 : }
658 14 : GNUNET_log (GNUNET_ERROR_TYPE_INFO,
659 : "account_set_kyc_status (%s, %u, %s, %s) returned %d\n",
660 : i->e->keys->exchange_url,
661 : i->last_http_status,
662 : i->auth_ok ? "auth OK" : "auth needed",
663 : NULL == i->jlimits ? "default limits" : "custom limits",
664 : (int) qs);
665 14 : i->not_first_time = true;
666 : }
667 14 : GNUNET_log (GNUNET_ERROR_TYPE_INFO,
668 : "Will repeat inquiry in %s\n",
669 : GNUNET_TIME_relative2s (
670 : GNUNET_TIME_absolute_get_remaining (i->due),
671 : true));
672 14 : if (! GNUNET_TIME_absolute_is_never (i->due))
673 14 : i->task = GNUNET_SCHEDULER_add_at (i->due,
674 : &inquiry_work,
675 : i);
676 14 : end_inquiry ();
677 : }
678 :
679 :
680 : static void
681 14 : inquiry_work (void *cls)
682 : {
683 14 : struct Inquiry *i = cls;
684 : enum TALER_EXCHANGE_KycLongPollTarget lpt;
685 :
686 14 : i->task = NULL;
687 14 : if (! GNUNET_TIME_absolute_is_past (i->due))
688 : {
689 0 : GNUNET_log (GNUNET_ERROR_TYPE_INFO,
690 : "Will start inquiry on %s for %s in %s\n",
691 : i->a->merchant_account_uri.full_payto,
692 : i->e->keys->exchange_url,
693 : GNUNET_TIME_relative2s (
694 : GNUNET_TIME_absolute_get_remaining (i->due),
695 : true));
696 : i->task
697 0 : = GNUNET_SCHEDULER_add_at (i->due,
698 : &inquiry_work,
699 : i);
700 0 : goto finish;
701 : }
702 :
703 14 : GNUNET_assert (OPEN_INQUIRY_LIMIT >= active_inquiries);
704 14 : if (OPEN_INQUIRY_LIMIT <= active_inquiries)
705 : {
706 0 : GNUNET_log (GNUNET_ERROR_TYPE_INFO,
707 : "Not looking for work: at limit\n");
708 0 : i->limited = true;
709 0 : at_limit = true;
710 0 : return;
711 : }
712 14 : at_limit = false;
713 14 : GNUNET_log (GNUNET_ERROR_TYPE_INFO,
714 : "Checking KYC status of `%s' at `%s'\n",
715 : i->a->merchant_account_uri.full_payto,
716 : i->e->keys->exchange_url);
717 : i->timeout
718 14 : = GNUNET_TIME_relative_to_absolute (EXCHANGE_TIMEOUT);
719 14 : lpt = TALER_EXCHANGE_KLPT_NONE;
720 14 : if (! i->auth_ok)
721 13 : lpt = TALER_EXCHANGE_KLPT_KYC_AUTH_TRANSFER;
722 1 : else if (! i->kyc_ok)
723 0 : lpt = TALER_EXCHANGE_KLPT_KYC_OK;
724 1 : else if (i->aml_review)
725 0 : lpt = TALER_EXCHANGE_KLPT_INVESTIGATION_DONE;
726 14 : if (! i->not_first_time)
727 12 : lpt = TALER_EXCHANGE_KLPT_NONE;
728 12 : i->kyc = TALER_EXCHANGE_kyc_check (
729 : ctx,
730 14 : i->e->keys->exchange_url,
731 14 : &i->a->h_payto,
732 14 : &i->a->ap,
733 : i->rule_gen,
734 : lpt,
735 14 : i->not_first_time && (! test_mode)
736 2 : ? EXCHANGE_TIMEOUT
737 : : GNUNET_TIME_UNIT_ZERO,
738 : &exchange_check_cb,
739 : i);
740 14 : if (NULL == i->kyc)
741 : {
742 0 : GNUNET_break (0);
743 0 : i->due = i->timeout;
744 : i->task
745 0 : = GNUNET_SCHEDULER_add_at (i->due,
746 : &inquiry_work,
747 : i);
748 0 : goto finish;
749 : }
750 14 : active_inquiries++;
751 14 : finish:
752 14 : if ( (0 == active_inquiries) &&
753 : (test_mode) )
754 : {
755 0 : GNUNET_log (GNUNET_ERROR_TYPE_INFO,
756 : "No more open inquiries and in test mode. Existing.\n");
757 0 : GNUNET_SCHEDULER_shutdown ();
758 0 : return;
759 : }
760 : }
761 :
762 :
763 : /**
764 : * Check if the account @a could work with exchange that
765 : * has keys @a keys.
766 : *
767 : * @param keys the keys of an exchange
768 : * @param a an account
769 : */
770 : static bool
771 27 : is_eligible (const struct TALER_EXCHANGE_Keys *keys,
772 : const struct Account *a)
773 : {
774 : struct TALER_NormalizedPayto np;
775 : bool ret;
776 :
777 27 : np = TALER_payto_normalize (a->merchant_account_uri);
778 27 : ret = TALER_EXCHANGE_keys_test_account_allowed (keys,
779 : true,
780 : np);
781 27 : GNUNET_free (np.normalized_payto);
782 27 : return ret;
783 : }
784 :
785 :
786 : /**
787 : * Start the KYC checking for account @a at exchange @a e.
788 : *
789 : * @param e an exchange
790 : * @param a an account
791 : */
792 : static void
793 12 : start_inquiry (struct Exchange *e,
794 : struct Account *a)
795 : {
796 : struct Inquiry *i;
797 : enum GNUNET_DB_QueryStatus qs;
798 :
799 12 : i = GNUNET_new (struct Inquiry);
800 12 : i->e = e;
801 12 : i->a = a;
802 12 : GNUNET_CONTAINER_DLL_insert (a->i_head,
803 : a->i_tail,
804 : i);
805 12 : qs = db_plugin->get_kyc_status (db_plugin->cls,
806 : a->merchant_account_uri,
807 12 : a->instance_id,
808 12 : e->keys->exchange_url,
809 : &i->auth_ok,
810 : &i->access_token,
811 : &i->kyc_ok,
812 : &i->last_http_status,
813 : &i->last_ec,
814 : &i->rule_gen,
815 : &i->last_kyc_check,
816 : &i->aml_review,
817 : &i->jlimits);
818 12 : if (qs < 0)
819 : {
820 0 : GNUNET_break (0);
821 0 : global_ret = EXIT_FAILURE;
822 0 : GNUNET_SCHEDULER_shutdown ();
823 0 : return;
824 : }
825 12 : if (qs > 0)
826 0 : i->not_first_time = true;
827 12 : switch (i->last_http_status)
828 : {
829 0 : case MHD_HTTP_OK:
830 : /* KYC is OK, but we could have missed some triggers,
831 : so let's check, but slowly within the next minute
832 : so that we do not overdo it if this process happens
833 : to be restarted a lot. */
834 0 : if (GNUNET_YES != test_mode)
835 : {
836 0 : i->due = GNUNET_TIME_relative_to_absolute (
837 : GNUNET_TIME_randomize (GNUNET_TIME_UNIT_MINUTES));
838 0 : GNUNET_log (GNUNET_ERROR_TYPE_INFO,
839 : "Previous KYC status is OK, randomizing inquiry to start at %s\n",
840 : GNUNET_TIME_absolute2s (i->due));
841 : }
842 0 : break;
843 0 : case MHD_HTTP_ACCEPTED:
844 : /* KYC required, due immediately */
845 0 : break;
846 0 : case MHD_HTTP_NO_CONTENT:
847 : /* KYC is OFF, only check again if triggered */
848 0 : if (GNUNET_YES != test_mode)
849 : {
850 0 : i->due = GNUNET_TIME_relative_to_absolute (
851 : GNUNET_TIME_randomize (aml_low_freq));
852 0 : GNUNET_log (GNUNET_ERROR_TYPE_INFO,
853 : "KYC was disabled, randomizing inquiry to start at %s\n",
854 : GNUNET_TIME_absolute2s (i->due));
855 : }
856 0 : break;
857 0 : case MHD_HTTP_FORBIDDEN: /* bad signature */
858 : case MHD_HTTP_NOT_FOUND: /* account unknown */
859 : case MHD_HTTP_CONFLICT: /* no account_pub known */
860 : /* go immediately into long-polling */
861 0 : break;
862 12 : default:
863 : /* start with decent back-off after hard failure */
864 12 : if (GNUNET_YES != test_mode)
865 : {
866 : i->backoff
867 12 : = GNUNET_TIME_randomize (GNUNET_TIME_UNIT_MINUTES);
868 12 : GNUNET_log (GNUNET_ERROR_TYPE_INFO,
869 : "Last KYC check failed, starting with backoff %s\n",
870 : GNUNET_TIME_relative2s (i->backoff,
871 : true));
872 : }
873 12 : break;
874 : }
875 12 : inquiry_work (i);
876 : }
877 :
878 :
879 : /**
880 : * Stop KYC inquiry @a i.
881 : *
882 : * @param[in] i the inquiry to stop
883 : */
884 : static void
885 12 : stop_inquiry (struct Inquiry *i)
886 : {
887 12 : struct Account *a = i->a;
888 :
889 12 : GNUNET_CONTAINER_DLL_remove (a->i_head,
890 : a->i_tail,
891 : i);
892 12 : if (NULL != i->task)
893 : {
894 12 : GNUNET_SCHEDULER_cancel (i->task);
895 12 : i->task = NULL;
896 : }
897 12 : if (NULL != i->kyc)
898 : {
899 0 : TALER_EXCHANGE_kyc_check_cancel (i->kyc);
900 0 : i->kyc = NULL;
901 : }
902 12 : if (NULL != i->jlimits)
903 : {
904 1 : json_decref (i->jlimits);
905 1 : i->jlimits = NULL;
906 : }
907 12 : GNUNET_free (i);
908 12 : }
909 :
910 :
911 : /**
912 : * Stop KYC inquiry for account @a at exchange @a e.
913 : *
914 : * @param e an exchange
915 : * @param a an account
916 : */
917 : static void
918 0 : stop_inquiry_at (struct Exchange *e,
919 : struct Account *a)
920 : {
921 0 : for (struct Inquiry *i = a->i_head;
922 0 : NULL != i;
923 0 : i = i->next)
924 : {
925 0 : if (e == i->e)
926 : {
927 0 : stop_inquiry (i);
928 0 : return;
929 : }
930 : }
931 : /* strange, there should have been a match! */
932 0 : GNUNET_break (0);
933 : }
934 :
935 :
936 : /**
937 : * Start inquries for all exchanges on account @a a.
938 : *
939 : * @param a an account
940 : */
941 : static void
942 14 : start_inquiries (struct Account *a)
943 : {
944 14 : for (struct Exchange *e = e_head;
945 38 : NULL != e;
946 24 : e = e->next)
947 : {
948 24 : if (is_eligible (e->keys,
949 : a))
950 9 : start_inquiry (e,
951 : a);
952 : else
953 15 : GNUNET_log (GNUNET_ERROR_TYPE_INFO,
954 : "Account %s not eligible at exchange %s\n",
955 : a->merchant_account_uri.full_payto,
956 : e->keys->exchange_url);
957 : }
958 14 : }
959 :
960 :
961 : /**
962 : * Stop all inquries involving account @a a.
963 : *
964 : * @param a an account
965 : */
966 : static void
967 19 : stop_inquiries (struct Account *a)
968 : {
969 : struct Inquiry *i;
970 :
971 31 : while (NULL != (i = a->i_head))
972 12 : stop_inquiry (i);
973 19 : }
974 :
975 :
976 : /**
977 : * Callback invoked with information about a bank account.
978 : *
979 : * @param cls closure
980 : * @param merchant_priv private key of the merchant instance
981 : * @param ad details about the account
982 : */
983 : static void
984 39 : account_cb (
985 : void *cls,
986 : const struct TALER_MerchantPrivateKeyP *merchant_priv,
987 : const struct TALER_MERCHANTDB_AccountDetails *ad)
988 : {
989 39 : struct TALER_FullPayto payto_uri = ad->payto_uri;
990 :
991 39 : if (! ad->active)
992 25 : return;
993 38 : if (NULL == merchant_priv)
994 0 : return; /* instance was deleted */
995 38 : for (struct Account *a = a_head;
996 45 : NULL != a;
997 7 : a = a->next)
998 : {
999 31 : if (0 ==
1000 31 : TALER_full_payto_cmp (payto_uri,
1001 : a->merchant_account_uri))
1002 : {
1003 24 : a->account_gen = database_gen;
1004 24 : return;
1005 : }
1006 : }
1007 : {
1008 14 : struct Account *a = GNUNET_new (struct Account);
1009 :
1010 14 : a->account_gen = database_gen;
1011 : a->merchant_account_uri.full_payto
1012 14 : = GNUNET_strdup (ad->payto_uri.full_payto);
1013 : a->instance_id
1014 14 : = GNUNET_strdup (ad->instance_id);
1015 : a->h_wire
1016 14 : = ad->h_wire;
1017 : a->ap.merchant_priv
1018 14 : = *merchant_priv;
1019 14 : TALER_full_payto_normalize_and_hash (a->merchant_account_uri,
1020 : &a->h_payto);
1021 14 : GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1022 : "Found account %s of instance %s with H_PAYTO %s\n",
1023 : ad->payto_uri.full_payto,
1024 : ad->instance_id,
1025 : GNUNET_sh2s (&a->h_payto.hash));
1026 14 : GNUNET_CONTAINER_DLL_insert (a_head,
1027 : a_tail,
1028 : a);
1029 14 : start_inquiries (a);
1030 : }
1031 : }
1032 :
1033 :
1034 : /**
1035 : * The set of bank accounts has changed, update our
1036 : * list of active inquiries.
1037 : *
1038 : * @param cls unused
1039 : */
1040 : static void
1041 51 : find_accounts (void *cls)
1042 : {
1043 : enum GNUNET_DB_QueryStatus qs;
1044 :
1045 : (void) cls;
1046 51 : account_task = NULL;
1047 51 : database_gen++;
1048 51 : qs = db_plugin->select_accounts (db_plugin->cls,
1049 : NULL, /* all instances */
1050 : &account_cb,
1051 : NULL);
1052 51 : if (qs < 0)
1053 : {
1054 0 : GNUNET_break (0);
1055 0 : return;
1056 : }
1057 51 : for (struct Account *a = a_head;
1058 92 : NULL != a;
1059 41 : a = a->next)
1060 : {
1061 41 : if (a->account_gen < database_gen)
1062 5 : stop_inquiries (a);
1063 : }
1064 : }
1065 :
1066 :
1067 : /**
1068 : * Function called when transfers are added to the merchant database. We look
1069 : * for more work.
1070 : *
1071 : * @param cls closure (NULL)
1072 : * @param extra additional event data provided
1073 : * @param extra_size number of bytes in @a extra
1074 : */
1075 : static void
1076 38 : account_changed (void *cls,
1077 : const void *extra,
1078 : size_t extra_size)
1079 : {
1080 : (void) cls;
1081 : (void) extra;
1082 : (void) extra_size;
1083 38 : if (NULL != account_task)
1084 0 : return;
1085 : account_task
1086 38 : = GNUNET_SCHEDULER_add_now (&find_accounts,
1087 : NULL);
1088 : }
1089 :
1090 :
1091 : /**
1092 : * Interact with the database to get the current set
1093 : * of exchange keys known to us.
1094 : *
1095 : * @param exchange_url the exchange URL to check
1096 : */
1097 : static void
1098 48 : find_keys (const char *exchange_url)
1099 : {
1100 : enum GNUNET_DB_QueryStatus qs;
1101 : struct TALER_EXCHANGE_Keys *keys;
1102 : struct Exchange *e;
1103 : struct GNUNET_TIME_Absolute first_retry;
1104 :
1105 48 : qs = db_plugin->select_exchange_keys (db_plugin->cls,
1106 : exchange_url,
1107 : &first_retry,
1108 : &keys);
1109 48 : if (qs < 0)
1110 : {
1111 0 : GNUNET_break (0);
1112 26 : return;
1113 : }
1114 48 : if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs)
1115 : {
1116 26 : GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1117 : "No %s/keys yet!\n",
1118 : exchange_url);
1119 26 : return;
1120 : }
1121 31 : for (e = e_head; NULL != e; e = e->next)
1122 : {
1123 9 : if (0 == strcmp (e->keys->exchange_url,
1124 9 : keys->exchange_url))
1125 : {
1126 0 : struct TALER_EXCHANGE_Keys *old_keys = e->keys;
1127 :
1128 0 : e->keys = keys;
1129 0 : for (struct Account *a = a_head;
1130 0 : NULL != a;
1131 0 : a = a->next)
1132 : {
1133 0 : bool was_eligible = is_eligible (old_keys,
1134 : a);
1135 0 : bool now_eligible = is_eligible (keys,
1136 : a);
1137 :
1138 0 : if (was_eligible == now_eligible)
1139 0 : continue; /* no change, do nothing */
1140 0 : if (was_eligible)
1141 0 : stop_inquiry_at (e,
1142 : a);
1143 : else /* is_eligible */
1144 0 : start_inquiry (e,
1145 : a);
1146 : }
1147 0 : TALER_EXCHANGE_keys_decref (old_keys);
1148 0 : return;
1149 : }
1150 : }
1151 22 : e = GNUNET_new (struct Exchange);
1152 22 : e->keys = keys;
1153 22 : GNUNET_CONTAINER_DLL_insert (e_head,
1154 : e_tail,
1155 : e);
1156 22 : for (struct Account *a = a_head;
1157 25 : NULL != a;
1158 3 : a = a->next)
1159 : {
1160 6 : if ( (a->account_gen == database_gen) &&
1161 3 : (is_eligible (e->keys,
1162 : a)) )
1163 3 : start_inquiry (e,
1164 : a);
1165 : }
1166 : }
1167 :
1168 :
1169 : /**
1170 : * Function called when keys were changed in the
1171 : * merchant database. Updates ours.
1172 : *
1173 : * @param cls closure (NULL)
1174 : * @param extra additional event data provided
1175 : * @param extra_size number of bytes in @a extra
1176 : */
1177 : static void
1178 22 : keys_changed (void *cls,
1179 : const void *extra,
1180 : size_t extra_size)
1181 : {
1182 22 : const char *url = extra;
1183 :
1184 : (void) cls;
1185 22 : if ( (NULL == extra) ||
1186 : (0 == extra_size) )
1187 : {
1188 0 : GNUNET_break (0);
1189 0 : return;
1190 : }
1191 22 : if ('\0' != url[extra_size - 1])
1192 : {
1193 0 : GNUNET_break (0);
1194 0 : return;
1195 : }
1196 22 : GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1197 : "Received keys change notification: reload `%s'\n",
1198 : url);
1199 22 : find_keys (url);
1200 : }
1201 :
1202 :
1203 : /**
1204 : * Function called when a KYC rule was triggered by
1205 : * a transaction and we need to get the latest KYC
1206 : * status immediately.
1207 : *
1208 : * @param cls closure (NULL)
1209 : * @param extra additional event data provided
1210 : * @param extra_size number of bytes in @a extra
1211 : */
1212 : static void
1213 0 : rule_triggered (void *cls,
1214 : const void *extra,
1215 : size_t extra_size)
1216 : {
1217 0 : const char *text = extra;
1218 : const char *space;
1219 : struct TALER_MerchantWireHashP h_wire;
1220 : const char *exchange_url;
1221 :
1222 : (void) cls;
1223 0 : if ( (NULL == extra) ||
1224 : (0 == extra_size) )
1225 : {
1226 0 : GNUNET_break (0);
1227 0 : return;
1228 : }
1229 0 : if ('\0' != text[extra_size - 1])
1230 : {
1231 0 : GNUNET_break (0);
1232 0 : return;
1233 : }
1234 0 : space = memchr (extra,
1235 : ' ',
1236 : extra_size);
1237 0 : if (NULL == space)
1238 : {
1239 0 : GNUNET_break (0);
1240 0 : return;
1241 : }
1242 0 : if (GNUNET_OK !=
1243 0 : GNUNET_STRINGS_string_to_data (extra,
1244 0 : space - text,
1245 : &h_wire,
1246 : sizeof (h_wire)))
1247 : {
1248 0 : GNUNET_break (0);
1249 0 : return;
1250 : }
1251 0 : exchange_url = &space[1];
1252 0 : if (! TALER_is_web_url (exchange_url))
1253 : {
1254 0 : GNUNET_break (0);
1255 0 : return;
1256 : }
1257 :
1258 0 : for (struct Account *a = a_head;
1259 0 : NULL != a;
1260 0 : a = a->next)
1261 : {
1262 0 : if (0 !=
1263 0 : GNUNET_memcmp (&h_wire,
1264 : &a->h_wire))
1265 0 : continue;
1266 0 : for (struct Inquiry *i = a->i_head;
1267 0 : NULL != i;
1268 0 : i = i->next)
1269 : {
1270 0 : if (0 != strcmp (exchange_url,
1271 0 : i->e->keys->exchange_url))
1272 0 : continue;
1273 0 : i->kyc_ok = false;
1274 0 : i->due = GNUNET_TIME_UNIT_ZERO_ABS;
1275 0 : if (NULL != i->task)
1276 : {
1277 0 : GNUNET_SCHEDULER_cancel (i->task);
1278 0 : i->task = NULL;
1279 : }
1280 0 : if (NULL != i->kyc)
1281 : {
1282 0 : GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1283 : "/kyc-check already running for %s\n",
1284 : text);
1285 0 : return;
1286 : }
1287 0 : GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1288 : "Starting %skyc-check for `%s' due to KYC rule trigger\n",
1289 : exchange_url,
1290 : i->a->merchant_account_uri.full_payto);
1291 0 : i->task = GNUNET_SCHEDULER_add_at (i->due,
1292 : &inquiry_work,
1293 : i);
1294 0 : return;
1295 : }
1296 : }
1297 0 : GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1298 : "KYC rule trigger notification `%s' matches none of our accounts\n",
1299 : text);
1300 : }
1301 :
1302 :
1303 : /**
1304 : * Function called on each configuration section. Finds sections
1305 : * about exchanges, parses the entries.
1306 : *
1307 : * @param cls NULL
1308 : * @param section name of the section
1309 : */
1310 : static void
1311 506 : accept_exchanges (void *cls,
1312 : const char *section)
1313 : {
1314 : char *url;
1315 :
1316 : (void) cls;
1317 506 : if (0 !=
1318 506 : strncasecmp (section,
1319 : "merchant-exchange-",
1320 : strlen ("merchant-exchange-")))
1321 480 : return;
1322 39 : if (GNUNET_YES ==
1323 39 : GNUNET_CONFIGURATION_get_value_yesno (cfg,
1324 : section,
1325 : "DISABLED"))
1326 13 : return;
1327 26 : if (GNUNET_OK !=
1328 26 : GNUNET_CONFIGURATION_get_value_string (cfg,
1329 : section,
1330 : "EXCHANGE_BASE_URL",
1331 : &url))
1332 : {
1333 0 : GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
1334 : section,
1335 : "EXCHANGE_BASE_URL");
1336 0 : global_ret = EXIT_NOTCONFIGURED;
1337 0 : GNUNET_SCHEDULER_shutdown ();
1338 0 : return;
1339 : }
1340 26 : find_keys (url);
1341 26 : GNUNET_free (url);
1342 : }
1343 :
1344 :
1345 : /**
1346 : * We're being aborted with CTRL-C (or SIGTERM). Shut down.
1347 : *
1348 : * @param cls closure (NULL)
1349 : */
1350 : static void
1351 13 : shutdown_task (void *cls)
1352 : {
1353 : (void) cls;
1354 13 : GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1355 : "Running shutdown\n");
1356 35 : while (NULL != e_head)
1357 : {
1358 22 : struct Exchange *e = e_head;
1359 :
1360 22 : if (NULL != e->keys)
1361 : {
1362 22 : TALER_EXCHANGE_keys_decref (e->keys);
1363 22 : e->keys = NULL;
1364 : }
1365 22 : GNUNET_CONTAINER_DLL_remove (e_head,
1366 : e_tail,
1367 : e);
1368 22 : GNUNET_free (e);
1369 : }
1370 27 : while (NULL != a_head)
1371 : {
1372 14 : struct Account *a = a_head;
1373 :
1374 14 : stop_inquiries (a);
1375 14 : GNUNET_CONTAINER_DLL_remove (a_head,
1376 : a_tail,
1377 : a);
1378 14 : GNUNET_free (a->merchant_account_uri.full_payto);
1379 14 : GNUNET_free (a->instance_id);
1380 14 : GNUNET_free (a);
1381 : }
1382 13 : if (NULL != eh_accounts)
1383 : {
1384 13 : db_plugin->event_listen_cancel (eh_accounts);
1385 13 : eh_accounts = NULL;
1386 : }
1387 13 : if (NULL != account_task)
1388 : {
1389 0 : GNUNET_SCHEDULER_cancel (account_task);
1390 0 : account_task = NULL;
1391 : }
1392 13 : if (NULL != eh_keys)
1393 : {
1394 13 : db_plugin->event_listen_cancel (eh_keys);
1395 13 : eh_keys = NULL;
1396 : }
1397 13 : if (NULL != eh_rule)
1398 : {
1399 13 : db_plugin->event_listen_cancel (eh_rule);
1400 13 : eh_rule = NULL;
1401 : }
1402 13 : TALER_MERCHANTDB_plugin_unload (db_plugin);
1403 13 : db_plugin = NULL;
1404 13 : cfg = NULL;
1405 13 : if (NULL != ctx)
1406 : {
1407 13 : GNUNET_CURL_fini (ctx);
1408 13 : ctx = NULL;
1409 : }
1410 13 : if (NULL != rc)
1411 : {
1412 13 : GNUNET_CURL_gnunet_rc_destroy (rc);
1413 13 : rc = NULL;
1414 : }
1415 13 : }
1416 :
1417 :
1418 : /**
1419 : * First task.
1420 : *
1421 : * @param cls closure, NULL
1422 : * @param args remaining command-line arguments
1423 : * @param cfgfile name of the configuration file used (for saving, can be NULL!)
1424 : * @param c configuration
1425 : */
1426 : static void
1427 13 : run (void *cls,
1428 : char *const *args,
1429 : const char *cfgfile,
1430 : const struct GNUNET_CONFIGURATION_Handle *c)
1431 : {
1432 : (void) args;
1433 : (void) cfgfile;
1434 :
1435 13 : cfg = c;
1436 13 : if (GNUNET_OK !=
1437 13 : GNUNET_CONFIGURATION_get_value_time (cfg,
1438 : "merchant-kyccheck",
1439 : "AML_FREQ",
1440 : &aml_freq))
1441 : {
1442 0 : GNUNET_log_config_missing (GNUNET_ERROR_TYPE_WARNING,
1443 : "merchant-kyccheck",
1444 : "AML_FREQ");
1445 : /* use default */
1446 0 : aml_freq = AML_FREQ;
1447 : }
1448 13 : if (GNUNET_OK !=
1449 13 : GNUNET_CONFIGURATION_get_value_time (cfg,
1450 : "merchant-kyccheck",
1451 : "AML_LOW_FREQ",
1452 : &aml_low_freq))
1453 : {
1454 0 : GNUNET_log_config_missing (GNUNET_ERROR_TYPE_WARNING,
1455 : "merchant-kyccheck",
1456 : "AML_LOW_FREQ");
1457 : /* use default */
1458 0 : aml_low_freq = AML_LOW_FREQ;
1459 : }
1460 13 : if (GNUNET_TIME_relative_cmp (aml_low_freq,
1461 : <,
1462 : aml_freq))
1463 : {
1464 0 : aml_low_freq = GNUNET_TIME_relative_multiply (aml_freq,
1465 : 10);
1466 0 : GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1467 : "AML_LOW_FREQ was set to less than AML_FREQ. Using %s instead\n",
1468 : GNUNET_TIME_relative2s (aml_low_freq,
1469 : true));
1470 : }
1471 13 : GNUNET_SCHEDULER_add_shutdown (&shutdown_task,
1472 : NULL);
1473 13 : ctx = GNUNET_CURL_init (&GNUNET_CURL_gnunet_scheduler_reschedule,
1474 : &rc);
1475 13 : rc = GNUNET_CURL_gnunet_rc_create (ctx);
1476 13 : if (NULL == ctx)
1477 : {
1478 0 : GNUNET_break (0);
1479 0 : GNUNET_SCHEDULER_shutdown ();
1480 0 : global_ret = EXIT_FAILURE;
1481 0 : return;
1482 : }
1483 13 : if (NULL ==
1484 13 : (db_plugin = TALER_MERCHANTDB_plugin_load (cfg)))
1485 : {
1486 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1487 : "Failed to initialize DB subsystem\n");
1488 0 : GNUNET_SCHEDULER_shutdown ();
1489 0 : global_ret = EXIT_NOTCONFIGURED;
1490 0 : return;
1491 : }
1492 13 : if (GNUNET_OK !=
1493 13 : db_plugin->connect (db_plugin->cls))
1494 : {
1495 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1496 : "Failed to connect to database. Consider running taler-merchant-dbinit.\n");
1497 0 : GNUNET_SCHEDULER_shutdown ();
1498 0 : global_ret = EXIT_FAILURE;
1499 0 : return;
1500 : }
1501 : {
1502 13 : struct GNUNET_DB_EventHeaderP es = {
1503 13 : .size = htons (sizeof (es)),
1504 13 : .type = htons (TALER_DBEVENT_MERCHANT_EXCHANGE_KEYS)
1505 : };
1506 :
1507 : eh_keys
1508 26 : = db_plugin->event_listen (db_plugin->cls,
1509 : &es,
1510 13 : GNUNET_TIME_UNIT_FOREVER_REL,
1511 : &keys_changed,
1512 : NULL);
1513 : }
1514 : {
1515 13 : struct GNUNET_DB_EventHeaderP es = {
1516 13 : .size = htons (sizeof (es)),
1517 13 : .type = htons (TALER_DBEVENT_MERCHANT_EXCHANGE_KYC_RULE_TRIGGERED)
1518 : };
1519 :
1520 : eh_rule
1521 26 : = db_plugin->event_listen (db_plugin->cls,
1522 : &es,
1523 13 : GNUNET_TIME_UNIT_FOREVER_REL,
1524 : &rule_triggered,
1525 : NULL);
1526 : }
1527 13 : GNUNET_CONFIGURATION_iterate_sections (cfg,
1528 : &accept_exchanges,
1529 : NULL);
1530 : {
1531 13 : struct GNUNET_DB_EventHeaderP es = {
1532 13 : .size = htons (sizeof (es)),
1533 13 : .type = htons (TALER_DBEVENT_MERCHANT_ACCOUNTS_CHANGED)
1534 : };
1535 :
1536 : eh_accounts
1537 26 : = db_plugin->event_listen (db_plugin->cls,
1538 : &es,
1539 13 : GNUNET_TIME_UNIT_FOREVER_REL,
1540 : &account_changed,
1541 : NULL);
1542 : }
1543 13 : GNUNET_assert (NULL == account_task);
1544 : account_task
1545 13 : = GNUNET_SCHEDULER_add_now (&find_accounts,
1546 : NULL);
1547 : }
1548 :
1549 :
1550 : /**
1551 : * The main function of taler-merchant-kyccheck
1552 : *
1553 : * @param argc number of arguments from the command line
1554 : * @param argv command line arguments
1555 : * @return 0 ok, 1 on error
1556 : */
1557 : int
1558 13 : main (int argc,
1559 : char *const *argv)
1560 : {
1561 13 : struct GNUNET_GETOPT_CommandLineOption options[] = {
1562 13 : GNUNET_GETOPT_option_timetravel ('T',
1563 : "timetravel"),
1564 13 : GNUNET_GETOPT_option_flag ('t',
1565 : "test",
1566 : "run in test mode and exit when idle",
1567 : &test_mode),
1568 13 : GNUNET_GETOPT_option_version (VERSION "-" VCS_VERSION),
1569 : GNUNET_GETOPT_OPTION_END
1570 : };
1571 : enum GNUNET_GenericReturnValue ret;
1572 :
1573 13 : ret = GNUNET_PROGRAM_run (
1574 : TALER_MERCHANT_project_data (),
1575 : argc, argv,
1576 : "taler-merchant-kyccheck",
1577 : gettext_noop (
1578 : "background process that checks the KYC state of our bank accounts at various exchanges"),
1579 : options,
1580 : &run, NULL);
1581 13 : if (GNUNET_SYSERR == ret)
1582 0 : return EXIT_INVALIDARGUMENT;
1583 13 : if (GNUNET_NO == ret)
1584 0 : return EXIT_SUCCESS;
1585 13 : return global_ret;
1586 : }
1587 :
1588 :
1589 : /* end of taler-merchant-kyccheck.c */
|