test_kyc_attributes.c (30267B)
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 encrypt_attributes (const char *name, 95 void **enc, 96 size_t *enc_size) 97 { 98 json_t *attrs; 99 100 attrs = GNUNET_JSON_PACK ( 101 GNUNET_JSON_pack_string ("FORM_ID", 102 "test-form"), 103 GNUNET_JSON_pack_string ("NAME", 104 name)); 105 GNUNET_assert (NULL != attrs); 106 TALER_CRYPTO_kyc_attributes_encrypt (&attribute_key, 107 attrs, 108 enc, 109 enc_size); 110 json_decref (attrs); 111 } 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 ac_free (struct AttributeContext *ctx) 169 { 170 GNUNET_free (ctx->name); 171 GNUNET_free (ctx->provider); 172 GNUNET_free (ctx->officer); 173 } 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 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 GNUNET_free (ctx->name); 192 ctx->name = NULL; 193 attrs = TALER_CRYPTO_kyc_attributes_decrypt (&attribute_key, 194 enc, 195 enc_size); 196 if (NULL == attrs) 197 return; 198 name = json_string_value (json_object_get (attrs, 199 "NAME")); 200 if (NULL != name) 201 ctx->name = GNUNET_strdup (name); 202 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 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 struct AttributeContext *ctx = cls; 227 228 (void) h_payto; 229 (void) collection_time; 230 (void) expiration_time; 231 ctx->total++; 232 GNUNET_free (ctx->provider); 233 ctx->provider = (NULL == provider_name) 234 ? NULL 235 : GNUNET_strdup (provider_name); 236 remember_name (ctx, 237 enc_attributes_size, 238 enc_attributes); 239 } 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 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 struct AttributeContext *ctx = cls; 268 269 (void) h_payto; 270 (void) collection_time; 271 (void) expiration_time; 272 (void) properties; 273 ctx->total++; 274 ctx->row_id = row_id; 275 GNUNET_free (ctx->provider); 276 ctx->provider = (NULL == provider_name) 277 ? NULL 278 : GNUNET_strdup (provider_name); 279 remember_name (ctx, 280 enc_attributes_size, 281 enc_attributes); 282 return ! ( (0 != ctx->stop_after) && 283 (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 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 struct AttributeContext *ctx = cls; 308 309 (void) collection_time; 310 ctx->total++; 311 ctx->row_id = row_id; 312 ctx->by_aml_officer = by_aml_officer; 313 GNUNET_free (ctx->officer); 314 ctx->officer = (NULL == officer_name) 315 ? NULL 316 : GNUNET_strdup (officer_name); 317 remember_name (ctx, 318 enc_attributes_size, 319 enc_attributes); 320 } 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 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 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 ctx->total++; 360 ctx->finished = finished; 361 GNUNET_free (ctx->provider); 362 ctx->provider = (NULL == provider_name) 363 ? NULL 364 : GNUNET_strdup (provider_name); 365 remember_name (ctx, 366 encrypted_attributes_len, 367 encrypted_attributes); 368 } 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 setup_account (struct TALER_EXCHANGEDB_PostgresContext *pg) 379 { 380 json_t *jmeasures; 381 bool bad_kyc_auth; 382 383 if (0 != measure_row) 384 return; 385 TDB_FILL (attribute_key, 386 42); 387 TDB_account (pg, 388 10, 389 &account); 390 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 GNUNET_assert (NULL != jmeasures); 403 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 json_decref (jmeasures); 415 GNUNET_assert (0 != measure_row); 416 for (unsigned int i = 0; i < 2; i++) 417 { 418 char *legi_id; 419 420 GNUNET_asprintf (&legi_id, 421 "legi-%u", 422 i); 423 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 GNUNET_free (legi_id); 434 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 check_empty (struct TALER_EXCHANGEDB_PostgresContext *pg) 447 { 448 struct AttributeContext ctx = { 0 }; 449 struct TALER_EXCHANGEDB_HistoryBuilderContext hbc; 450 json_t *j; 451 452 setup_account (pg); 453 FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != 454 TALER_EXCHANGEDB_iterate_kyc_attributes (pg, 455 &account.h_normalized, 456 &attribute_cb, 457 &ctx)); 458 FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != 459 TALER_EXCHANGEDB_iterate_unscreened_kyc_attributes ( 460 pg, 461 &all_attributes_cb, 462 &ctx)); 463 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 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 FAILIF (0 != ctx.total); 476 477 hbc.account = &account.h_normalized; 478 hbc.pg = pg; 479 hbc.attribute_key = &attribute_key; 480 hbc.is_wallet = false; 481 j = TALER_EXCHANGEDB_kyc_history_builder (&hbc); 482 FAILIF (NULL == j); 483 FAILIF_C (0 != json_array_size (j), 484 json_decref (j)); 485 json_decref (j); 486 /* with no attributes at all, the "current" ones are an empty object */ 487 j = TALER_EXCHANGEDB_current_attributes_builder (&hbc); 488 FAILIF (NULL == j); 489 FAILIF_C (! json_is_object (j), 490 json_decref (j)); 491 FAILIF_C (0 != json_object_size (j), 492 json_decref (j)); 493 json_decref (j); 494 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 check_insert (struct TALER_EXCHANGEDB_PostgresContext *pg) 507 { 508 void *enc; 509 size_t enc_size; 510 enum GNUNET_DB_QueryStatus qs; 511 512 encrypt_attributes ("Alice", 513 &enc, 514 &enc_size); 515 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 GNUNET_free (enc); 528 FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != qs); 529 FAILIF (1 != TDB_count (pg, 530 "FROM kyc_attributes")); 531 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 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 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 FAILIF (0 == TDB_count (pg, 547 "FROM kyc_alerts")); 548 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 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 encrypt_attributes ("Bob", 567 &enc, 568 &enc_size); 569 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 GNUNET_free (enc); 583 FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != qs); 584 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 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 FAILIF (1 != TDB_count (pg, 595 "FROM kyc_attributes" 596 " WHERE form_name IS NULL")); 597 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 check_iterate (struct TALER_EXCHANGEDB_PostgresContext *pg) 609 { 610 struct AttributeContext ctx; 611 struct TALER_NormalizedPaytoHashP other; 612 613 memset (&ctx, 614 0, 615 sizeof (ctx)); 616 FAILIF (0 >= 617 TALER_EXCHANGEDB_iterate_kyc_attributes (pg, 618 &account.h_normalized, 619 &attribute_cb, 620 &ctx)); 621 FAILIF_C (2 != ctx.total, 622 ac_free (&ctx)); 623 FAILIF_C (NULL == ctx.name, 624 ac_free (&ctx)); 625 ac_free (&ctx); 626 627 /* an account without attributes has none */ 628 TDB_FILL (other, 629 99); 630 memset (&ctx, 631 0, 632 sizeof (ctx)); 633 FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != 634 TALER_EXCHANGEDB_iterate_kyc_attributes (pg, 635 &other, 636 &attribute_cb, 637 &ctx)); 638 FAILIF_C (0 != ctx.total, 639 ac_free (&ctx)); 640 ac_free (&ctx); 641 642 /* the unscreened iterator sees both rows, in ascending row order */ 643 memset (&ctx, 644 0, 645 sizeof (ctx)); 646 FAILIF (0 >= 647 TALER_EXCHANGEDB_iterate_unscreened_kyc_attributes ( 648 pg, 649 &all_attributes_cb, 650 &ctx)); 651 FAILIF_C (2 != ctx.total, 652 ac_free (&ctx)); 653 FAILIF_C (0 != strcmp (ctx.name, 654 "Bob"), 655 ac_free (&ctx)); 656 { 657 uint64_t first = ctx.row_id - 1; 658 659 ac_free (&ctx); 660 /* ... but no longer the first row once that one is screened */ 661 FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != 662 TALER_EXCHANGEDB_update_to_kyc_attributes_screened ( 663 pg, 664 &account.h_normalized, 665 first)); 666 memset (&ctx, 667 0, 668 sizeof (ctx)); 669 FAILIF (0 >= 670 TALER_EXCHANGEDB_iterate_unscreened_kyc_attributes ( 671 pg, 672 &all_attributes_cb, 673 &ctx)); 674 FAILIF_C (1 != ctx.total, 675 ac_free (&ctx)); 676 FAILIF_C (first + 1 != ctx.row_id, 677 ac_free (&ctx)); 678 ac_free (&ctx); 679 /* marking a row under another account does nothing */ 680 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 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 memset (&ctx, 692 0, 693 sizeof (ctx)); 694 FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != 695 TALER_EXCHANGEDB_iterate_unscreened_kyc_attributes ( 696 pg, 697 &all_attributes_cb, 698 &ctx)); 699 FAILIF_C (0 != ctx.total, 700 ac_free (&ctx)); 701 ac_free (&ctx); 702 /* a new sanctions list makes both rows show up again */ 703 FAILIF (2 != 704 TALER_EXCHANGEDB_update_to_kyc_attributes_unscreened (pg)); 705 FAILIF (2 != TDB_count (pg, 706 "FROM kyc_attributes" 707 " WHERE NOT screened")); 708 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 memset (&ctx, 714 0, 715 sizeof (ctx)); 716 ctx.stop_after = 1; 717 FAILIF (0 >= 718 TALER_EXCHANGEDB_iterate_unscreened_kyc_attributes ( 719 pg, 720 &all_attributes_cb, 721 &ctx)); 722 FAILIF_C (1 != ctx.total, 723 ac_free (&ctx)); 724 FAILIF_C (0 != strcmp (ctx.name, 725 "Alice"), 726 ac_free (&ctx)); 727 ac_free (&ctx); 728 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 check_kyc_history (struct TALER_EXCHANGEDB_PostgresContext *pg) 741 { 742 struct AttributeContext ctx; 743 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 memset (&ctx, 752 0, 753 sizeof (ctx)); 754 FAILIF (0 >= 755 TALER_EXCHANGEDB_iterate_kyc_history (pg, 756 &account.h_normalized, 757 &kyc_history_cb, 758 &ctx)); 759 FAILIF_C (2 != ctx.total, 760 ac_free (&ctx)); 761 ac_free (&ctx); 762 763 j = TALER_EXCHANGEDB_kyc_history_builder (&hbc); 764 FAILIF (NULL == j); 765 FAILIF_C (2 != json_array_size (j), 766 json_decref (j)); 767 { 768 json_t *e = json_array_get (j, 769 0); 770 const json_t *attrs = json_object_get (e, 771 "attributes"); 772 773 FAILIF_C (NULL == attrs, 774 json_decref (j)); 775 FAILIF_C (NULL == json_object_get (attrs, 776 "NAME"), 777 json_decref (j)); 778 } 779 json_decref (j); 780 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 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 struct TALER_FullPayto null_payto = { NULL }; 799 struct GNUNET_HashCode attributes_hash; 800 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 TDB_FILL (officer_pub, 813 20); 814 TDB_FILL (officer_sig, 815 21); 816 TDB_FILL (master_sig, 817 22); 818 TDB_FILL (attributes_hash, 819 23); 820 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 encrypt_attributes ("Carol", 830 &enc, 831 &enc_size); 832 new_rules = GNUNET_JSON_PACK ( 833 GNUNET_JSON_pack_array_steal ("rules", 834 json_array ())); 835 GNUNET_assert (NULL != new_rules); 836 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 json_decref (new_rules); 863 GNUNET_free (enc); 864 FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != qs); 865 FAILIF (invalid_officer); 866 FAILIF (3 != TDB_count (pg, 867 "FROM kyc_attributes")); 868 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 memset (&ctx, 874 0, 875 sizeof (ctx)); 876 FAILIF (0 >= 877 TALER_EXCHANGEDB_iterate_aml_attributes (pg, 878 &account.h_normalized, 879 0, 880 16, 881 &aml_attribute_cb, 882 &ctx)); 883 FAILIF_C (3 != ctx.total, 884 ac_free (&ctx)); 885 FAILIF_C (! ctx.by_aml_officer, 886 ac_free (&ctx)); 887 FAILIF_C (NULL == ctx.officer, 888 ac_free (&ctx)); 889 FAILIF_C (0 != strcmp (ctx.officer, 890 OFFICER_NAME), 891 ac_free (&ctx)); 892 FAILIF_C (0 != strcmp (ctx.name, 893 "Carol"), 894 ac_free (&ctx)); 895 ac_free (&ctx); 896 897 /* descending from the end: only the newest row */ 898 memset (&ctx, 899 0, 900 sizeof (ctx)); 901 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 FAILIF_C (1 != ctx.total, 909 ac_free (&ctx)); 910 FAILIF_C (! ctx.by_aml_officer, 911 ac_free (&ctx)); 912 ac_free (&ctx); 913 914 /* ascending past the last row: nothing */ 915 memset (&ctx, 916 0, 917 sizeof (ctx)); 918 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 FAILIF_C (0 != ctx.total, 926 ac_free (&ctx)); 927 ac_free (&ctx); 928 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 check_current_attributes (struct TALER_EXCHANGEDB_PostgresContext *pg) 940 { 941 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 j = TALER_EXCHANGEDB_current_attributes_builder (&hbc); 951 FAILIF (NULL == j); 952 name = json_string_value (json_object_get (j, 953 "NAME")); 954 FAILIF_C (NULL == name, 955 json_decref (j)); 956 FAILIF_C (0 != strcmp (name, 957 "Carol"), 958 json_decref (j)); 959 json_decref (j); 960 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 main (int argc, 988 char *const *argv) 989 { 990 int ret; 991 992 ret = TDB_main (argc, 993 argv, 994 "test-kyc-attributes", 995 "Tests for the exchangedb `kyc_attributes' table", 996 tests); 997 TDB_account_free (&account); 998 return ret; 999 } 1000 1001 1002 /* end of test_kyc_attributes.c */