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