Line data Source code
1 : /*
2 : This file is part of TALER
3 : Copyright (C) 2026 Taler Systems SA
4 :
5 : TALER is free software; you can redistribute it and/or modify it under the
6 : terms of the GNU 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 General Public License for more details.
12 :
13 : You should have received a copy of the GNU General Public License along with
14 : TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
15 : */
16 : /**
17 : * @file exchangedb/test_kyc_attributes.c
18 : * @brief tests for the exchangedb functions whose primary table is
19 : * `kyc_attributes`
20 : * @author Christian Grothoff
21 : *
22 : * Covers #TALER_EXCHANGEDB_do_insert_kyc_attributes(),
23 : * #TALER_EXCHANGEDB_iterate_kyc_attributes(),
24 : * #TALER_EXCHANGEDB_iterate_unscreened_kyc_attributes(),
25 : * #TALER_EXCHANGEDB_update_to_kyc_attributes_screened(),
26 : * #TALER_EXCHANGEDB_update_to_kyc_attributes_unscreened(),
27 : * #TALER_EXCHANGEDB_iterate_aml_attributes(),
28 : * #TALER_EXCHANGEDB_iterate_kyc_history(),
29 : * #TALER_EXCHANGEDB_kyc_history_builder() and
30 : * #TALER_EXCHANGEDB_current_attributes_builder().
31 : *
32 : * A `kyc_attributes` row is the (encrypted) personal data one KYC process
33 : * collected, so every row needs a `legitimization_processes` row to hang
34 : * off; those in turn need a legitimization measure on a known account.
35 : * That is what setup_account() builds before the first insert. The AML
36 : * officer path is exercised too, because it is the only way to get a row
37 : * with `by_aml_officer` set, which is what the AML attribute iterator
38 : * reports on.
39 : */
40 : #include "test_common.h"
41 : #include "exchange-database/account_history.h"
42 : #include "exchange-database/do_insert_kyc_attributes.h"
43 : #include "exchange-database/do_trigger_kyc_rule_for_account.h"
44 : #include "exchange-database/insert_aml_decision.h"
45 : #include "exchange-database/insert_aml_officer.h"
46 : #include "exchange-database/insert_legitimization_process.h"
47 : #include "exchange-database/iterate_unscreened_kyc_attributes.h"
48 : #include "exchange-database/iterate_aml_attributes.h"
49 : #include "exchange-database/iterate_kyc_attributes.h"
50 : #include "exchange-database/iterate_kyc_history.h"
51 : #include "exchange-database/update_to_kyc_attributes_screened.h"
52 : #include "exchange-database/update_to_kyc_attributes_unscreened.h"
53 :
54 :
55 : /**
56 : * Account the attributes are about.
57 : */
58 : static struct TDB_Account account;
59 :
60 :
61 : /**
62 : * Row of the legitimization measures on @e account.
63 : */
64 : static uint64_t measure_row;
65 :
66 :
67 : /**
68 : * Rows of the two KYC processes we run on @e account.
69 : */
70 : static uint64_t process_row[2];
71 :
72 :
73 : /**
74 : * Key the attributes are encrypted with.
75 : */
76 : static struct TALER_AttributeEncryptionKeyP attribute_key;
77 :
78 :
79 : /**
80 : * Name the AML officer is on file under.
81 : */
82 : #define OFFICER_NAME "Alex Officer"
83 :
84 :
85 : /**
86 : * Build the attribute set of @a name for storage.
87 : *
88 : * @param name value of the NAME attribute
89 : * @param[out] enc set to the encrypted attributes, to be freed by the
90 : * caller
91 : * @param[out] enc_size set to the number of bytes in @a enc
92 : */
93 : static void
94 3 : encrypt_attributes (const char *name,
95 : void **enc,
96 : size_t *enc_size)
97 : {
98 : json_t *attrs;
99 :
100 3 : attrs = GNUNET_JSON_PACK (
101 : GNUNET_JSON_pack_string ("FORM_ID",
102 : "test-form"),
103 : GNUNET_JSON_pack_string ("NAME",
104 : name));
105 3 : GNUNET_assert (NULL != attrs);
106 3 : TALER_CRYPTO_kyc_attributes_encrypt (&attribute_key,
107 : attrs,
108 : enc,
109 : enc_size);
110 3 : json_decref (attrs);
111 3 : }
112 :
113 :
114 : /**
115 : * Closure for the various attribute callbacks.
116 : */
117 : struct AttributeContext
118 : {
119 : /**
120 : * How many rows did the callback see?
121 : */
122 : unsigned int total;
123 :
124 : /**
125 : * Stop after this many rows; 0 for no limit.
126 : */
127 : unsigned int stop_after;
128 :
129 : /**
130 : * Value of the NAME attribute of the last row seen, owned by this
131 : * struct.
132 : */
133 : char *name;
134 :
135 : /**
136 : * Provider of the last row seen, owned by this struct.
137 : */
138 : char *provider;
139 :
140 : /**
141 : * Officer of the last row seen, owned by this struct.
142 : */
143 : char *officer;
144 :
145 : /**
146 : * Row ID of the last row seen.
147 : */
148 : uint64_t row_id;
149 :
150 : /**
151 : * Was the last row filed by an AML officer?
152 : */
153 : bool by_aml_officer;
154 :
155 : /**
156 : * Was the KYC process of the last row finished?
157 : */
158 : bool finished;
159 : };
160 :
161 :
162 : /**
163 : * Release what a `struct AttributeContext` owns.
164 : *
165 : * @param[in,out] ctx context to clean up
166 : */
167 : static void
168 10 : ac_free (struct AttributeContext *ctx)
169 : {
170 10 : GNUNET_free (ctx->name);
171 10 : GNUNET_free (ctx->provider);
172 10 : GNUNET_free (ctx->officer);
173 10 : }
174 :
175 :
176 : /**
177 : * Decrypt @a enc and remember its NAME attribute in @a ctx.
178 : *
179 : * @param[in,out] ctx context to update
180 : * @param enc_size number of bytes in @a enc
181 : * @param enc encrypted attributes
182 : */
183 : static void
184 12 : remember_name (struct AttributeContext *ctx,
185 : size_t enc_size,
186 : const void *enc)
187 : {
188 : json_t *attrs;
189 : const char *name;
190 :
191 12 : GNUNET_free (ctx->name);
192 12 : ctx->name = NULL;
193 12 : attrs = TALER_CRYPTO_kyc_attributes_decrypt (&attribute_key,
194 : enc,
195 : enc_size);
196 12 : if (NULL == attrs)
197 0 : return;
198 12 : name = json_string_value (json_object_get (attrs,
199 : "NAME"));
200 12 : if (NULL != name)
201 12 : ctx->name = GNUNET_strdup (name);
202 12 : json_decref (attrs);
203 : }
204 :
205 :
206 : /**
207 : * Callback for #TALER_EXCHANGEDB_iterate_kyc_attributes().
208 : *
209 : * @param cls a `struct AttributeContext *`
210 : * @param h_payto account the attributes are about
211 : * @param provider_name provider that collected them
212 : * @param collection_time when they were collected
213 : * @param expiration_time when they expire
214 : * @param enc_attributes_size number of bytes in @a enc_attributes
215 : * @param enc_attributes the encrypted attributes
216 : */
217 : static void
218 2 : attribute_cb (void *cls,
219 : const struct TALER_NormalizedPaytoHashP *h_payto,
220 : const char *provider_name,
221 : struct GNUNET_TIME_Timestamp collection_time,
222 : struct GNUNET_TIME_Timestamp expiration_time,
223 : size_t enc_attributes_size,
224 : const void *enc_attributes)
225 : {
226 2 : struct AttributeContext *ctx = cls;
227 :
228 : (void) h_payto;
229 : (void) collection_time;
230 : (void) expiration_time;
231 2 : ctx->total++;
232 2 : GNUNET_free (ctx->provider);
233 2 : ctx->provider = (NULL == provider_name)
234 : ? NULL
235 2 : : GNUNET_strdup (provider_name);
236 2 : remember_name (ctx,
237 : enc_attributes_size,
238 : enc_attributes);
239 2 : }
240 :
241 :
242 : /**
243 : * Callback for #TALER_EXCHANGEDB_iterate_unscreened_kyc_attributes().
244 : *
245 : * @param cls a `struct AttributeContext *`
246 : * @param row_id row of the attributes
247 : * @param h_payto account the attributes are about
248 : * @param provider_name provider that collected them
249 : * @param collection_time when they were collected
250 : * @param expiration_time when they expire
251 : * @param properties properties set for the account
252 : * @param enc_attributes_size number of bytes in @a enc_attributes
253 : * @param enc_attributes the encrypted attributes
254 : * @return true to continue iterating
255 : */
256 : static bool
257 4 : all_attributes_cb (void *cls,
258 : uint64_t row_id,
259 : const struct TALER_NormalizedPaytoHashP *h_payto,
260 : const char *provider_name,
261 : struct GNUNET_TIME_Timestamp collection_time,
262 : struct GNUNET_TIME_Timestamp expiration_time,
263 : const json_t *properties,
264 : size_t enc_attributes_size,
265 : const void *enc_attributes)
266 : {
267 4 : struct AttributeContext *ctx = cls;
268 :
269 : (void) h_payto;
270 : (void) collection_time;
271 : (void) expiration_time;
272 : (void) properties;
273 4 : ctx->total++;
274 4 : ctx->row_id = row_id;
275 4 : GNUNET_free (ctx->provider);
276 4 : ctx->provider = (NULL == provider_name)
277 : ? NULL
278 4 : : GNUNET_strdup (provider_name);
279 4 : remember_name (ctx,
280 : enc_attributes_size,
281 : enc_attributes);
282 5 : return ! ( (0 != ctx->stop_after) &&
283 1 : (ctx->total >= ctx->stop_after) );
284 : }
285 :
286 :
287 : /**
288 : * Callback for #TALER_EXCHANGEDB_iterate_aml_attributes().
289 : *
290 : * @param cls a `struct AttributeContext *`
291 : * @param row_id row of the attributes
292 : * @param collection_time when they were collected
293 : * @param by_aml_officer were they filed by an AML officer
294 : * @param officer_name name of that officer, NULL if none
295 : * @param enc_attributes_size number of bytes in @a enc_attributes
296 : * @param enc_attributes the encrypted attributes
297 : */
298 : static void
299 4 : aml_attribute_cb (void *cls,
300 : uint64_t row_id,
301 : struct GNUNET_TIME_Timestamp collection_time,
302 : bool by_aml_officer,
303 : const char *officer_name,
304 : size_t enc_attributes_size,
305 : const void *enc_attributes)
306 : {
307 4 : struct AttributeContext *ctx = cls;
308 :
309 : (void) collection_time;
310 4 : ctx->total++;
311 4 : ctx->row_id = row_id;
312 4 : ctx->by_aml_officer = by_aml_officer;
313 4 : GNUNET_free (ctx->officer);
314 4 : ctx->officer = (NULL == officer_name)
315 : ? NULL
316 4 : : GNUNET_strdup (officer_name);
317 4 : remember_name (ctx,
318 : enc_attributes_size,
319 : enc_attributes);
320 4 : }
321 :
322 :
323 : /**
324 : * Callback for #TALER_EXCHANGEDB_iterate_kyc_history().
325 : *
326 : * @param cls a `struct AttributeContext *`
327 : * @param provider_name provider that ran the process
328 : * @param finished did the process finish
329 : * @param error_code error the process ran into
330 : * @param error_message message for @a error_code
331 : * @param provider_user_id account ID at the provider
332 : * @param provider_legitimization_id process ID at the provider
333 : * @param collection_time when the data was collected
334 : * @param expiration_time when the data expires
335 : * @param encrypted_attributes_len number of bytes in @a encrypted_attributes
336 : * @param encrypted_attributes the encrypted attributes
337 : */
338 : static void
339 2 : kyc_history_cb (void *cls,
340 : const char *provider_name,
341 : bool finished,
342 : enum TALER_ErrorCode error_code,
343 : const char *error_message,
344 : const char *provider_user_id,
345 : const char *provider_legitimization_id,
346 : struct GNUNET_TIME_Timestamp collection_time,
347 : struct GNUNET_TIME_Absolute expiration_time,
348 : size_t encrypted_attributes_len,
349 : const void *encrypted_attributes)
350 : {
351 2 : struct AttributeContext *ctx = cls;
352 :
353 : (void) error_code;
354 : (void) error_message;
355 : (void) provider_user_id;
356 : (void) provider_legitimization_id;
357 : (void) collection_time;
358 : (void) expiration_time;
359 2 : ctx->total++;
360 2 : ctx->finished = finished;
361 2 : GNUNET_free (ctx->provider);
362 2 : ctx->provider = (NULL == provider_name)
363 : ? NULL
364 2 : : GNUNET_strdup (provider_name);
365 2 : remember_name (ctx,
366 : encrypted_attributes_len,
367 : encrypted_attributes);
368 2 : }
369 :
370 :
371 : /**
372 : * Create the account, put a legitimization measure on it and start the
373 : * two KYC processes the attributes will belong to.
374 : *
375 : * @param pg the database context
376 : */
377 : static void
378 1 : setup_account (struct TALER_EXCHANGEDB_PostgresContext *pg)
379 : {
380 : json_t *jmeasures;
381 : bool bad_kyc_auth;
382 :
383 1 : if (0 != measure_row)
384 0 : return;
385 1 : TDB_FILL (attribute_key,
386 : 42);
387 1 : TDB_account (pg,
388 : 10,
389 : &account);
390 1 : jmeasures = GNUNET_JSON_PACK (
391 : GNUNET_JSON_pack_array_steal (
392 : "measures",
393 : json_pack ("[{s:s,s:s,s:s}]",
394 : "check_name",
395 : "verify-id",
396 : "prog_name",
397 : "skip",
398 : "context",
399 : "none")),
400 : GNUNET_JSON_pack_bool ("is_and_combinator",
401 : true));
402 1 : GNUNET_assert (NULL != jmeasures);
403 1 : GNUNET_assert (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT ==
404 : TALER_EXCHANGEDB_do_trigger_kyc_rule_for_account (
405 : pg,
406 : account.payto,
407 : &account.h_normalized,
408 : NULL,
409 : NULL,
410 : jmeasures,
411 : 1,
412 : &measure_row,
413 : &bad_kyc_auth));
414 1 : json_decref (jmeasures);
415 1 : GNUNET_assert (0 != measure_row);
416 3 : for (unsigned int i = 0; i < 2; i++)
417 : {
418 : char *legi_id;
419 :
420 2 : GNUNET_asprintf (&legi_id,
421 : "legi-%u",
422 : i);
423 2 : GNUNET_assert (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT ==
424 : TALER_EXCHANGEDB_insert_legitimization_process (
425 : pg,
426 : &account.h_normalized,
427 : i,
428 : measure_row,
429 : (0 == i) ? "provider-a" : "provider-b",
430 : "provider-account",
431 : legi_id,
432 : &process_row[i]));
433 2 : GNUNET_free (legi_id);
434 2 : GNUNET_assert (0 != process_row[i]);
435 : }
436 : }
437 :
438 :
439 : /**
440 : * Nothing is known while the table is empty.
441 : *
442 : * @param pg the database context
443 : * @return 0 on success
444 : */
445 : static int
446 1 : check_empty (struct TALER_EXCHANGEDB_PostgresContext *pg)
447 : {
448 1 : struct AttributeContext ctx = { 0 };
449 : struct TALER_EXCHANGEDB_HistoryBuilderContext hbc;
450 : json_t *j;
451 :
452 1 : setup_account (pg);
453 1 : FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
454 : TALER_EXCHANGEDB_iterate_kyc_attributes (pg,
455 : &account.h_normalized,
456 : &attribute_cb,
457 : &ctx));
458 1 : FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
459 : TALER_EXCHANGEDB_iterate_unscreened_kyc_attributes (
460 : pg,
461 : &all_attributes_cb,
462 : &ctx));
463 1 : FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
464 : TALER_EXCHANGEDB_iterate_aml_attributes (pg,
465 : &account.h_normalized,
466 : 0,
467 : 16,
468 : &aml_attribute_cb,
469 : &ctx));
470 1 : FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
471 : TALER_EXCHANGEDB_iterate_kyc_history (pg,
472 : &account.h_normalized,
473 : &kyc_history_cb,
474 : &ctx));
475 1 : FAILIF (0 != ctx.total);
476 :
477 1 : hbc.account = &account.h_normalized;
478 1 : hbc.pg = pg;
479 1 : hbc.attribute_key = &attribute_key;
480 1 : hbc.is_wallet = false;
481 1 : j = TALER_EXCHANGEDB_kyc_history_builder (&hbc);
482 1 : FAILIF (NULL == j);
483 1 : FAILIF_C (0 != json_array_size (j),
484 : json_decref (j));
485 1 : json_decref (j);
486 : /* with no attributes at all, the "current" ones are an empty object */
487 1 : j = TALER_EXCHANGEDB_current_attributes_builder (&hbc);
488 1 : FAILIF (NULL == j);
489 1 : FAILIF_C (! json_is_object (j),
490 : json_decref (j));
491 1 : FAILIF_C (0 != json_object_size (j),
492 : json_decref (j));
493 1 : json_decref (j);
494 1 : return 0;
495 : }
496 :
497 :
498 : /**
499 : * Storing attributes creates the row and finishes the KYC process they
500 : * were collected by.
501 : *
502 : * @param pg the database context
503 : * @return 0 on success
504 : */
505 : static int
506 1 : check_insert (struct TALER_EXCHANGEDB_PostgresContext *pg)
507 : {
508 : void *enc;
509 : size_t enc_size;
510 : enum GNUNET_DB_QueryStatus qs;
511 :
512 1 : encrypt_attributes ("Alice",
513 : &enc,
514 : &enc_size);
515 1 : qs = TALER_EXCHANGEDB_do_insert_kyc_attributes (
516 : pg,
517 : process_row[0],
518 : &account.h_normalized,
519 : "provider-a",
520 : "provider-account",
521 : "legi-0",
522 : 0,
523 : GNUNET_TIME_relative_to_absolute (GNUNET_TIME_UNIT_DAYS),
524 : "test-form",
525 : enc_size,
526 : enc);
527 1 : GNUNET_free (enc);
528 1 : FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != qs);
529 1 : FAILIF (1 != TDB_count (pg,
530 : "FROM kyc_attributes"));
531 1 : FAILIF (1 != TDB_count (pg,
532 : "FROM kyc_attributes"
533 : " WHERE NOT by_aml_officer"
534 : " AND form_name='test-form'"));
535 : /* new attributes still have to be screened against the sanctions list */
536 1 : FAILIF (1 != TDB_count (pg,
537 : "FROM kyc_attributes"
538 : " WHERE NOT screened"));
539 : /* the KYC process the attributes came from is now finished */
540 1 : FAILIF (1 != TDB_count (pg,
541 : "FROM legitimization_processes"
542 : " WHERE legitimization_process_serial_id=%llu"
543 : " AND finished",
544 : (unsigned long long) process_row[0]));
545 : /* ... and the aggregator was told to have another look */
546 1 : FAILIF (0 == TDB_count (pg,
547 : "FROM kyc_alerts"));
548 1 : return 0;
549 : }
550 :
551 :
552 : /**
553 : * Naming a provider that does not own the KYC process stores the
554 : * attributes but leaves the process unfinished.
555 : *
556 : * @param pg the database context
557 : * @return 0 on success
558 : */
559 : static int
560 1 : check_insert_wrong_provider (struct TALER_EXCHANGEDB_PostgresContext *pg)
561 : {
562 : void *enc;
563 : size_t enc_size;
564 : enum GNUNET_DB_QueryStatus qs;
565 :
566 1 : encrypt_attributes ("Bob",
567 : &enc,
568 : &enc_size);
569 1 : qs = TALER_EXCHANGEDB_do_insert_kyc_attributes (
570 : pg,
571 : process_row[1],
572 : &account.h_normalized,
573 : /* process_row[1] belongs to provider-b */
574 : "provider-a",
575 : "provider-account",
576 : "legi-1",
577 : 0,
578 : GNUNET_TIME_relative_to_absolute (GNUNET_TIME_UNIT_DAYS),
579 : NULL,
580 : enc_size,
581 : enc);
582 1 : GNUNET_free (enc);
583 1 : FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != qs);
584 1 : FAILIF (2 != TDB_count (pg,
585 : "FROM kyc_attributes"));
586 : /* the attributes were stored, but the process was not finished; the
587 : stored procedure reports that through out_ok, which the C wrapper
588 : drops on the floor (EDBT-16) */
589 1 : FAILIF (0 != TDB_count (pg,
590 : "FROM legitimization_processes"
591 : " WHERE legitimization_process_serial_id=%llu"
592 : " AND finished",
593 : (unsigned long long) process_row[1]));
594 1 : FAILIF (1 != TDB_count (pg,
595 : "FROM kyc_attributes"
596 : " WHERE form_name IS NULL"));
597 1 : return 0;
598 : }
599 :
600 :
601 : /**
602 : * The per-account and the global iterator both find the stored rows.
603 : *
604 : * @param pg the database context
605 : * @return 0 on success
606 : */
607 : static int
608 1 : check_iterate (struct TALER_EXCHANGEDB_PostgresContext *pg)
609 : {
610 : struct AttributeContext ctx;
611 : struct TALER_NormalizedPaytoHashP other;
612 :
613 1 : memset (&ctx,
614 : 0,
615 : sizeof (ctx));
616 1 : FAILIF (0 >=
617 : TALER_EXCHANGEDB_iterate_kyc_attributes (pg,
618 : &account.h_normalized,
619 : &attribute_cb,
620 : &ctx));
621 1 : FAILIF_C (2 != ctx.total,
622 : ac_free (&ctx));
623 1 : FAILIF_C (NULL == ctx.name,
624 : ac_free (&ctx));
625 1 : ac_free (&ctx);
626 :
627 : /* an account without attributes has none */
628 1 : TDB_FILL (other,
629 : 99);
630 1 : memset (&ctx,
631 : 0,
632 : sizeof (ctx));
633 1 : FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
634 : TALER_EXCHANGEDB_iterate_kyc_attributes (pg,
635 : &other,
636 : &attribute_cb,
637 : &ctx));
638 1 : FAILIF_C (0 != ctx.total,
639 : ac_free (&ctx));
640 1 : ac_free (&ctx);
641 :
642 : /* the unscreened iterator sees both rows, in ascending row order */
643 1 : memset (&ctx,
644 : 0,
645 : sizeof (ctx));
646 1 : FAILIF (0 >=
647 : TALER_EXCHANGEDB_iterate_unscreened_kyc_attributes (
648 : pg,
649 : &all_attributes_cb,
650 : &ctx));
651 1 : FAILIF_C (2 != ctx.total,
652 : ac_free (&ctx));
653 1 : FAILIF_C (0 != strcmp (ctx.name,
654 : "Bob"),
655 : ac_free (&ctx));
656 : {
657 1 : uint64_t first = ctx.row_id - 1;
658 :
659 1 : ac_free (&ctx);
660 : /* ... but no longer the first row once that one is screened */
661 1 : FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
662 : TALER_EXCHANGEDB_update_to_kyc_attributes_screened (
663 : pg,
664 : &account.h_normalized,
665 : first));
666 1 : memset (&ctx,
667 : 0,
668 : sizeof (ctx));
669 1 : FAILIF (0 >=
670 : TALER_EXCHANGEDB_iterate_unscreened_kyc_attributes (
671 : pg,
672 : &all_attributes_cb,
673 : &ctx));
674 1 : FAILIF_C (1 != ctx.total,
675 : ac_free (&ctx));
676 1 : FAILIF_C (first + 1 != ctx.row_id,
677 : ac_free (&ctx));
678 1 : ac_free (&ctx);
679 : /* marking a row under another account does nothing */
680 1 : FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
681 : TALER_EXCHANGEDB_update_to_kyc_attributes_screened (
682 : pg,
683 : &other,
684 : first + 1));
685 : /* with the second row screened as well, nothing is left */
686 1 : FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
687 : TALER_EXCHANGEDB_update_to_kyc_attributes_screened (
688 : pg,
689 : &account.h_normalized,
690 : first + 1));
691 1 : memset (&ctx,
692 : 0,
693 : sizeof (ctx));
694 1 : FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
695 : TALER_EXCHANGEDB_iterate_unscreened_kyc_attributes (
696 : pg,
697 : &all_attributes_cb,
698 : &ctx));
699 1 : FAILIF_C (0 != ctx.total,
700 : ac_free (&ctx));
701 1 : ac_free (&ctx);
702 : /* a new sanctions list makes both rows show up again */
703 1 : FAILIF (2 !=
704 : TALER_EXCHANGEDB_update_to_kyc_attributes_unscreened (pg));
705 1 : FAILIF (2 != TDB_count (pg,
706 : "FROM kyc_attributes"
707 : " WHERE NOT screened"));
708 1 : FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
709 : TALER_EXCHANGEDB_update_to_kyc_attributes_unscreened (pg));
710 : }
711 :
712 : /* a callback that says stop is not called again */
713 1 : memset (&ctx,
714 : 0,
715 : sizeof (ctx));
716 1 : ctx.stop_after = 1;
717 1 : FAILIF (0 >=
718 : TALER_EXCHANGEDB_iterate_unscreened_kyc_attributes (
719 : pg,
720 : &all_attributes_cb,
721 : &ctx));
722 1 : FAILIF_C (1 != ctx.total,
723 : ac_free (&ctx));
724 1 : FAILIF_C (0 != strcmp (ctx.name,
725 : "Alice"),
726 : ac_free (&ctx));
727 1 : ac_free (&ctx);
728 1 : return 0;
729 : }
730 :
731 :
732 : /**
733 : * The KYC history reports the state of the process each set of
734 : * attributes came from.
735 : *
736 : * @param pg the database context
737 : * @return 0 on success
738 : */
739 : static int
740 1 : check_kyc_history (struct TALER_EXCHANGEDB_PostgresContext *pg)
741 : {
742 : struct AttributeContext ctx;
743 1 : struct TALER_EXCHANGEDB_HistoryBuilderContext hbc = {
744 : .account = &account.h_normalized,
745 : .pg = pg,
746 : .attribute_key = &attribute_key,
747 : .is_wallet = false
748 : };
749 : json_t *j;
750 :
751 1 : memset (&ctx,
752 : 0,
753 : sizeof (ctx));
754 1 : FAILIF (0 >=
755 : TALER_EXCHANGEDB_iterate_kyc_history (pg,
756 : &account.h_normalized,
757 : &kyc_history_cb,
758 : &ctx));
759 1 : FAILIF_C (2 != ctx.total,
760 : ac_free (&ctx));
761 1 : ac_free (&ctx);
762 :
763 1 : j = TALER_EXCHANGEDB_kyc_history_builder (&hbc);
764 1 : FAILIF (NULL == j);
765 1 : FAILIF_C (2 != json_array_size (j),
766 : json_decref (j));
767 : {
768 1 : json_t *e = json_array_get (j,
769 : 0);
770 1 : const json_t *attrs = json_object_get (e,
771 : "attributes");
772 :
773 1 : FAILIF_C (NULL == attrs,
774 : json_decref (j));
775 1 : FAILIF_C (NULL == json_object_get (attrs,
776 : "NAME"),
777 : json_decref (j));
778 : }
779 1 : json_decref (j);
780 1 : return 0;
781 : }
782 :
783 :
784 : /**
785 : * Attributes filed by an AML officer are reported as such, together with
786 : * the officer's name.
787 : *
788 : * @param pg the database context
789 : * @return 0 on success
790 : */
791 : static int
792 1 : check_aml_attributes (struct TALER_EXCHANGEDB_PostgresContext *pg)
793 : {
794 : struct TALER_AmlOfficerPublicKeyP officer_pub;
795 : struct TALER_AmlOfficerSignatureP officer_sig;
796 : struct TALER_MasterSignatureP master_sig;
797 : struct GNUNET_TIME_Timestamp previous_change;
798 1 : struct TALER_FullPayto null_payto = { NULL };
799 : struct GNUNET_HashCode attributes_hash;
800 1 : const char *no_events[1] = { NULL };
801 : struct AttributeContext ctx;
802 : json_t *new_rules;
803 : void *enc;
804 : size_t enc_size;
805 : bool invalid_officer;
806 : bool unknown_account;
807 : bool is_wallet;
808 : uint64_t lms;
809 : struct GNUNET_TIME_Timestamp last_date;
810 : enum GNUNET_DB_QueryStatus qs;
811 :
812 1 : TDB_FILL (officer_pub,
813 : 20);
814 1 : TDB_FILL (officer_sig,
815 : 21);
816 1 : TDB_FILL (master_sig,
817 : 22);
818 1 : TDB_FILL (attributes_hash,
819 : 23);
820 1 : FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
821 : TALER_EXCHANGEDB_insert_aml_officer (pg,
822 : &officer_pub,
823 : &master_sig,
824 : OFFICER_NAME,
825 : true,
826 : false,
827 : GNUNET_TIME_timestamp_get (),
828 : &previous_change));
829 1 : encrypt_attributes ("Carol",
830 : &enc,
831 : &enc_size);
832 1 : new_rules = GNUNET_JSON_PACK (
833 : GNUNET_JSON_pack_array_steal ("rules",
834 : json_array ()));
835 1 : GNUNET_assert (NULL != new_rules);
836 1 : qs = TALER_EXCHANGEDB_insert_aml_decision (
837 : pg,
838 : null_payto,
839 : &account.h_normalized,
840 : GNUNET_TIME_timestamp_get (),
841 : GNUNET_TIME_relative_to_timestamp (GNUNET_TIME_UNIT_HOURS),
842 : NULL,
843 : new_rules,
844 : false,
845 : NULL,
846 : NULL,
847 : "collected in person",
848 : &officer_pub,
849 : &officer_sig,
850 : 0,
851 : no_events,
852 : "test-form",
853 : enc_size,
854 : enc,
855 : &attributes_hash,
856 : GNUNET_TIME_relative_to_timestamp (GNUNET_TIME_UNIT_DAYS),
857 : &invalid_officer,
858 : &unknown_account,
859 : &last_date,
860 : &lms,
861 : &is_wallet);
862 1 : json_decref (new_rules);
863 1 : GNUNET_free (enc);
864 1 : FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != qs);
865 1 : FAILIF (invalid_officer);
866 1 : FAILIF (3 != TDB_count (pg,
867 : "FROM kyc_attributes"));
868 1 : FAILIF (1 != TDB_count (pg,
869 : "FROM kyc_attributes"
870 : " WHERE by_aml_officer"));
871 :
872 : /* ascending from the start: all three rows, the officer's last */
873 1 : memset (&ctx,
874 : 0,
875 : sizeof (ctx));
876 1 : FAILIF (0 >=
877 : TALER_EXCHANGEDB_iterate_aml_attributes (pg,
878 : &account.h_normalized,
879 : 0,
880 : 16,
881 : &aml_attribute_cb,
882 : &ctx));
883 1 : FAILIF_C (3 != ctx.total,
884 : ac_free (&ctx));
885 1 : FAILIF_C (! ctx.by_aml_officer,
886 : ac_free (&ctx));
887 1 : FAILIF_C (NULL == ctx.officer,
888 : ac_free (&ctx));
889 1 : FAILIF_C (0 != strcmp (ctx.officer,
890 : OFFICER_NAME),
891 : ac_free (&ctx));
892 1 : FAILIF_C (0 != strcmp (ctx.name,
893 : "Carol"),
894 : ac_free (&ctx));
895 1 : ac_free (&ctx);
896 :
897 : /* descending from the end: only the newest row */
898 1 : memset (&ctx,
899 : 0,
900 : sizeof (ctx));
901 1 : FAILIF (0 >=
902 : TALER_EXCHANGEDB_iterate_aml_attributes (pg,
903 : &account.h_normalized,
904 : INT64_MAX,
905 : -1,
906 : &aml_attribute_cb,
907 : &ctx));
908 1 : FAILIF_C (1 != ctx.total,
909 : ac_free (&ctx));
910 1 : FAILIF_C (! ctx.by_aml_officer,
911 : ac_free (&ctx));
912 1 : ac_free (&ctx);
913 :
914 : /* ascending past the last row: nothing */
915 1 : memset (&ctx,
916 : 0,
917 : sizeof (ctx));
918 1 : FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
919 : TALER_EXCHANGEDB_iterate_aml_attributes (pg,
920 : &account.h_normalized,
921 : INT64_MAX,
922 : 16,
923 : &aml_attribute_cb,
924 : &ctx));
925 1 : FAILIF_C (0 != ctx.total,
926 : ac_free (&ctx));
927 1 : ac_free (&ctx);
928 1 : return 0;
929 : }
930 :
931 :
932 : /**
933 : * The "current attributes" builder returns the newest set, decrypted.
934 : *
935 : * @param pg the database context
936 : * @return 0 on success
937 : */
938 : static int
939 1 : check_current_attributes (struct TALER_EXCHANGEDB_PostgresContext *pg)
940 : {
941 1 : struct TALER_EXCHANGEDB_HistoryBuilderContext hbc = {
942 : .account = &account.h_normalized,
943 : .pg = pg,
944 : .attribute_key = &attribute_key,
945 : .is_wallet = false
946 : };
947 : json_t *j;
948 : const char *name;
949 :
950 1 : j = TALER_EXCHANGEDB_current_attributes_builder (&hbc);
951 1 : FAILIF (NULL == j);
952 1 : name = json_string_value (json_object_get (j,
953 : "NAME"));
954 1 : FAILIF_C (NULL == name,
955 : json_decref (j));
956 1 : FAILIF_C (0 != strcmp (name,
957 : "Carol"),
958 : json_decref (j));
959 1 : json_decref (j);
960 1 : return 0;
961 : }
962 :
963 :
964 : /**
965 : * The checks to run, in order.
966 : */
967 : static const struct TDB_Test tests[] = {
968 : { "kyc-attributes-empty",
969 : &check_empty },
970 : { "kyc-attributes-insert",
971 : &check_insert },
972 : { "kyc-attributes-insert-wrong-provider",
973 : &check_insert_wrong_provider },
974 : { "kyc-attributes-iterate",
975 : &check_iterate },
976 : { "kyc-attributes-kyc-history",
977 : &check_kyc_history },
978 : { "kyc-attributes-aml-attributes",
979 : &check_aml_attributes },
980 : { "kyc-attributes-current-attributes",
981 : &check_current_attributes },
982 : { NULL, NULL }
983 : };
984 :
985 :
986 : int
987 1 : main (int argc,
988 : char *const *argv)
989 : {
990 : int ret;
991 :
992 1 : ret = TDB_main (argc,
993 : argv,
994 : "test-kyc-attributes",
995 : "Tests for the exchangedb `kyc_attributes' table",
996 : tests);
997 1 : TDB_account_free (&account);
998 1 : return ret;
999 : }
1000 :
1001 :
1002 : /* end of test_kyc_attributes.c */
|