Line data Source code
1 : /*
2 : This file is part of TALER
3 : Copyright (C) 2022 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 kyclogic_api.c
18 : * @brief server-side KYC API
19 : * @author Christian Grothoff
20 : */
21 : #include "platform.h"
22 : #include "taler_kyclogic_lib.h"
23 :
24 : /**
25 : * Information about a KYC provider.
26 : */
27 : struct TALER_KYCLOGIC_KycProvider;
28 :
29 :
30 : /**
31 : * Abstract representation of a KYC check.
32 : */
33 : struct TALER_KYCLOGIC_KycCheck
34 : {
35 : /**
36 : * Human-readable name given to the KYC check.
37 : */
38 : char *name;
39 :
40 : /**
41 : * Array of @e num_providers providers that offer this type of KYC check.
42 : */
43 : struct TALER_KYCLOGIC_KycProvider **providers;
44 :
45 : /**
46 : * Length of the @e providers array.
47 : */
48 : unsigned int num_providers;
49 :
50 : };
51 :
52 :
53 : struct TALER_KYCLOGIC_KycProvider
54 : {
55 : /**
56 : * Name of the provider (configuration section name).
57 : */
58 : const char *provider_section_name;
59 :
60 : /**
61 : * Array of @e num_checks checks performed by this provider.
62 : */
63 : struct TALER_KYCLOGIC_KycCheck **provided_checks;
64 :
65 : /**
66 : * Logic to run for this provider.
67 : */
68 : struct TALER_KYCLOGIC_Plugin *logic;
69 :
70 : /**
71 : * @e provider_section_name specific details to
72 : * pass to the @e logic functions.
73 : */
74 : struct TALER_KYCLOGIC_ProviderDetails *pd;
75 :
76 : /**
77 : * Cost of running this provider's KYC.
78 : */
79 : unsigned long long cost;
80 :
81 : /**
82 : * Length of the @e checks array.
83 : */
84 : unsigned int num_checks;
85 :
86 : /**
87 : * Type of user this provider supports.
88 : */
89 : enum TALER_KYCLOGIC_KycUserType user_type;
90 : };
91 :
92 :
93 : /**
94 : * Condition that triggers a need to perform KYC.
95 : */
96 : struct TALER_KYCLOGIC_KycTrigger
97 : {
98 :
99 : /**
100 : * Timeframe to consider for computing the amount
101 : * to compare against the @e limit. Zero for the
102 : * wallet balance trigger (as not applicable).
103 : */
104 : struct GNUNET_TIME_Relative timeframe;
105 :
106 : /**
107 : * Maximum amount that can be transacted until
108 : * the rule triggers.
109 : */
110 : struct TALER_Amount threshold;
111 :
112 : /**
113 : * Array of @e num_checks checks to apply on this trigger.
114 : */
115 : struct TALER_KYCLOGIC_KycCheck **required_checks;
116 :
117 : /**
118 : * Length of the @e checks array.
119 : */
120 : unsigned int num_checks;
121 :
122 : /**
123 : * What event is this trigger for?
124 : */
125 : enum TALER_KYCLOGIC_KycTriggerEvent trigger;
126 :
127 : };
128 :
129 :
130 : /**
131 : * Array of @e num_kyc_logics KYC logic plugins we have loaded.
132 : */
133 : static struct TALER_KYCLOGIC_Plugin **kyc_logics;
134 :
135 : /**
136 : * Length of the #kyc_logics array.
137 : */
138 : static unsigned int num_kyc_logics;
139 :
140 : /**
141 : * Array of @e num_kyc_checks known types of
142 : * KYC checks.
143 : */
144 : static struct TALER_KYCLOGIC_KycCheck **kyc_checks;
145 :
146 : /**
147 : * Length of the #kyc_checks array.
148 : */
149 : static unsigned int num_kyc_checks;
150 :
151 : /**
152 : * Array of configured triggers.
153 : */
154 : static struct TALER_KYCLOGIC_KycTrigger **kyc_triggers;
155 :
156 : /**
157 : * Length of the #kyc_triggers array.
158 : */
159 : static unsigned int num_kyc_triggers;
160 :
161 : /**
162 : * Array of configured providers.
163 : */
164 : static struct TALER_KYCLOGIC_KycProvider **kyc_providers;
165 :
166 : /**
167 : * Length of the #kyc_providers array.
168 : */
169 : static unsigned int num_kyc_providers;
170 :
171 :
172 : enum GNUNET_GenericReturnValue
173 0 : TALER_KYCLOGIC_kyc_trigger_from_string (const char *trigger_s,
174 : enum TALER_KYCLOGIC_KycTriggerEvent *
175 : trigger)
176 : {
177 : struct
178 : {
179 : const char *in;
180 : enum TALER_KYCLOGIC_KycTriggerEvent out;
181 0 : } map [] = {
182 : { "withdraw", TALER_KYCLOGIC_KYC_TRIGGER_WITHDRAW },
183 : { "deposit", TALER_KYCLOGIC_KYC_TRIGGER_DEPOSIT },
184 : { "merge", TALER_KYCLOGIC_KYC_TRIGGER_P2P_RECEIVE },
185 : { "balance", TALER_KYCLOGIC_KYC_TRIGGER_WALLET_BALANCE },
186 : { NULL, 0 }
187 : };
188 :
189 0 : for (unsigned int i = 0; NULL != map[i].in; i++)
190 0 : if (0 == strcasecmp (map[i].in,
191 : trigger_s))
192 : {
193 0 : *trigger = map[i].out;
194 0 : return GNUNET_OK;
195 : }
196 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
197 : "Invalid KYC trigger `%s'\n",
198 : trigger_s);
199 0 : return GNUNET_SYSERR;
200 : }
201 :
202 :
203 : const char *
204 0 : TALER_KYCLOGIC_kyc_trigger2s (enum TALER_KYCLOGIC_KycTriggerEvent trigger)
205 : {
206 0 : switch (trigger)
207 : {
208 0 : case TALER_KYCLOGIC_KYC_TRIGGER_WITHDRAW:
209 0 : return "withdraw";
210 0 : case TALER_KYCLOGIC_KYC_TRIGGER_DEPOSIT:
211 0 : return "deposit";
212 0 : case TALER_KYCLOGIC_KYC_TRIGGER_P2P_RECEIVE:
213 0 : return "merge";
214 0 : case TALER_KYCLOGIC_KYC_TRIGGER_WALLET_BALANCE:
215 0 : return "balance";
216 : }
217 0 : GNUNET_break (0);
218 0 : return NULL;
219 : }
220 :
221 :
222 : enum GNUNET_GenericReturnValue
223 3 : TALER_KYCLOGIC_kyc_user_type_from_string (const char *ut_s,
224 : enum TALER_KYCLOGIC_KycUserType *ut)
225 : {
226 : struct
227 : {
228 : const char *in;
229 : enum TALER_KYCLOGIC_KycUserType out;
230 3 : } map [] = {
231 : { "individual", TALER_KYCLOGIC_KYC_UT_INDIVIDUAL },
232 : { "business", TALER_KYCLOGIC_KYC_UT_BUSINESS },
233 : { NULL, 0 }
234 : };
235 :
236 3 : for (unsigned int i = 0; NULL != map[i].in; i++)
237 3 : if (0 == strcasecmp (map[i].in,
238 : ut_s))
239 : {
240 3 : *ut = map[i].out;
241 3 : return GNUNET_OK;
242 : }
243 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
244 : "Invalid user type `%s'\n",
245 : ut_s);
246 0 : return GNUNET_SYSERR;
247 : }
248 :
249 :
250 : const char *
251 0 : TALER_KYCLOGIC_kyc_user_type2s (enum TALER_KYCLOGIC_KycUserType ut)
252 : {
253 0 : switch (ut)
254 : {
255 0 : case TALER_KYCLOGIC_KYC_UT_INDIVIDUAL:
256 0 : return "individual";
257 0 : case TALER_KYCLOGIC_KYC_UT_BUSINESS:
258 0 : return "business";
259 : }
260 0 : GNUNET_break (0);
261 0 : return NULL;
262 : }
263 :
264 :
265 : /**
266 : * Load KYC logic plugin.
267 : *
268 : * @param cfg configuration to use
269 : * @param name name of the plugin
270 : * @return NULL on error
271 : */
272 : static struct TALER_KYCLOGIC_Plugin *
273 3 : load_logic (const struct GNUNET_CONFIGURATION_Handle *cfg,
274 : const char *name)
275 : {
276 : char *lib_name;
277 : struct TALER_KYCLOGIC_Plugin *plugin;
278 :
279 3 : GNUNET_asprintf (&lib_name,
280 : "libtaler_plugin_kyclogic_%s",
281 : name);
282 6 : for (unsigned int i = 0; i<num_kyc_logics; i++)
283 3 : if (0 == strcmp (lib_name,
284 3 : kyc_logics[i]->library_name))
285 : {
286 0 : GNUNET_free (lib_name);
287 0 : return kyc_logics[i];
288 : }
289 3 : plugin = GNUNET_PLUGIN_load (lib_name,
290 : (void *) cfg);
291 3 : if (NULL == plugin)
292 : {
293 0 : GNUNET_free (lib_name);
294 0 : return NULL;
295 : }
296 3 : plugin->library_name = lib_name;
297 3 : plugin->name = GNUNET_strdup (name);
298 3 : GNUNET_array_append (kyc_logics,
299 : num_kyc_logics,
300 : plugin);
301 3 : return plugin;
302 : }
303 :
304 :
305 : /**
306 : * Add check type to global array of checks.
307 : * First checks if the type already exists, otherwise
308 : * adds a new one.
309 : *
310 : * @param check name of the check
311 : * @return pointer into the global list
312 : */
313 : static struct TALER_KYCLOGIC_KycCheck *
314 3 : add_check (const char *check)
315 : {
316 : struct TALER_KYCLOGIC_KycCheck *kc;
317 :
318 3 : for (unsigned int i = 0; i<num_kyc_checks; i++)
319 2 : if (0 == strcasecmp (check,
320 2 : kyc_checks[i]->name))
321 2 : return kyc_checks[i];
322 1 : kc = GNUNET_new (struct TALER_KYCLOGIC_KycCheck);
323 1 : kc->name = GNUNET_strdup (check);
324 1 : GNUNET_array_append (kyc_checks,
325 : num_kyc_checks,
326 : kc);
327 1 : return kc;
328 : }
329 :
330 :
331 : /**
332 : * Parse list of checks from @a checks and build an
333 : * array of aliases into the global checks array
334 : * in @a provided_checks.
335 : *
336 : * @param[in,out] checks list of checks; clobbered
337 : * @param[out] p_checks where to put array of aliases
338 : * @param[out] num_p_checks set to length of @a p_checks array
339 : */
340 : static void
341 3 : add_checks (char *checks,
342 : struct TALER_KYCLOGIC_KycCheck ***p_checks,
343 : unsigned int *num_p_checks)
344 : {
345 : char *sptr;
346 3 : struct TALER_KYCLOGIC_KycCheck **rchecks = NULL;
347 3 : unsigned int num_rchecks = 0;
348 :
349 6 : for (char *tok = strtok_r (checks, " ", &sptr);
350 : NULL != tok;
351 3 : tok = strtok_r (NULL, " ", &sptr))
352 : {
353 : struct TALER_KYCLOGIC_KycCheck *kc;
354 :
355 3 : kc = add_check (tok);
356 3 : GNUNET_array_append (rchecks,
357 : num_rchecks,
358 : kc);
359 : }
360 3 : *p_checks = rchecks;
361 3 : *num_p_checks = num_rchecks;
362 3 : }
363 :
364 :
365 : /**
366 : * Parse configuration of a KYC provider.
367 : *
368 : * @param cfg configuration to parse
369 : * @param section name of the section to analyze
370 : * @return #GNUNET_OK on success
371 : */
372 : static enum GNUNET_GenericReturnValue
373 3 : add_provider (const struct GNUNET_CONFIGURATION_Handle *cfg,
374 : const char *section)
375 : {
376 : unsigned long long cost;
377 : char *logic;
378 : char *ut_s;
379 : enum TALER_KYCLOGIC_KycUserType ut;
380 : char *checks;
381 : struct TALER_KYCLOGIC_Plugin *lp;
382 :
383 3 : if (GNUNET_OK !=
384 3 : GNUNET_CONFIGURATION_get_value_number (cfg,
385 : section,
386 : "COST",
387 : &cost))
388 : {
389 0 : GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
390 : section,
391 : "COST",
392 : "number required");
393 0 : return GNUNET_SYSERR;
394 : }
395 3 : if (GNUNET_OK !=
396 3 : GNUNET_CONFIGURATION_get_value_string (cfg,
397 : section,
398 : "USER_TYPE",
399 : &ut_s))
400 : {
401 0 : GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
402 : section,
403 : "USER_TYPE");
404 0 : return GNUNET_SYSERR;
405 : }
406 3 : if (GNUNET_OK !=
407 3 : TALER_KYCLOGIC_kyc_user_type_from_string (ut_s,
408 : &ut))
409 : {
410 0 : GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
411 : section,
412 : "USER_TYPE",
413 : "valid user type required");
414 0 : GNUNET_free (ut_s);
415 0 : return GNUNET_SYSERR;
416 : }
417 3 : GNUNET_free (ut_s);
418 3 : if (GNUNET_OK !=
419 3 : GNUNET_CONFIGURATION_get_value_string (cfg,
420 : section,
421 : "LOGIC",
422 : &logic))
423 : {
424 0 : GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
425 : section,
426 : "LOGIC");
427 0 : return GNUNET_SYSERR;
428 : }
429 3 : lp = load_logic (cfg,
430 : logic);
431 3 : if (NULL == lp)
432 : {
433 0 : GNUNET_free (logic);
434 0 : GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
435 : section,
436 : "LOGIC",
437 : "logic plugin could not be loaded");
438 0 : return GNUNET_SYSERR;
439 : }
440 3 : GNUNET_free (logic);
441 3 : if (GNUNET_OK !=
442 3 : GNUNET_CONFIGURATION_get_value_string (cfg,
443 : section,
444 : "PROVIDED_CHECKS",
445 : &checks))
446 : {
447 0 : GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
448 : section,
449 : "PROVIDED_CHECKS");
450 0 : return GNUNET_SYSERR;
451 : }
452 : {
453 : struct TALER_KYCLOGIC_KycProvider *kp;
454 :
455 3 : kp = GNUNET_new (struct TALER_KYCLOGIC_KycProvider);
456 3 : kp->provider_section_name = section;
457 3 : kp->user_type = ut;
458 3 : kp->logic = lp;
459 3 : kp->cost = cost;
460 3 : add_checks (checks,
461 : &kp->provided_checks,
462 : &kp->num_checks);
463 3 : GNUNET_free (checks);
464 3 : kp->pd = lp->load_configuration (lp->cls,
465 : section);
466 3 : if (NULL == kp->pd)
467 : {
468 0 : GNUNET_free (kp);
469 0 : return GNUNET_SYSERR;
470 : }
471 3 : GNUNET_array_append (kyc_providers,
472 : num_kyc_providers,
473 : kp);
474 6 : for (unsigned int i = 0; i<kp->num_checks; i++)
475 : {
476 3 : struct TALER_KYCLOGIC_KycCheck *kc = kp->provided_checks[i];
477 :
478 3 : GNUNET_array_append (kc->providers,
479 : kc->num_providers,
480 : kp);
481 : }
482 : }
483 3 : return GNUNET_OK;
484 : }
485 :
486 :
487 : /**
488 : * Parse configuration @a cfg in section @a section for
489 : * the specification of a KYC trigger.
490 : *
491 : * @param cfg configuration to parse
492 : * @param section configuration section to parse
493 : * @return #GNUNET_OK on success
494 : */
495 : static enum GNUNET_GenericReturnValue
496 0 : add_trigger (const struct GNUNET_CONFIGURATION_Handle *cfg,
497 : const char *section)
498 : {
499 : char *ot_s;
500 : struct TALER_Amount threshold;
501 : struct GNUNET_TIME_Relative timeframe;
502 : char *checks;
503 : enum TALER_KYCLOGIC_KycTriggerEvent ot;
504 :
505 0 : if (GNUNET_OK !=
506 0 : TALER_config_get_amount (cfg,
507 : section,
508 : "THRESHOLD",
509 : &threshold))
510 : {
511 0 : GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
512 : section,
513 : "THRESHOLD",
514 : "amount required");
515 0 : return GNUNET_SYSERR;
516 : }
517 0 : if (GNUNET_OK !=
518 0 : GNUNET_CONFIGURATION_get_value_string (cfg,
519 : section,
520 : "OPERATION_TYPE",
521 : &ot_s))
522 : {
523 0 : GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
524 : section,
525 : "OPERATION_TYPE");
526 0 : return GNUNET_SYSERR;
527 : }
528 0 : if (GNUNET_OK !=
529 0 : TALER_KYCLOGIC_kyc_trigger_from_string (ot_s,
530 : &ot))
531 : {
532 0 : GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
533 : section,
534 : "OPERATION_TYPE",
535 : "valid trigger type required");
536 0 : GNUNET_free (ot_s);
537 0 : return GNUNET_SYSERR;
538 : }
539 0 : GNUNET_free (ot_s);
540 :
541 0 : if (GNUNET_OK !=
542 0 : GNUNET_CONFIGURATION_get_value_time (cfg,
543 : section,
544 : "TIMEFRAME",
545 : &timeframe))
546 : {
547 0 : if (TALER_KYCLOGIC_KYC_TRIGGER_WALLET_BALANCE == ot)
548 : {
549 0 : timeframe = GNUNET_TIME_UNIT_ZERO;
550 : }
551 : else
552 : {
553 0 : GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
554 : section,
555 : "TIMEFRAME",
556 : "duration required");
557 0 : return GNUNET_SYSERR;
558 : }
559 : }
560 0 : if (GNUNET_OK !=
561 0 : GNUNET_CONFIGURATION_get_value_string (cfg,
562 : section,
563 : "REQUIRED_CHECKS",
564 : &checks))
565 : {
566 0 : GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
567 : section,
568 : "REQUIRED_CHECKS");
569 0 : return GNUNET_SYSERR;
570 : }
571 :
572 : {
573 : struct TALER_KYCLOGIC_KycTrigger *kt;
574 :
575 0 : kt = GNUNET_new (struct TALER_KYCLOGIC_KycTrigger);
576 0 : kt->timeframe = timeframe;
577 0 : kt->threshold = threshold;
578 0 : kt->trigger = ot;
579 0 : add_checks (checks,
580 : &kt->required_checks,
581 : &kt->num_checks);
582 0 : GNUNET_free (checks);
583 0 : GNUNET_array_append (kyc_triggers,
584 : num_kyc_triggers,
585 : kt);
586 : }
587 0 : return GNUNET_OK;
588 : }
589 :
590 :
591 : /**
592 : * Closure for #handle_section().
593 : */
594 : struct SectionContext
595 : {
596 : /**
597 : * Configuration to handle.
598 : */
599 : const struct GNUNET_CONFIGURATION_Handle *cfg;
600 :
601 : /**
602 : * Result to return, set to false on failures.
603 : */
604 : bool result;
605 : };
606 :
607 :
608 : /**
609 : * Function to iterate over configuration sections.
610 : *
611 : * @param cls a `struct SectionContext *`
612 : * @param section name of the section
613 : */
614 : static void
615 29 : handle_section (void *cls,
616 : const char *section)
617 : {
618 29 : struct SectionContext *sc = cls;
619 :
620 29 : if (0 == strncasecmp (section,
621 : "kyc-provider-",
622 : strlen ("kyc-provider-")))
623 : {
624 3 : if (GNUNET_OK !=
625 3 : add_provider (sc->cfg,
626 : section))
627 0 : sc->result = false;
628 3 : return;
629 : }
630 26 : if (0 == strncasecmp (section,
631 : "kyc-legitimization-",
632 : strlen ("kyc-legitimization-")))
633 : {
634 0 : if (GNUNET_OK !=
635 0 : add_trigger (sc->cfg,
636 : section))
637 0 : sc->result = false;
638 0 : return;
639 : }
640 : }
641 :
642 :
643 : /**
644 : * Comparator for qsort. Compares two triggers
645 : * by timeframe to sort triggers by time.
646 : *
647 : * @param p1 first trigger to compare
648 : * @param p2 second trigger to compare
649 : * @return -1 if p1 < p2, 0 if p1==p2, 1 if p1 > p2.
650 : */
651 : static int
652 0 : sort_by_timeframe (const void *p1,
653 : const void *p2)
654 : {
655 0 : struct TALER_KYCLOGIC_KycTrigger **t1 = (struct
656 : TALER_KYCLOGIC_KycTrigger **) p1;
657 0 : struct TALER_KYCLOGIC_KycTrigger **t2 = (struct
658 : TALER_KYCLOGIC_KycTrigger **) p2;
659 :
660 0 : if (GNUNET_TIME_relative_cmp ((*t1)->timeframe,
661 : <,
662 : (*t2)->timeframe))
663 0 : return -1;
664 0 : if (GNUNET_TIME_relative_cmp ((*t1)->timeframe,
665 : >,
666 : (*t2)->timeframe))
667 0 : return 1;
668 0 : return 0;
669 : }
670 :
671 :
672 : enum GNUNET_GenericReturnValue
673 1 : TALER_KYCLOGIC_kyc_init (const struct GNUNET_CONFIGURATION_Handle *cfg)
674 : {
675 1 : struct SectionContext sc = {
676 : .cfg = cfg,
677 : .result = true
678 : };
679 :
680 1 : GNUNET_CONFIGURATION_iterate_sections (cfg,
681 : &handle_section,
682 : &sc);
683 1 : if (! sc.result)
684 : {
685 0 : TALER_KYCLOGIC_kyc_done ();
686 0 : return GNUNET_SYSERR;
687 : }
688 :
689 : /* sanity check: ensure at least one provider exists
690 : for any trigger and indidivual or business. */
691 2 : for (unsigned int i = 0; i<num_kyc_checks; i++)
692 1 : if (0 == kyc_checks[i]->num_providers)
693 : {
694 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
695 : "No provider available for required KYC check `%s'\n",
696 : kyc_checks[i]->name);
697 0 : TALER_KYCLOGIC_kyc_done ();
698 0 : return GNUNET_SYSERR;
699 : }
700 1 : qsort (kyc_triggers,
701 : num_kyc_triggers,
702 : sizeof (struct TALER_KYCLOGIC_KycTrigger *),
703 : &sort_by_timeframe);
704 1 : return GNUNET_OK;
705 : }
706 :
707 :
708 : void
709 0 : TALER_KYCLOGIC_kyc_done (void)
710 : {
711 0 : for (unsigned int i = 0; i<num_kyc_triggers; i++)
712 : {
713 0 : struct TALER_KYCLOGIC_KycTrigger *kt = kyc_triggers[i];
714 :
715 0 : GNUNET_array_grow (kt->required_checks,
716 : kt->num_checks,
717 : 0);
718 0 : GNUNET_free (kt);
719 : }
720 0 : GNUNET_array_grow (kyc_triggers,
721 : num_kyc_triggers,
722 : 0);
723 0 : for (unsigned int i = 0; i<num_kyc_providers; i++)
724 : {
725 0 : struct TALER_KYCLOGIC_KycProvider *kp = kyc_providers[i];
726 :
727 0 : kp->logic->unload_configuration (kp->pd);
728 0 : GNUNET_array_grow (kp->provided_checks,
729 : kp->num_checks,
730 : 0);
731 0 : GNUNET_free (kp);
732 : }
733 0 : GNUNET_array_grow (kyc_providers,
734 : num_kyc_providers,
735 : 0);
736 0 : for (unsigned int i = 0; i<num_kyc_logics; i++)
737 : {
738 0 : struct TALER_KYCLOGIC_Plugin *lp = kyc_logics[i];
739 0 : char *lib_name = lp->library_name;
740 :
741 0 : GNUNET_free (lp->name);
742 0 : GNUNET_assert (NULL == GNUNET_PLUGIN_unload (lib_name,
743 : lp));
744 0 : GNUNET_free (lib_name);
745 : }
746 0 : GNUNET_array_grow (kyc_logics,
747 : num_kyc_logics,
748 : 0);
749 0 : for (unsigned int i = 0; i<num_kyc_checks; i++)
750 : {
751 0 : struct TALER_KYCLOGIC_KycCheck *kc = kyc_checks[i];
752 :
753 0 : GNUNET_array_grow (kc->providers,
754 : kc->num_providers,
755 : 0);
756 0 : GNUNET_free (kc->name);
757 0 : GNUNET_free (kc);
758 : }
759 0 : GNUNET_array_grow (kyc_checks,
760 : num_kyc_checks,
761 : 0);
762 0 : }
763 :
764 :
765 : /**
766 : * Closure for the #eval_trigger().
767 : */
768 : struct ThresholdTestContext
769 : {
770 : /**
771 : * Total amount so far.
772 : */
773 : struct TALER_Amount total;
774 :
775 : /**
776 : * Trigger event to evaluate triggers of.
777 : */
778 : enum TALER_KYCLOGIC_KycTriggerEvent event;
779 :
780 : /**
781 : * Offset in the triggers array where we need to start
782 : * checking for triggers. All trigges below this
783 : * offset were already hit.
784 : */
785 : unsigned int start;
786 :
787 : /**
788 : * Array of checks needed so far.
789 : */
790 : struct TALER_KYCLOGIC_KycCheck **needed;
791 :
792 : /**
793 : * Pointer to number of entries used in @a needed.
794 : */
795 : unsigned int *needed_cnt;
796 :
797 : /**
798 : * Has @e total been initialized yet?
799 : */
800 : bool have_total;
801 : };
802 :
803 :
804 : /**
805 : * Function called on each @a amount that was found to
806 : * be relevant for a KYC check.
807 : *
808 : * @param cls closure to allow the KYC module to
809 : * total up amounts and evaluate rules
810 : * @param amount encountered transaction amount
811 : * @param date when was the amount encountered
812 : * @return #GNUNET_OK to continue to iterate,
813 : * #GNUNET_NO to abort iteration
814 : * #GNUNET_SYSERR on internal error (also abort itaration)
815 : */
816 : static enum GNUNET_GenericReturnValue
817 0 : eval_trigger (void *cls,
818 : const struct TALER_Amount *amount,
819 : struct GNUNET_TIME_Absolute date)
820 : {
821 0 : struct ThresholdTestContext *ttc = cls;
822 : struct GNUNET_TIME_Relative duration;
823 0 : bool bump = true;
824 :
825 0 : GNUNET_log (GNUNET_ERROR_TYPE_INFO,
826 : "KYC check with new amount %s\n",
827 : TALER_amount2s (amount));
828 0 : duration = GNUNET_TIME_absolute_get_duration (date);
829 0 : if (ttc->have_total)
830 : {
831 0 : if (0 >
832 0 : TALER_amount_add (&ttc->total,
833 0 : &ttc->total,
834 : amount))
835 : {
836 0 : GNUNET_break (0);
837 0 : return GNUNET_SYSERR;
838 : }
839 : }
840 : else
841 : {
842 0 : ttc->total = *amount;
843 0 : ttc->have_total = true;
844 : }
845 0 : GNUNET_log (GNUNET_ERROR_TYPE_INFO,
846 : "KYC check: new total is %s\n",
847 : TALER_amount2s (&ttc->total));
848 0 : for (unsigned int i = ttc->start; i<num_kyc_triggers; i++)
849 : {
850 0 : const struct TALER_KYCLOGIC_KycTrigger *kt = kyc_triggers[i];
851 :
852 0 : if (ttc->event != kt->trigger)
853 : {
854 0 : GNUNET_log (GNUNET_ERROR_TYPE_INFO,
855 : "KYC check #%u: trigger type does not match\n",
856 : i);
857 0 : continue;
858 : }
859 0 : duration = GNUNET_TIME_relative_max (duration,
860 : kt->timeframe);
861 0 : if (GNUNET_TIME_relative_cmp (kt->timeframe,
862 : >,
863 : duration))
864 : {
865 0 : GNUNET_log (GNUNET_ERROR_TYPE_INFO,
866 : "KYC check #%u: amount is beyond time limit\n",
867 : i);
868 0 : if (bump)
869 0 : ttc->start = i;
870 0 : return GNUNET_OK;
871 : }
872 0 : if (-1 ==
873 0 : TALER_amount_cmp (&ttc->total,
874 : &kt->threshold))
875 : {
876 0 : GNUNET_log (GNUNET_ERROR_TYPE_INFO,
877 : "KYC check #%u: amount is below threshold\n",
878 : i);
879 0 : if (bump)
880 0 : ttc->start = i;
881 0 : bump = false;
882 0 : continue; /* amount too low to trigger */
883 : }
884 : /* add check to list of required checks, unless
885 : already present... */
886 0 : for (unsigned int j = 0; j<kt->num_checks; j++)
887 : {
888 0 : struct TALER_KYCLOGIC_KycCheck *rc = kt->required_checks[j];
889 0 : bool found = false;
890 :
891 0 : for (unsigned int k = 0; k<*ttc->needed_cnt; k++)
892 0 : if (ttc->needed[k] == rc)
893 : {
894 0 : GNUNET_log (GNUNET_ERROR_TYPE_INFO,
895 : "KYC rule #%u already listed\n",
896 : j);
897 0 : found = true;
898 0 : break;
899 : }
900 0 : if (! found)
901 : {
902 0 : ttc->needed[*ttc->needed_cnt] = rc;
903 0 : (*ttc->needed_cnt)++;
904 : }
905 : }
906 0 : GNUNET_log (GNUNET_ERROR_TYPE_INFO,
907 : "KYC check #%u (%s) is applicable, %u checks needed so far\n",
908 : i,
909 : ttc->needed[(*ttc->needed_cnt) - 1]->name,
910 : *ttc->needed_cnt);
911 : }
912 0 : if (bump)
913 0 : return GNUNET_NO; /* we hit all possible triggers! */
914 0 : return GNUNET_OK;
915 : }
916 :
917 :
918 : /**
919 : * Closure for the #remove_satisfied().
920 : */
921 : struct RemoveContext
922 : {
923 :
924 : /**
925 : * Array of checks needed so far.
926 : */
927 : struct TALER_KYCLOGIC_KycCheck **needed;
928 :
929 : /**
930 : * Pointer to number of entries used in @a needed.
931 : */
932 : unsigned int *needed_cnt;
933 :
934 : };
935 :
936 :
937 : /**
938 : * Remove all checks satisfied by @a provider_name from
939 : * our list of checks.
940 : *
941 : * @param cls a `struct RemoveContext`
942 : * @param provider_name section name of provider that was already run previously
943 : */
944 : static void
945 0 : remove_satisfied (void *cls,
946 : const char *provider_name)
947 : {
948 0 : struct RemoveContext *rc = cls;
949 :
950 0 : for (unsigned int i = 0; i<num_kyc_providers; i++)
951 : {
952 0 : const struct TALER_KYCLOGIC_KycProvider *kp = kyc_providers[i];
953 :
954 0 : if (0 != strcasecmp (provider_name,
955 : kp->provider_section_name))
956 0 : continue;
957 0 : GNUNET_log (GNUNET_ERROR_TYPE_INFO,
958 : "Provider `%s' satisfied\n",
959 : provider_name);
960 0 : for (unsigned int j = 0; j<kp->num_checks; j++)
961 : {
962 0 : const struct TALER_KYCLOGIC_KycCheck *kc = kp->provided_checks[j];
963 :
964 0 : GNUNET_log (GNUNET_ERROR_TYPE_INFO,
965 : "Provider satisfies check `%s'\n",
966 : kc->name);
967 0 : for (unsigned int k = 0; k<*rc->needed_cnt; k++)
968 0 : if (kc == rc->needed[k])
969 : {
970 0 : GNUNET_log (GNUNET_ERROR_TYPE_INFO,
971 : "Removing check `%s' from list\n",
972 : kc->name);
973 0 : rc->needed[k] = rc->needed[*rc->needed_cnt - 1];
974 0 : (*rc->needed_cnt)--;
975 0 : if (0 == *rc->needed_cnt)
976 0 : return; /* for sure finished */
977 0 : break;
978 : }
979 : }
980 0 : break;
981 : }
982 : }
983 :
984 :
985 : const char *
986 0 : TALER_KYCLOGIC_kyc_test_required (enum TALER_KYCLOGIC_KycTriggerEvent event,
987 : const struct TALER_PaytoHashP *h_payto,
988 : TALER_KYCLOGIC_KycSatisfiedIterator ki,
989 : void *ki_cls,
990 : TALER_KYCLOGIC_KycAmountIterator ai,
991 : void *ai_cls)
992 0 : {
993 0 : struct TALER_KYCLOGIC_KycCheck *needed[num_kyc_checks];
994 0 : unsigned int needed_cnt = 0;
995 : char *ret;
996 : struct GNUNET_TIME_Relative timeframe;
997 :
998 0 : timeframe = GNUNET_TIME_UNIT_ZERO;
999 0 : for (unsigned int i = 0; i<num_kyc_triggers; i++)
1000 : {
1001 0 : const struct TALER_KYCLOGIC_KycTrigger *kt = kyc_triggers[i];
1002 :
1003 0 : if (event != kt->trigger)
1004 0 : continue;
1005 0 : timeframe = GNUNET_TIME_relative_max (timeframe,
1006 : kt->timeframe);
1007 : }
1008 : {
1009 : struct GNUNET_TIME_Absolute now;
1010 0 : struct ThresholdTestContext ttc = {
1011 : .event = event,
1012 : .needed = needed,
1013 : .needed_cnt = &needed_cnt
1014 : };
1015 :
1016 0 : now = GNUNET_TIME_absolute_get ();
1017 0 : ai (ai_cls,
1018 : GNUNET_TIME_absolute_subtract (now,
1019 : timeframe),
1020 : &eval_trigger,
1021 : &ttc);
1022 : }
1023 0 : if (0 == needed_cnt)
1024 0 : return NULL;
1025 0 : timeframe = GNUNET_TIME_UNIT_ZERO;
1026 0 : for (unsigned int i = 0; i<num_kyc_triggers; i++)
1027 : {
1028 0 : const struct TALER_KYCLOGIC_KycTrigger *kt = kyc_triggers[i];
1029 :
1030 0 : if (event != kt->trigger)
1031 0 : continue;
1032 0 : timeframe = GNUNET_TIME_relative_max (timeframe,
1033 : kt->timeframe);
1034 : }
1035 : {
1036 : struct GNUNET_TIME_Absolute now;
1037 0 : struct ThresholdTestContext ttc = {
1038 : .event = event,
1039 : .needed = needed,
1040 : .needed_cnt = &needed_cnt
1041 : };
1042 :
1043 0 : now = GNUNET_TIME_absolute_get ();
1044 0 : ai (ai_cls,
1045 : GNUNET_TIME_absolute_subtract (now,
1046 : timeframe),
1047 : &eval_trigger,
1048 : &ttc);
1049 : }
1050 0 : if (0 == needed_cnt)
1051 0 : return NULL;
1052 : {
1053 0 : struct RemoveContext rc = {
1054 : .needed = needed,
1055 : .needed_cnt = &needed_cnt
1056 : };
1057 : enum GNUNET_DB_QueryStatus qs;
1058 :
1059 : /* Check what provider checks are already satisfied for h_payto (with
1060 : database), remove those from the 'needed' array. */
1061 0 : qs = ki (ki_cls,
1062 : h_payto,
1063 : &remove_satisfied,
1064 : &rc);
1065 0 : GNUNET_break (qs >= 0); // FIXME: handle DB failure more nicely?
1066 : }
1067 0 : if (0 == needed_cnt)
1068 0 : return NULL;
1069 : {
1070 0 : struct RemoveContext rc = {
1071 : .needed = needed,
1072 : .needed_cnt = &needed_cnt
1073 : };
1074 : enum GNUNET_DB_QueryStatus qs;
1075 :
1076 : /* Check what provider checks are already satisfied for h_payto (with
1077 : database), remove those from the 'needed' array. */
1078 0 : qs = ki (ki_cls,
1079 : h_payto,
1080 : &remove_satisfied,
1081 : &rc);
1082 0 : GNUNET_break (qs >= 0); // FIXME: handle DB failure more nicely?
1083 : }
1084 0 : if (0 == needed_cnt)
1085 0 : return NULL;
1086 0 : ret = NULL;
1087 0 : for (unsigned int k = 0; k<needed_cnt; k++)
1088 : {
1089 0 : const struct TALER_KYCLOGIC_KycCheck *kc = needed[k];
1090 :
1091 0 : if (NULL == ret)
1092 : {
1093 0 : ret = GNUNET_strdup (kc->name);
1094 : }
1095 : else /* append */
1096 : {
1097 0 : char *tmp = ret;
1098 :
1099 0 : GNUNET_asprintf (&ret,
1100 : "%s %s",
1101 : tmp,
1102 : kc->name);
1103 0 : GNUNET_free (tmp);
1104 : }
1105 : }
1106 0 : return ret;
1107 : }
1108 :
1109 :
1110 : void
1111 0 : TALER_KYCLOGIC_kyc_get_details (
1112 : const char *logic_name,
1113 : TALER_KYCLOGIC_DetailsCallback cb,
1114 : void *cb_cls)
1115 : {
1116 0 : for (unsigned int i = 0; i<num_kyc_providers; i++)
1117 : {
1118 0 : struct TALER_KYCLOGIC_KycProvider *kp = kyc_providers[i];
1119 :
1120 0 : if (0 !=
1121 0 : strcmp (kp->logic->name,
1122 : logic_name))
1123 0 : continue;
1124 0 : if (GNUNET_OK !=
1125 0 : cb (cb_cls,
1126 0 : kp->pd,
1127 0 : kp->logic->cls))
1128 0 : return;
1129 : }
1130 : }
1131 :
1132 :
1133 : bool
1134 0 : TALER_KYCLOGIC_check_satisfied (const char *requirements,
1135 : const struct TALER_PaytoHashP *h_payto,
1136 : TALER_KYCLOGIC_KycSatisfiedIterator ki,
1137 : void *ki_cls)
1138 0 : {
1139 0 : struct TALER_KYCLOGIC_KycCheck *needed[num_kyc_checks];
1140 0 : unsigned int needed_cnt = 0;
1141 :
1142 0 : if (NULL == requirements)
1143 0 : return true;
1144 : {
1145 0 : char *req = GNUNET_strdup (requirements);
1146 :
1147 0 : for (const char *tok = strtok (req, " ");
1148 : NULL != tok;
1149 0 : tok = strtok (NULL, " "))
1150 0 : needed[needed_cnt++] = add_check (tok);
1151 0 : GNUNET_free (req);
1152 : }
1153 :
1154 : {
1155 0 : struct RemoveContext rc = {
1156 : .needed = needed,
1157 : .needed_cnt = &needed_cnt
1158 : };
1159 : enum GNUNET_DB_QueryStatus qs;
1160 :
1161 : /* Check what provider checks are already satisfied for h_payto (with
1162 : database), remove those from the 'needed' array. */
1163 0 : qs = ki (ki_cls,
1164 : h_payto,
1165 : &remove_satisfied,
1166 : &rc);
1167 0 : GNUNET_break (qs >= 0); // FIXME: handle DB failure more nicely?
1168 : }
1169 0 : return (0 == needed_cnt);
1170 : }
1171 :
1172 :
1173 : enum GNUNET_GenericReturnValue
1174 0 : TALER_KYCLOGIC_requirements_to_logic (const char *requirements,
1175 : enum TALER_KYCLOGIC_KycUserType ut,
1176 : struct TALER_KYCLOGIC_Plugin **plugin,
1177 : struct TALER_KYCLOGIC_ProviderDetails **pd,
1178 : const char **configuration_section)
1179 0 : {
1180 0 : struct TALER_KYCLOGIC_KycCheck *needed[num_kyc_checks];
1181 0 : unsigned int needed_cnt = 0;
1182 0 : unsigned long long min_cost = ULLONG_MAX;
1183 0 : unsigned int max_checks = 0;
1184 0 : const struct TALER_KYCLOGIC_KycProvider *kp_best = NULL;
1185 :
1186 : // FIXME: use 'ut' to filter providers!
1187 0 : if (NULL == requirements)
1188 0 : return GNUNET_NO;
1189 : {
1190 0 : char *req = GNUNET_strdup (requirements);
1191 :
1192 0 : for (const char *tok = strtok (req, " ");
1193 : NULL != tok;
1194 0 : tok = strtok (NULL, " "))
1195 0 : needed[needed_cnt++] = add_check (tok);
1196 0 : GNUNET_free (req);
1197 : }
1198 :
1199 : /* Count maximum number of remaining checks covered by any
1200 : provider */
1201 0 : for (unsigned int i = 0; i<num_kyc_providers; i++)
1202 : {
1203 0 : const struct TALER_KYCLOGIC_KycProvider *kp = kyc_providers[i];
1204 0 : unsigned int matched = 0;
1205 :
1206 0 : for (unsigned int j = 0; j<kp->num_checks; j++)
1207 : {
1208 0 : const struct TALER_KYCLOGIC_KycCheck *kc = kp->provided_checks[j];
1209 :
1210 0 : for (unsigned int k = 0; k<needed_cnt; k++)
1211 0 : if (kc == needed[k])
1212 : {
1213 0 : matched++;
1214 0 : break;
1215 : }
1216 : }
1217 0 : max_checks = GNUNET_MAX (max_checks,
1218 : matched);
1219 : }
1220 0 : if (0 == max_checks)
1221 0 : return GNUNET_SYSERR;
1222 :
1223 : /* Find min-cost provider covering max_checks. */
1224 0 : for (unsigned int i = 0; i<num_kyc_providers; i++)
1225 : {
1226 0 : const struct TALER_KYCLOGIC_KycProvider *kp = kyc_providers[i];
1227 0 : unsigned int matched = 0;
1228 :
1229 0 : for (unsigned int j = 0; j<kp->num_checks; j++)
1230 : {
1231 0 : const struct TALER_KYCLOGIC_KycCheck *kc = kp->provided_checks[j];
1232 :
1233 0 : for (unsigned int k = 0; k<needed_cnt; k++)
1234 0 : if (kc == needed[k])
1235 : {
1236 0 : matched++;
1237 0 : break;
1238 : }
1239 : }
1240 0 : if ( (max_checks == matched) &&
1241 0 : (kp->cost < min_cost) )
1242 : {
1243 0 : min_cost = kp->cost;
1244 0 : kp_best = kp;
1245 : }
1246 : }
1247 0 : *plugin = kp_best->logic;
1248 0 : *pd = kp_best->pd;
1249 0 : *configuration_section = kp_best->provider_section_name;
1250 0 : return GNUNET_OK;
1251 : }
1252 :
1253 :
1254 : enum GNUNET_GenericReturnValue
1255 0 : TALER_KYCLOGIC_lookup_logic (const char *name,
1256 : struct TALER_KYCLOGIC_Plugin **plugin,
1257 : struct TALER_KYCLOGIC_ProviderDetails **pd,
1258 : const char **provider_section)
1259 : {
1260 0 : for (unsigned int i = 0; i<num_kyc_providers; i++)
1261 : {
1262 0 : struct TALER_KYCLOGIC_KycProvider *kp = kyc_providers[i];
1263 :
1264 0 : if (0 !=
1265 0 : strcasecmp (name,
1266 : kp->provider_section_name))
1267 0 : continue;
1268 0 : *plugin = kp->logic;
1269 0 : *pd = kp->pd;
1270 0 : *provider_section = kp->provider_section_name;
1271 0 : return GNUNET_OK;
1272 : }
1273 0 : for (unsigned int i = 0; i<num_kyc_logics; i++)
1274 : {
1275 0 : struct TALER_KYCLOGIC_Plugin *logic = kyc_logics[i];
1276 :
1277 0 : if (0 !=
1278 0 : strcasecmp (logic->name,
1279 : name))
1280 0 : continue;
1281 0 : *plugin = logic;
1282 0 : *pd = NULL;
1283 0 : *provider_section = NULL;
1284 0 : return GNUNET_OK;
1285 : }
1286 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1287 : "Provider `%s' unknown\n",
1288 : name);
1289 0 : return GNUNET_SYSERR;
1290 : }
1291 :
1292 :
1293 : void
1294 0 : TALER_KYCLOGIC_kyc_iterate_thresholds (
1295 : enum TALER_KYCLOGIC_KycTriggerEvent event,
1296 : TALER_KYCLOGIC_KycThresholdIterator it,
1297 : void *it_cls)
1298 : {
1299 0 : for (unsigned int i = 0; i<num_kyc_triggers; i++)
1300 : {
1301 0 : const struct TALER_KYCLOGIC_KycTrigger *kt = kyc_triggers[i];
1302 :
1303 0 : if (event != kt->trigger)
1304 0 : continue;
1305 0 : it (it_cls,
1306 : &kt->threshold);
1307 : }
1308 0 : }
1309 :
1310 :
1311 : /* end of taler-exchange-httpd_kyc.c */
|