exchange

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

exchangedb_history.c (10162B)


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