Line data Source code
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 2 : 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 2 : json_t *aml_history = cls;
59 : json_t *e;
60 :
61 2 : 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 2 : GNUNET_assert (0 ==
80 : json_array_append_new (aml_history,
81 : e));
82 2 : }
83 :
84 :
85 : json_t *
86 1 : TALER_EXCHANGEDB_aml_history_builder (void *cls)
87 : {
88 1 : struct TALER_EXCHANGEDB_HistoryBuilderContext *hbc = cls;
89 1 : const struct TALER_NormalizedPaytoHashP *acc = hbc->account;
90 : enum GNUNET_DB_QueryStatus qs;
91 : json_t *aml_history;
92 :
93 1 : aml_history = json_array ();
94 1 : GNUNET_assert (NULL != aml_history);
95 1 : 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 1 : switch (qs)
105 : {
106 0 : case GNUNET_DB_STATUS_HARD_ERROR:
107 : case GNUNET_DB_STATUS_SOFT_ERROR:
108 0 : GNUNET_break (0);
109 0 : json_decref (aml_history);
110 0 : return NULL;
111 0 : case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
112 : /* empty history is fine! */
113 0 : break;
114 0 : case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
115 0 : break;
116 : }
117 1 : 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 2 : 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 2 : struct KycContext *kc = cls;
172 2 : json_t *kyc_history = kc->kyc_history;
173 : json_t *attributes;
174 : json_t *e;
175 :
176 2 : attributes = TALER_CRYPTO_kyc_attributes_decrypt (
177 : kc->attribute_key,
178 : encrypted_attributes,
179 : encrypted_attributes_len);
180 2 : 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 2 : GNUNET_assert (0 ==
216 : json_array_append_new (kyc_history,
217 : e));
218 2 : }
219 :
220 :
221 : json_t *
222 2 : TALER_EXCHANGEDB_kyc_history_builder (void *cls)
223 : {
224 2 : struct TALER_EXCHANGEDB_HistoryBuilderContext *hbc = cls;
225 2 : const struct TALER_NormalizedPaytoHashP *acc = hbc->account;
226 : enum GNUNET_DB_QueryStatus qs;
227 2 : struct KycContext kc = {
228 2 : .kyc_history = json_array (),
229 2 : .attribute_key = hbc->attribute_key
230 : };
231 :
232 2 : GNUNET_assert (NULL != kc.kyc_history);
233 2 : qs = TALER_EXCHANGEDB_iterate_kyc_history (
234 : hbc->pg,
235 : acc,
236 : &add_kyc_history_entry,
237 : &kc);
238 2 : switch (qs)
239 : {
240 0 : case GNUNET_DB_STATUS_HARD_ERROR:
241 : case GNUNET_DB_STATUS_SOFT_ERROR:
242 0 : GNUNET_break (0);
243 0 : json_decref (kc.kyc_history);
244 0 : return NULL;
245 1 : case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
246 : /* empty history is fine! */
247 1 : break;
248 0 : case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
249 0 : break;
250 : }
251 2 : return kc.kyc_history;
252 : }
253 :
254 :
255 : json_t *
256 1 : TALER_EXCHANGEDB_current_rule_builder (void *cls)
257 : {
258 1 : struct TALER_EXCHANGEDB_HistoryBuilderContext *hbc = cls;
259 1 : const struct TALER_NormalizedPaytoHashP *acc = hbc->account;
260 : enum GNUNET_DB_QueryStatus qs;
261 : json_t *jlrs;
262 :
263 1 : qs = TALER_EXCHANGEDB_get_kyc_rules (
264 : hbc->pg,
265 : acc,
266 : &jlrs);
267 1 : switch (qs)
268 : {
269 0 : case GNUNET_DB_STATUS_HARD_ERROR:
270 : case GNUNET_DB_STATUS_SOFT_ERROR:
271 0 : GNUNET_break (0);
272 0 : return NULL;
273 0 : case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
274 0 : jlrs = TALER_KYCLOGIC_get_default_legi_rules (
275 0 : hbc->is_wallet);
276 0 : break;
277 1 : case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
278 1 : 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 0 : jlrs = TALER_KYCLOGIC_get_default_legi_rules (
285 0 : hbc->is_wallet);
286 : }
287 1 : break;
288 : }
289 1 : 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 11 : 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 11 : struct DecryptContext *decon = cls;
332 :
333 : (void) row_id;
334 : (void) collection_time;
335 : (void) officer_name;
336 : decon->attr
337 11 : = TALER_CRYPTO_kyc_attributes_decrypt (decon->hbc->attribute_key,
338 : enc_attributes,
339 : enc_attributes_size);
340 11 : GNUNET_break (NULL != decon->attr);
341 11 : }
342 :
343 :
344 : json_t *
345 12 : TALER_EXCHANGEDB_current_attributes_builder (void *cls)
346 : {
347 12 : struct TALER_EXCHANGEDB_HistoryBuilderContext *hbc = cls;
348 12 : const struct TALER_NormalizedPaytoHashP *acc = hbc->account;
349 : enum GNUNET_DB_QueryStatus qs;
350 12 : struct DecryptContext decon = {
351 : .hbc = hbc
352 : };
353 :
354 12 : 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 12 : GNUNET_log (GNUNET_ERROR_TYPE_INFO,
362 : "select_aml_attributes returned %d\n",
363 : (int) qs);
364 12 : switch (qs)
365 : {
366 0 : case GNUNET_DB_STATUS_HARD_ERROR:
367 : case GNUNET_DB_STATUS_SOFT_ERROR:
368 0 : GNUNET_break (0);
369 0 : return NULL;
370 1 : case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
371 1 : decon.attr = json_object ();
372 1 : GNUNET_break (NULL != decon.attr);
373 1 : break;
374 11 : case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
375 11 : GNUNET_break (NULL != decon.attr);
376 11 : break;
377 : }
378 12 : return decon.attr;
379 : }
|