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 }