exchange

Base system with REST service to issue digital coins, run by the payment service provider
Log | Files | Refs | Submodules | README | LICENSE

account_history.c (10709B)


      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 account_history.c
     18  * @brief helper function to build AML inputs from account histories
     19  * @author Christian Grothoff
     20  */
     21 #include "exchangedb_lib.h"
     22 #include "exchangedb_lib.h"
     23 #include "taler/taler_kyclogic_lib.h"
     24 #include "taler/taler_json_lib.h"
     25 #include "exchange-database/iterate_aml_history.h"
     26 #include "exchange-database/iterate_kyc_history.h"
     27 #include "exchange-database/get_kyc_rules.h"
     28 #include "exchange-database/iterate_aml_attributes.h"
     29 #include "exchange-database/account_history.h"
     30 #include <gnunet/gnunet_common.h>
     31 
     32 /**
     33  * Function called to expand AML history for the account.
     34  *
     35  * @param cls a `json_t *` array to build
     36  * @param outcome_serial_id row ID of the decision
     37  * @param decision_time when was the decision taken
     38  * @param justification what was the given justification
     39  * @param decider_pub which key signed the decision
     40  * @param jproperties what are the new account properties
     41  * @param jnew_rules what are the new account rules
     42  * @param to_investigate should AML staff investigate
     43  *          after the decision
     44  * @param is_active is this the active decision
     45  */
     46 static void
     47 add_aml_history_entry (
     48   void *cls,
     49   uint64_t outcome_serial_id,
     50   struct GNUNET_TIME_Timestamp decision_time,
     51   const char *justification,
     52   const struct TALER_AmlOfficerPublicKeyP *decider_pub,
     53   const json_t *jproperties,
     54   const json_t *jnew_rules,
     55   bool to_investigate,
     56   bool is_active)
     57 {
     58   json_t *aml_history = cls;
     59   json_t *e;
     60 
     61   e = GNUNET_JSON_PACK (
     62     GNUNET_JSON_pack_timestamp ("decision_time",
     63                                 decision_time),
     64     GNUNET_JSON_pack_string ("justification",
     65                              justification),
     66     GNUNET_JSON_pack_data_auto ("decider_pub",
     67                                 decider_pub),
     68     GNUNET_JSON_pack_object_incref ("properties",
     69                                     (json_t *) jproperties),
     70     GNUNET_JSON_pack_object_incref ("new_rules",
     71                                     (json_t *) jnew_rules),
     72     GNUNET_JSON_pack_bool ("to_investigate",
     73                            to_investigate),
     74     GNUNET_JSON_pack_bool ("is_active",
     75                            is_active)
     76     );
     77   GNUNET_assert (0 ==
     78                  json_array_append_new (aml_history,
     79                                         e));
     80 }
     81 
     82 
     83 json_t *
     84 TALER_EXCHANGEDB_aml_history_builder (void *cls)
     85 {
     86   struct TALER_EXCHANGEDB_HistoryBuilderContext *hbc = cls;
     87   const struct TALER_NormalizedPaytoHashP *acc = hbc->account;
     88   enum GNUNET_DB_QueryStatus qs;
     89   json_t *aml_history;
     90 
     91   aml_history = json_array ();
     92   GNUNET_assert (NULL != aml_history);
     93   qs = TALER_EXCHANGEDB_iterate_aml_history (
     94     hbc->pg,
     95     acc,
     96     UINT64_MAX, /* offset */
     97     -16 * 1024,  /* limit: none for all practical purposes (for now) */
     98     &add_aml_history_entry,
     99     aml_history);
    100   switch (qs)
    101   {
    102   case GNUNET_DB_STATUS_HARD_ERROR:
    103   case GNUNET_DB_STATUS_SOFT_ERROR:
    104     GNUNET_break (0);
    105     json_decref (aml_history);
    106     return NULL;
    107   case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
    108     /* empty history is fine! */
    109     break;
    110   case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
    111     break;
    112   }
    113   return aml_history;
    114 }
    115 
    116 
    117 /**
    118  * Closure for #add_kyc_history_entry.
    119  */
    120 struct KycContext
    121 {
    122   /**
    123    * JSON array we are building.
    124    */
    125   json_t *kyc_history;
    126 
    127   /**
    128    * Key to use to decrypt KYC attributes.
    129    */
    130   const struct TALER_AttributeEncryptionKeyP *attribute_key;
    131 };
    132 
    133 
    134 /**
    135  * Function called to expand KYC history for the account.
    136  *
    137  * @param cls a `json_t *` array to build
    138  * @param provider_name name of the KYC provider
    139  *    or NULL for none
    140  * @param finished did the KYC process finish
    141  * @param error_code error code from the KYC process
    142  * @param error_message error message from the KYC process,
    143  *    or NULL for none
    144  * @param provider_user_id user ID at the provider
    145  *    or NULL for none
    146  * @param provider_legitimization_id legitimization process ID at the provider
    147  *    or NULL for none
    148  * @param collection_time when was the data collected
    149  * @param expiration_time when does the collected data expire
    150  * @param encrypted_attributes_len number of bytes in @a encrypted_attributes
    151  * @param encrypted_attributes encrypted KYC attributes
    152  */
    153 static void
    154 add_kyc_history_entry (
    155   void *cls,
    156   const char *provider_name,
    157   bool finished,
    158   enum TALER_ErrorCode error_code,
    159   const char *error_message,
    160   const char *provider_user_id,
    161   const char *provider_legitimization_id,
    162   struct GNUNET_TIME_Timestamp collection_time,
    163   struct GNUNET_TIME_Absolute expiration_time,
    164   size_t encrypted_attributes_len,
    165   const void *encrypted_attributes)
    166 {
    167   struct KycContext *kc = cls;
    168   json_t *kyc_history = kc->kyc_history;
    169   json_t *attributes;
    170   json_t *e;
    171 
    172   attributes = TALER_CRYPTO_kyc_attributes_decrypt (
    173     kc->attribute_key,
    174     encrypted_attributes,
    175     encrypted_attributes_len);
    176   e = GNUNET_JSON_PACK (
    177     GNUNET_JSON_pack_string (
    178       "provider_name",
    179       provider_name),
    180     GNUNET_JSON_pack_bool (
    181       "finished",
    182       finished),
    183     TALER_JSON_pack_ec (error_code),
    184     GNUNET_JSON_pack_allow_null (
    185       GNUNET_JSON_pack_string (
    186         "error_message",
    187         error_message)),
    188     GNUNET_JSON_pack_allow_null (
    189       GNUNET_JSON_pack_string (
    190         "provider_user_id",
    191         provider_user_id)),
    192     GNUNET_JSON_pack_allow_null (
    193       GNUNET_JSON_pack_string (
    194         "provider_legitimization_id",
    195         provider_legitimization_id)),
    196     GNUNET_JSON_pack_allow_null (
    197       GNUNET_JSON_pack_timestamp (
    198         "collection_time",
    199         collection_time)),
    200     GNUNET_JSON_pack_allow_null (
    201       GNUNET_JSON_pack_timestamp (
    202         "expiration_time",
    203         GNUNET_TIME_absolute_to_timestamp (
    204           expiration_time))),
    205     GNUNET_JSON_pack_allow_null (
    206       GNUNET_JSON_pack_object_steal (
    207         "attributes",
    208         attributes))
    209     );
    210 
    211   GNUNET_assert (0 ==
    212                  json_array_append_new (kyc_history,
    213                                         e));
    214 }
    215 
    216 
    217 json_t *
    218 TALER_EXCHANGEDB_kyc_history_builder (void *cls)
    219 {
    220   struct TALER_EXCHANGEDB_HistoryBuilderContext *hbc = cls;
    221   const struct TALER_NormalizedPaytoHashP *acc = hbc->account;
    222   enum GNUNET_DB_QueryStatus qs;
    223   struct KycContext kc = {
    224     .kyc_history = json_array (),
    225     .attribute_key = hbc->attribute_key
    226   };
    227 
    228   GNUNET_assert (NULL != kc.kyc_history);
    229   qs = TALER_EXCHANGEDB_iterate_kyc_history (
    230     hbc->pg,
    231     acc,
    232     &add_kyc_history_entry,
    233     &kc);
    234   switch (qs)
    235   {
    236   case GNUNET_DB_STATUS_HARD_ERROR:
    237   case GNUNET_DB_STATUS_SOFT_ERROR:
    238     GNUNET_break (0);
    239     json_decref (kc.kyc_history);
    240     return NULL;
    241   case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
    242     /* empty history is fine! */
    243     break;
    244   case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
    245     break;
    246   }
    247   return kc.kyc_history;
    248 }
    249 
    250 
    251 json_t *
    252 TALER_EXCHANGEDB_current_rule_builder (void *cls)
    253 {
    254   struct TALER_EXCHANGEDB_HistoryBuilderContext *hbc = cls;
    255   const struct TALER_NormalizedPaytoHashP *acc = hbc->account;
    256   enum GNUNET_DB_QueryStatus qs;
    257   json_t *jlrs;
    258 
    259   qs = TALER_EXCHANGEDB_get_kyc_rules (
    260     hbc->pg,
    261     acc,
    262     &jlrs);
    263   switch (qs)
    264   {
    265   case GNUNET_DB_STATUS_HARD_ERROR:
    266   case GNUNET_DB_STATUS_SOFT_ERROR:
    267     GNUNET_break (0);
    268     return NULL;
    269   case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
    270     jlrs = TALER_KYCLOGIC_get_default_legi_rules (
    271       hbc->is_wallet);
    272     break;
    273   case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
    274     if (NULL == jlrs)
    275     {
    276       /* A NULL rule set means the account is on the exchange's default
    277          rules (see exchange_do_insert_successor_measure), not that it has
    278          no rules at all.  Without this AML programs would be run without
    279          "current_rules" and fail. */
    280       jlrs = TALER_KYCLOGIC_get_default_legi_rules (
    281         hbc->is_wallet);
    282     }
    283     break;
    284   }
    285   return jlrs;
    286 }
    287 
    288 
    289 /**
    290  * Closure for decrypt_attributes().
    291  */
    292 struct DecryptContext
    293 {
    294   /**
    295    * Overall context.
    296    */
    297   const struct TALER_EXCHANGEDB_HistoryBuilderContext *hbc;
    298 
    299   /**
    300    * Where to return the attributes.
    301    */
    302   json_t *attr;
    303 };
    304 
    305 
    306 /**
    307  * Decrypt and return AML attribute information.
    308  *
    309  * @param cls a `struct DecryptContext *`
    310  * @param row_id current row in kyc_attributes table
    311  * @param collection_time when were the attributes collected
    312  * @param by_aml_officer true if filed by AML officer
    313  * @param officer_name name of the officer, NULL if not @a by_aml_officer
    314  * @param enc_attributes_size size of @a enc_attributes
    315  * @param enc_attributes the encrypted collected attributes
    316  */
    317 static void
    318 decrypt_attributes (
    319   void *cls,
    320   uint64_t row_id,
    321   struct GNUNET_TIME_Timestamp collection_time,
    322   bool by_aml_officer,
    323   const char *officer_name,
    324   size_t enc_attributes_size,
    325   const void *enc_attributes)
    326 {
    327   struct DecryptContext *decon = cls;
    328 
    329   (void) row_id;
    330   (void) collection_time;
    331   (void) officer_name;
    332   decon->attr
    333     = TALER_CRYPTO_kyc_attributes_decrypt (decon->hbc->attribute_key,
    334                                            enc_attributes,
    335                                            enc_attributes_size);
    336   GNUNET_break (NULL != decon->attr);
    337 }
    338 
    339 
    340 json_t *
    341 TALER_EXCHANGEDB_current_attributes_builder (void *cls)
    342 {
    343   struct TALER_EXCHANGEDB_HistoryBuilderContext *hbc = cls;
    344   const struct TALER_NormalizedPaytoHashP *acc = hbc->account;
    345   enum GNUNET_DB_QueryStatus qs;
    346   struct DecryptContext decon = {
    347     .hbc = hbc
    348   };
    349 
    350   qs = TALER_EXCHANGEDB_iterate_aml_attributes (
    351     hbc->pg,
    352     acc,
    353     INT64_MAX,
    354     -1, /* we only fetch the latest ones */
    355     &decrypt_attributes,
    356     &decon);
    357   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    358               "select_aml_attributes returned %d\n",
    359               (int) qs);
    360   switch (qs)
    361   {
    362   case GNUNET_DB_STATUS_HARD_ERROR:
    363   case GNUNET_DB_STATUS_SOFT_ERROR:
    364     GNUNET_break (0);
    365     return NULL;
    366   case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
    367     decon.attr = json_object ();
    368     GNUNET_break (NULL != decon.attr);
    369     break;
    370   case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
    371     GNUNET_break (NULL != decon.attr);
    372     break;
    373   }
    374   return decon.attr;
    375 }