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


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