LCOV - code coverage report
Current view: top level - exchangedb - update_rules.c (source / functions) Coverage Total Hit
Test: coverage.info Lines: 25.3 % 217 55
Test Date: 2026-04-14 15:39:31 Functions: 50.0 % 10 5

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

Generated by: LCOV version 2.0-1