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 }