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 }