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 (10339B)


      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/lookup_aml_history.h"
     26 #include "exchange-database/lookup_kyc_history.h"
     27 #include "exchange-database/get_kyc_rules.h"
     28 #include "exchange-database/select_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_lookup_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_lookup_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_TALER_EXCHANGEDB_get_kyc_rules2 (
    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     break;
    275   }
    276   return jlrs;
    277 }
    278 
    279 
    280 /**
    281  * Closure for decrypt_attributes().
    282  */
    283 struct DecryptContext
    284 {
    285   /**
    286    * Overall context.
    287    */
    288   const struct TALER_EXCHANGEDB_HistoryBuilderContext *hbc;
    289 
    290   /**
    291    * Where to return the attributes.
    292    */
    293   json_t *attr;
    294 };
    295 
    296 
    297 /**
    298  * Decrypt and return AML attribute information.
    299  *
    300  * @param cls a `struct DecryptContext *`
    301  * @param row_id current row in kyc_attributes table
    302  * @param collection_time when were the attributes collected
    303  * @param by_aml_officer true if filed by AML officer
    304  * @param officer_name name of the officer, NULL if not @a by_aml_officer
    305  * @param enc_attributes_size size of @a enc_attributes
    306  * @param enc_attributes the encrypted collected attributes
    307  */
    308 static void
    309 decrypt_attributes (
    310   void *cls,
    311   uint64_t row_id,
    312   struct GNUNET_TIME_Timestamp collection_time,
    313   bool by_aml_officer,
    314   const char *officer_name,
    315   size_t enc_attributes_size,
    316   const void *enc_attributes)
    317 {
    318   struct DecryptContext *decon = cls;
    319 
    320   (void) row_id;
    321   (void) collection_time;
    322   (void) officer_name;
    323   decon->attr
    324     = TALER_CRYPTO_kyc_attributes_decrypt (decon->hbc->attribute_key,
    325                                            enc_attributes,
    326                                            enc_attributes_size);
    327   GNUNET_break (NULL != decon->attr);
    328 }
    329 
    330 
    331 json_t *
    332 TALER_EXCHANGEDB_current_attributes_builder (void *cls)
    333 {
    334   struct TALER_EXCHANGEDB_HistoryBuilderContext *hbc = cls;
    335   const struct TALER_NormalizedPaytoHashP *acc = hbc->account;
    336   enum GNUNET_DB_QueryStatus qs;
    337   struct DecryptContext decon = {
    338     .hbc = hbc
    339   };
    340 
    341   qs = TALER_EXCHANGEDB_select_aml_attributes (
    342     hbc->pg,
    343     acc,
    344     INT64_MAX,
    345     -1, /* we only fetch the latest ones */
    346     &decrypt_attributes,
    347     &decon);
    348   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    349               "select_aml_attributes returned %d\n",
    350               (int) qs);
    351   switch (qs)
    352   {
    353   case GNUNET_DB_STATUS_HARD_ERROR:
    354   case GNUNET_DB_STATUS_SOFT_ERROR:
    355     GNUNET_break (0);
    356     return NULL;
    357   case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
    358     decon.attr = json_object ();
    359     GNUNET_break (NULL != decon.attr);
    360     break;
    361   case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
    362     GNUNET_break (NULL != decon.attr);
    363     break;
    364   }
    365   return decon.attr;
    366 }