Line data Source code
1 : /*
2 : This file is part of TALER
3 : Copyright (C) 2023, 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 exchangedb_aml.c
18 : * @brief helper function to handle AML programs
19 : * @author Christian Grothoff
20 : */
21 : #include "taler_exchangedb_plugin.h"
22 : #include "taler_exchangedb_lib.h"
23 : #include "taler_kyclogic_lib.h"
24 : #include "taler_json_lib.h"
25 : #include "taler_dbevents.h"
26 : #include <gnunet/gnunet_common.h>
27 :
28 : /**
29 : * Maximum recursion depth we allow for AML programs.
30 : * Basically, after this number of "skip" processes
31 : * we forcefully terminate the recursion and fail hard.
32 : */
33 : #define MAX_DEPTH 16
34 :
35 : enum GNUNET_DB_QueryStatus
36 10 : TALER_EXCHANGEDB_persist_aml_program_result (
37 : struct TALER_EXCHANGEDB_Plugin *plugin,
38 : uint64_t process_row,
39 : const struct TALER_NormalizedPaytoHashP *account_id,
40 : const struct TALER_KYCLOGIC_AmlProgramResult *apr,
41 : enum TALER_EXCHANGEDB_PersistProgramResultStatus *ret_pprs)
42 : {
43 : enum GNUNET_DB_QueryStatus qs;
44 10 : json_t *jmeasures = NULL;
45 10 : struct TALER_KYCLOGIC_LegitimizationRuleSet *lrs = NULL;
46 :
47 10 : GNUNET_assert (NULL != ret_pprs);
48 :
49 10 : *ret_pprs = TALER_EXCHANGEDB_PPRS_OK;
50 :
51 10 : if ( (TALER_KYCLOGIC_AMLR_SUCCESS == apr->status) &&
52 10 : (NULL != apr->details.success.new_measures) )
53 : {
54 0 : lrs = TALER_KYCLOGIC_rules_parse (apr->details.success.new_rules);
55 0 : if (NULL == lrs)
56 : {
57 0 : qs = plugin->insert_aml_program_failure (
58 : plugin->cls,
59 : process_row,
60 : account_id,
61 : "Failed to parse AML program output",
62 : TALER_EC_EXCHANGE_KYC_AML_PROGRAM_MALFORMED_RESULT);
63 0 : GNUNET_break (qs > 0);
64 0 : return qs;
65 : }
66 0 : jmeasures = TALER_KYCLOGIC_get_jmeasures (
67 : lrs,
68 0 : apr->details.success.new_measures);
69 0 : if (NULL == jmeasures)
70 : {
71 : char *err;
72 :
73 0 : GNUNET_break (0);
74 0 : GNUNET_asprintf (&err,
75 : "Failed to find measures `%s' specified in AML program output",
76 0 : apr->details.success.new_measures);
77 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
78 : "AML program specified invalid measures `%s'\n",
79 : apr->details.success.new_measures);
80 0 : qs = plugin->insert_aml_program_failure (
81 : plugin->cls,
82 : process_row,
83 : account_id,
84 : err,
85 : TALER_EC_EXCHANGE_KYC_AML_PROGRAM_MALFORMED_RESULT);
86 0 : *ret_pprs = TALER_EXCHANGEDB_PPRS_BAD_OUTCOME;
87 0 : GNUNET_free (err);
88 0 : GNUNET_break (qs > 0);
89 0 : return qs;
90 : }
91 : }
92 :
93 10 : qs = plugin->clear_aml_lock (
94 : plugin->cls,
95 : account_id);
96 10 : switch (apr->status)
97 : {
98 0 : case TALER_KYCLOGIC_AMLR_FAILURE:
99 0 : qs = plugin->insert_aml_program_failure (
100 : plugin->cls,
101 : process_row,
102 : account_id,
103 0 : apr->details.failure.error_message,
104 0 : apr->details.failure.ec);
105 0 : GNUNET_break (qs > 0);
106 0 : goto cleanup;
107 10 : case TALER_KYCLOGIC_AMLR_SUCCESS:
108 : {
109 10 : struct TALER_FullPayto null_payto_uri = { 0 };
110 : bool invalid_officer;
111 : bool unknown_account;
112 : struct GNUNET_TIME_Timestamp last_date;
113 : uint64_t legitimization_measure_serial_id;
114 : bool is_wallet;
115 :
116 10 : qs = plugin->insert_aml_decision (
117 : plugin->cls,
118 : null_payto_uri,
119 : account_id,
120 : GNUNET_TIME_timestamp_get (),
121 : apr->details.success.expiration_time,
122 10 : apr->details.success.account_properties,
123 10 : apr->details.success.new_rules,
124 10 : apr->details.success.to_investigate,
125 10 : apr->details.success.new_measures,
126 : jmeasures,
127 : NULL, /* justification */
128 : NULL, /* decider_pub */
129 : NULL, /* decider_sig */
130 10 : apr->details.success.num_events,
131 10 : apr->details.success.events,
132 : NULL, /* form ID */
133 : 0, /* enc_attributes_size*/
134 : NULL, /* enc_attributes*/
135 : NULL, /* attributes_hash */
136 10 : GNUNET_TIME_UNIT_ZERO_TS, /* attributes_expiration_time */
137 : &invalid_officer,
138 : &unknown_account,
139 : &last_date,
140 : &legitimization_measure_serial_id,
141 : &is_wallet);
142 10 : GNUNET_break (qs > 0);
143 10 : goto cleanup;
144 : }
145 : }
146 0 : GNUNET_break (0);
147 0 : qs = GNUNET_DB_STATUS_HARD_ERROR;
148 10 : cleanup:
149 10 : TALER_KYCLOGIC_rules_free (lrs);
150 10 : json_decref (jmeasures);
151 10 : return qs;
152 : }
153 :
154 :
155 : struct TALER_EXCHANGEDB_RuleUpdater
156 : {
157 : /**
158 : * database plugin to use
159 : */
160 : struct TALER_EXCHANGEDB_Plugin *plugin;
161 :
162 : /**
163 : * key to use to decrypt attributes
164 : */
165 : struct TALER_AttributeEncryptionKeyP attribute_key;
166 :
167 : /**
168 : * account to get the rule set for
169 : */
170 : struct TALER_NormalizedPaytoHashP account;
171 :
172 : /**
173 : * function to call with the result
174 : */
175 : TALER_EXCHANGEDB_CurrentRulesCallback cb;
176 :
177 : /**
178 : * Closure for @e cb.
179 : */
180 : void *cb_cls;
181 :
182 : /**
183 : * Current rule set we are working on.
184 : */
185 : struct TALER_KYCLOGIC_LegitimizationRuleSet *lrs;
186 :
187 : /**
188 : * Task for asynchronous continuations.
189 : */
190 : struct GNUNET_SCHEDULER_Task *t;
191 :
192 : /**
193 : * Handler waiting notification that (previous) AML program
194 : * finished.
195 : */
196 : struct GNUNET_DB_EventHandler *eh;
197 :
198 : /**
199 : * Handle to running AML program.
200 : */
201 : struct TALER_KYCLOGIC_AmlProgramRunnerHandle *amlh;
202 :
203 : /**
204 : * Name of the AML program we were running asynchronously,
205 : * for diagnostics.
206 : */
207 : char *aml_program_name;
208 :
209 : /**
210 : * Error hint to return with @e ec.
211 : */
212 : const char *hint;
213 :
214 : /**
215 : * Row the rule set in @a lrs is based on.
216 : */
217 : uint64_t legitimization_outcome_last_row;
218 :
219 : /**
220 : * Taler error code to return.
221 : */
222 : enum TALER_ErrorCode ec;
223 :
224 : /**
225 : * Counter used to limit recursion depth.
226 : */
227 : unsigned int depth;
228 :
229 : /**
230 : * True if @e account is for a wallet.
231 : */
232 : bool is_wallet;
233 : };
234 :
235 :
236 : /**
237 : * Function that finally returns the result to the application and cleans
238 : * up. Called with an open database transaction on success; on failure, the
239 : * transaction will have already been rolled back.
240 : *
241 : * @param[in,out] ru rule updater to return result for
242 : */
243 : static void
244 28 : return_result (struct TALER_EXCHANGEDB_RuleUpdater *ru)
245 : {
246 28 : struct TALER_EXCHANGEDB_RuleUpdaterResult rur = {
247 28 : .legitimization_outcome_last_row = ru->legitimization_outcome_last_row,
248 28 : .lrs = ru->lrs,
249 28 : .ec = ru->ec,
250 : };
251 :
252 28 : ru->cb (ru->cb_cls,
253 : &rur);
254 28 : ru->lrs = NULL;
255 28 : TALER_EXCHANGEDB_update_rules_cancel (ru);
256 28 : }
257 :
258 :
259 : /**
260 : * Fail the update with the given @a ec and @a hint.
261 : * Called with an open database transaction, which will
262 : * be rolled back (!).
263 : *
264 : * @param[in,out] ru account we are processing
265 : * @param ec error code to fail with
266 : * @param hint hint to return, can be NULL
267 : */
268 : static void
269 0 : fail_update (struct TALER_EXCHANGEDB_RuleUpdater *ru,
270 : enum TALER_ErrorCode ec,
271 : const char *hint)
272 : {
273 0 : GNUNET_assert (NULL == ru->t);
274 0 : ru->plugin->rollback (ru->plugin->cls);
275 0 : ru->ec = ec;
276 0 : ru->hint = hint;
277 0 : return_result (ru);
278 0 : }
279 :
280 :
281 : /**
282 : * Check the rules in @a ru to see if they are current, and
283 : * if not begin the updating process. Called with an open
284 : * database transaction.
285 : *
286 : * @param[in] ru rule updater context
287 : */
288 : static void
289 : check_rules (struct TALER_EXCHANGEDB_RuleUpdater *ru);
290 :
291 :
292 : /**
293 : * Run the measure @a m in the context of the legitimisation rules
294 : * of @a ru. Called with an open database transaction.
295 : *
296 : * @param ru updating context we are using
297 : * @param m measure we need to run next
298 : */
299 : static void
300 : run_measure (struct TALER_EXCHANGEDB_RuleUpdater *ru,
301 : const struct TALER_KYCLOGIC_Measure *m);
302 :
303 :
304 : /**
305 : * Function called after AML program was run. Called
306 : * without an open database transaction, will start one!
307 : *
308 : * @param cls the `struct TALER_EXCHANGEDB_RuleUpdater *`
309 : * @param apr result of the AML program.
310 : */
311 : static void
312 0 : aml_result_callback (
313 : void *cls,
314 : const struct TALER_KYCLOGIC_AmlProgramResult *apr)
315 : {
316 0 : struct TALER_EXCHANGEDB_RuleUpdater *ru = cls;
317 : enum GNUNET_DB_QueryStatus qs;
318 : enum GNUNET_GenericReturnValue res;
319 : enum TALER_EXCHANGEDB_PersistProgramResultStatus pprs;
320 :
321 0 : ru->amlh = NULL;
322 0 : res = ru->plugin->start (ru->plugin->cls,
323 : "aml-persist-aml-program-result");
324 0 : if (GNUNET_OK != res)
325 : {
326 0 : GNUNET_break (0);
327 0 : fail_update (ru,
328 : TALER_EC_GENERIC_DB_START_FAILED,
329 : "aml-persist-aml-program-result");
330 0 : return;
331 : }
332 : /* Update database update based on result */
333 0 : qs = TALER_EXCHANGEDB_persist_aml_program_result (
334 : ru->plugin,
335 : 0LLU, /* 0: no existing legitimization process, creates new row */
336 0 : &ru->account,
337 : apr,
338 : &pprs);
339 0 : switch (qs)
340 : {
341 0 : case GNUNET_DB_STATUS_HARD_ERROR:
342 0 : GNUNET_break (0);
343 0 : fail_update (ru,
344 : TALER_EC_GENERIC_DB_STORE_FAILED,
345 : "persist_aml_program_result");
346 0 : return;
347 0 : case GNUNET_DB_STATUS_SOFT_ERROR:
348 : /* Bad, couldn't persist AML result. Try again... */
349 0 : GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
350 : "Serialization issue persisting result of AML program. Restarting.\n");
351 0 : fail_update (ru,
352 : TALER_EC_GENERIC_DB_SOFT_FAILURE,
353 : "persist_aml_program_result");
354 0 : return;
355 0 : case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
356 : /* Strange, but let's just continue */
357 0 : break;
358 0 : case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
359 : /* normal case */
360 0 : break;
361 : }
362 0 : switch (pprs)
363 : {
364 0 : case TALER_EXCHANGEDB_PPRS_OK:
365 0 : break;
366 0 : case TALER_EXCHANGEDB_PPRS_BAD_OUTCOME:
367 0 : fail_update (ru,
368 : TALER_EC_EXCHANGE_KYC_AML_PROGRAM_MALFORMED_RESULT,
369 : "persist_aml_program_result");
370 0 : return;
371 : }
372 0 : switch (apr->status)
373 : {
374 0 : case TALER_KYCLOGIC_AMLR_SUCCESS:
375 0 : TALER_KYCLOGIC_rules_free (ru->lrs);
376 0 : ru->lrs = NULL;
377 0 : ru->lrs = TALER_KYCLOGIC_rules_parse (apr->details.success.new_rules);
378 : /* Fall back to default rules on parse error! */
379 0 : GNUNET_break (NULL != ru->lrs);
380 0 : check_rules (ru);
381 0 : return;
382 0 : case TALER_KYCLOGIC_AMLR_FAILURE:
383 : {
384 0 : const char *fmn = apr->details.failure.fallback_measure;
385 : const struct TALER_KYCLOGIC_Measure *m;
386 :
387 0 : m = TALER_KYCLOGIC_get_measure (ru->lrs,
388 : fmn);
389 0 : if (NULL == m)
390 : {
391 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
392 : "Fallback measure `%s' does not exist (anymore?).\n",
393 : fmn);
394 0 : TALER_KYCLOGIC_rules_free (ru->lrs);
395 0 : ru->lrs = NULL;
396 0 : return_result (ru);
397 0 : return;
398 : }
399 0 : run_measure (ru,
400 : m);
401 0 : return;
402 : }
403 : }
404 : /* This should be impossible */
405 0 : GNUNET_assert (0);
406 : }
407 :
408 :
409 : /**
410 : * Entrypoint that fetches the latest rules from the database
411 : * and starts processing them. Called without an open database
412 : * transaction, will start one.
413 : *
414 : * @param[in] cls the `struct TALER_EXCHANGEDB_RuleUpdater *` to run
415 : */
416 : static void
417 : fetch_latest_rules (void *cls);
418 :
419 :
420 : /**
421 : * Notification called when we either timeout on the AML program lock
422 : * or when the (previous) AML program finished and we can thus try again.
423 : *
424 : * @param cls the `struct TALER_EXCHANGEDB_RuleUpdater *` to continue
425 : * @param extra additional event data provided (unused)
426 : * @param extra_size number of bytes in @a extra (unused)
427 : */
428 : static void
429 0 : trigger_fetch_latest_rules (void *cls,
430 : const void *extra,
431 : size_t extra_size)
432 : {
433 0 : struct TALER_EXCHANGEDB_RuleUpdater *ru = cls;
434 :
435 : (void) extra;
436 : (void) extra_size;
437 0 : if (NULL != ru->t)
438 0 : return; /* multiple events triggered us, ignore */
439 0 : ru->t = GNUNET_SCHEDULER_add_now (&fetch_latest_rules,
440 : ru);
441 : }
442 :
443 :
444 : static void
445 0 : run_measure (struct TALER_EXCHANGEDB_RuleUpdater *ru,
446 : const struct TALER_KYCLOGIC_Measure *m)
447 : {
448 0 : if (NULL == m)
449 : {
450 : /* fall back to default rules */
451 0 : TALER_KYCLOGIC_rules_free (ru->lrs);
452 0 : ru->lrs = NULL;
453 0 : return_result (ru);
454 0 : return;
455 : }
456 0 : ru->depth++;
457 0 : if (ru->depth > MAX_DEPTH)
458 : {
459 0 : fail_update (ru,
460 : TALER_EC_EXCHANGE_GENERIC_AML_PROGRAM_RECURSION_DETECTED,
461 : NULL);
462 0 : return;
463 : }
464 0 : if ( (NULL == m->check_name) ||
465 : (0 ==
466 0 : strcasecmp ("SKIP",
467 0 : m->check_name)) )
468 : {
469 0 : struct TALER_EXCHANGEDB_HistoryBuilderContext hbc = {
470 0 : .account = &ru->account,
471 0 : .is_wallet = ru->is_wallet,
472 0 : .db_plugin = ru->plugin,
473 0 : .attribute_key = &ru->attribute_key
474 : };
475 : enum GNUNET_DB_QueryStatus qs;
476 : struct GNUNET_TIME_Absolute xlock;
477 :
478 : /* Free previous one, in case we are iterating... */
479 0 : GNUNET_free (ru->aml_program_name);
480 0 : ru->aml_program_name = GNUNET_strdup (m->prog_name);
481 0 : qs = ru->plugin->set_aml_lock (
482 0 : ru->plugin->cls,
483 0 : &ru->account,
484 0 : GNUNET_TIME_relative_multiply (ru->plugin->max_aml_program_runtime,
485 : 2),
486 : &xlock);
487 0 : if (GNUNET_TIME_absolute_is_future (xlock))
488 : {
489 0 : struct TALER_KycCompletedEventP eh = {
490 0 : .header.size = htons (sizeof (eh)),
491 0 : .header.type = htons (TALER_DBEVENT_EXCHANGE_KYC_COMPLETED),
492 : .h_payto = ru->account
493 : };
494 : /* Wait for either timeout or notification */
495 0 : GNUNET_log (GNUNET_ERROR_TYPE_INFO,
496 : "AML program already running, waiting for it to finish\n");
497 0 : ru->plugin->rollback (ru->plugin->cls);
498 : ru->eh
499 0 : = ru->plugin->event_listen (
500 0 : ru->plugin->cls,
501 : GNUNET_TIME_absolute_get_remaining (xlock),
502 : &eh.header,
503 : &trigger_fetch_latest_rules,
504 : ru);
505 0 : return;
506 : }
507 0 : qs = ru->plugin->commit (ru->plugin->cls);
508 0 : if (qs < 0)
509 : {
510 0 : GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs);
511 0 : fail_update (ru,
512 : GNUNET_DB_STATUS_SOFT_ERROR == qs
513 : ? TALER_EC_GENERIC_DB_SOFT_FAILURE
514 : : TALER_EC_GENERIC_DB_COMMIT_FAILED,
515 : "current-aml-rule-fetch");
516 0 : return;
517 : }
518 0 : GNUNET_log (GNUNET_ERROR_TYPE_INFO,
519 : "Check is of type 'skip', running AML program %s.\n",
520 : m->prog_name);
521 0 : GNUNET_assert (NULL == ru->t);
522 0 : ru->amlh = TALER_KYCLOGIC_run_aml_program3 (
523 0 : ru->is_wallet,
524 : m,
525 : &TALER_EXCHANGEDB_current_attributes_builder,
526 : &hbc,
527 : &TALER_EXCHANGEDB_current_rule_builder,
528 : &hbc,
529 : &TALER_EXCHANGEDB_aml_history_builder,
530 : &hbc,
531 : &TALER_EXCHANGEDB_kyc_history_builder,
532 : &hbc,
533 0 : ru->plugin->max_aml_program_runtime,
534 : &aml_result_callback,
535 : ru);
536 0 : return;
537 : }
538 :
539 : /* User MUST pass interactive check */
540 0 : GNUNET_log (GNUNET_ERROR_TYPE_INFO,
541 : "Measure %s involves check %s\n",
542 : m->measure_name,
543 : m->check_name);
544 : {
545 : /* activate the measure/check */
546 : json_t *succ_jmeasures
547 0 : = TALER_KYCLOGIC_get_jmeasures (
548 0 : ru->lrs,
549 0 : m->measure_name);
550 : bool unknown_account;
551 : struct GNUNET_TIME_Timestamp last_date;
552 : enum GNUNET_DB_QueryStatus qs;
553 :
554 0 : qs = ru->plugin->insert_successor_measure (
555 0 : ru->plugin->cls,
556 0 : &ru->account,
557 : GNUNET_TIME_timestamp_get (),
558 0 : m->measure_name,
559 : succ_jmeasures,
560 : &unknown_account,
561 : &last_date);
562 0 : json_decref (succ_jmeasures);
563 0 : switch (qs)
564 : {
565 0 : case GNUNET_DB_STATUS_SOFT_ERROR:
566 0 : GNUNET_log (
567 : GNUNET_ERROR_TYPE_INFO,
568 : "Serialization issue!\n");
569 0 : fail_update (ru,
570 : TALER_EC_GENERIC_DB_SOFT_FAILURE,
571 : "insert_successor_measure");
572 0 : return;
573 0 : case GNUNET_DB_STATUS_HARD_ERROR:
574 0 : GNUNET_break (0);
575 0 : fail_update (ru,
576 : TALER_EC_GENERIC_DB_STORE_FAILED,
577 : "insert_successor_measure");
578 0 : return;
579 0 : default:
580 0 : break;
581 : }
582 0 : if (unknown_account)
583 : {
584 0 : fail_update (ru,
585 : TALER_EC_EXCHANGE_GENERIC_BANK_ACCOUNT_UNKNOWN,
586 : NULL);
587 0 : return;
588 : }
589 : }
590 : /* The rules remain these rules until the user passes the check */
591 0 : return_result (ru);
592 : }
593 :
594 :
595 : /**
596 : * Update the expired legitimization rules in @a ru, checking for expiration
597 : * first. Called with an open database transaction.
598 : *
599 : * @param[in,out] ru account we are processing
600 : */
601 : static void
602 0 : update_rules (struct TALER_EXCHANGEDB_RuleUpdater *ru)
603 : {
604 : const struct TALER_KYCLOGIC_Measure *m;
605 :
606 0 : GNUNET_assert (NULL != ru->lrs);
607 0 : GNUNET_assert (GNUNET_TIME_absolute_is_past (
608 : TALER_KYCLOGIC_rules_get_expiration (ru->lrs).abs_time));
609 0 : m = TALER_KYCLOGIC_rules_get_successor (ru->lrs);
610 0 : GNUNET_log (GNUNET_ERROR_TYPE_INFO,
611 : "Successor measure is %s.\n",
612 : (NULL != m) ? m->measure_name : "(null)");
613 0 : run_measure (ru,
614 : m);
615 0 : }
616 :
617 :
618 : static void
619 28 : check_rules (struct TALER_EXCHANGEDB_RuleUpdater *ru)
620 : {
621 28 : ru->depth++;
622 28 : if (ru->depth > MAX_DEPTH)
623 : {
624 0 : fail_update (ru,
625 : TALER_EC_EXCHANGE_GENERIC_AML_PROGRAM_RECURSION_DETECTED,
626 : NULL);
627 0 : return;
628 : }
629 28 : if (NULL == ru->lrs)
630 : {
631 : /* return NULL, aka default rules */
632 11 : GNUNET_log (GNUNET_ERROR_TYPE_INFO,
633 : "Default rules apply\n");
634 11 : return_result (ru);
635 11 : return;
636 : }
637 17 : if (! GNUNET_TIME_absolute_is_past
638 17 : (TALER_KYCLOGIC_rules_get_expiration (ru->lrs).abs_time) )
639 : {
640 : /* Rules did not expire, return them! */
641 17 : return_result (ru);
642 17 : return;
643 : }
644 0 : GNUNET_log (GNUNET_ERROR_TYPE_INFO,
645 : "Custom rules expired, updating...\n");
646 0 : update_rules (ru);
647 : }
648 :
649 :
650 : static void
651 28 : fetch_latest_rules (void *cls)
652 : {
653 28 : struct TALER_EXCHANGEDB_RuleUpdater *ru = cls;
654 : enum GNUNET_DB_QueryStatus qs;
655 : json_t *jnew_rules;
656 : enum GNUNET_GenericReturnValue res;
657 :
658 28 : GNUNET_log (GNUNET_ERROR_TYPE_INFO,
659 : "Fetching latest rules.");
660 :
661 28 : ru->t = NULL;
662 28 : if (NULL != ru->eh)
663 : {
664 : /* cancel event listener, if we have one */
665 0 : ru->plugin->event_listen_cancel (ru->plugin->cls,
666 : ru->eh);
667 0 : ru->eh = NULL;
668 : }
669 28 : GNUNET_break (NULL == ru->lrs);
670 28 : res = ru->plugin->start (ru->plugin->cls,
671 : "aml-begin-lookup-rules-by-access-token");
672 28 : if (GNUNET_OK != res)
673 : {
674 0 : GNUNET_break (0);
675 0 : fail_update (ru,
676 : TALER_EC_GENERIC_DB_START_FAILED,
677 : "aml-begin-lookup-rules-by-access-token");
678 0 : return;
679 : }
680 28 : qs = ru->plugin->lookup_rules_by_access_token (
681 28 : ru->plugin->cls,
682 28 : &ru->account,
683 : &jnew_rules,
684 : &ru->legitimization_outcome_last_row);
685 28 : if (qs < 0)
686 : {
687 0 : GNUNET_break (0);
688 0 : fail_update (ru,
689 : TALER_EC_GENERIC_DB_FETCH_FAILED,
690 : "lookup_rules_by_access_token");
691 0 : return;
692 : }
693 28 : if ( (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT == qs) &&
694 17 : (NULL != jnew_rules) )
695 : {
696 17 : ru->lrs = TALER_KYCLOGIC_rules_parse (jnew_rules);
697 17 : GNUNET_break (NULL != ru->lrs);
698 17 : json_decref (jnew_rules);
699 : }
700 28 : check_rules (ru);
701 : }
702 :
703 :
704 : struct TALER_EXCHANGEDB_RuleUpdater *
705 28 : TALER_EXCHANGEDB_update_rules (
706 : struct TALER_EXCHANGEDB_Plugin *plugin,
707 : const struct TALER_AttributeEncryptionKeyP *attribute_key,
708 : const struct TALER_NormalizedPaytoHashP *account,
709 : bool is_wallet,
710 : TALER_EXCHANGEDB_CurrentRulesCallback cb,
711 : void *cb_cls)
712 : {
713 : struct TALER_EXCHANGEDB_RuleUpdater *ru;
714 :
715 28 : ru = GNUNET_new (struct TALER_EXCHANGEDB_RuleUpdater);
716 28 : ru->plugin = plugin;
717 28 : ru->attribute_key = *attribute_key;
718 28 : ru->account = *account;
719 28 : ru->is_wallet = is_wallet;
720 28 : ru->cb = cb;
721 28 : ru->cb_cls = cb_cls;
722 28 : ru->t = GNUNET_SCHEDULER_add_now (&fetch_latest_rules,
723 : ru);
724 28 : return ru;
725 : }
726 :
727 :
728 : void
729 28 : TALER_EXCHANGEDB_update_rules_cancel (
730 : struct TALER_EXCHANGEDB_RuleUpdater *ru)
731 : {
732 28 : if (NULL != ru->t)
733 : {
734 0 : GNUNET_SCHEDULER_cancel (ru->t);
735 0 : ru->t = NULL;
736 : }
737 28 : if (NULL != ru->amlh)
738 : {
739 0 : TALER_KYCLOGIC_run_aml_program_cancel (ru->amlh);
740 0 : ru->amlh = NULL;
741 : }
742 28 : if (NULL != ru->lrs)
743 : {
744 0 : TALER_KYCLOGIC_rules_free (ru->lrs);
745 0 : ru->lrs = NULL;
746 : }
747 28 : if (NULL != ru->eh)
748 : {
749 0 : ru->plugin->event_listen_cancel (ru->plugin->cls,
750 : ru->eh);
751 0 : ru->eh = NULL;
752 : }
753 28 : GNUNET_free (ru->aml_program_name);
754 28 : GNUNET_free (ru);
755 28 : }
|