json_helper.c (63842B)
1 /* 2 This file is part of TALER 3 Copyright (C) 2014-2023 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 json/json_helper.c 18 * @brief helper functions to generate specifications to parse 19 * Taler-specific JSON objects with libgnunetjson 20 * @author Sree Harsha Totakura <sreeharsha@totakura.in> 21 * @author Christian Grothoff 22 */ 23 #include <gnunet/gnunet_util_lib.h> 24 #include "taler/taler_util.h" 25 #include "taler/taler_json_lib.h" 26 27 28 /** 29 * Convert string value to numeric cipher value. 30 * 31 * @param cipher_s input string 32 * @return numeric cipher value 33 */ 34 static enum GNUNET_CRYPTO_BlindSignatureAlgorithm 35 string_to_cipher (const char *cipher_s) 36 { 37 if ((0 == strcasecmp (cipher_s, 38 "RSA")) || 39 (0 == strcasecmp (cipher_s, 40 "RSA+age_restricted"))) 41 return GNUNET_CRYPTO_BSA_RSA; 42 if ((0 == strcasecmp (cipher_s, 43 "CS")) || 44 (0 == strcasecmp (cipher_s, 45 "CS+age_restricted"))) 46 return GNUNET_CRYPTO_BSA_CS; 47 return GNUNET_CRYPTO_BSA_INVALID; 48 } 49 50 51 json_t * 52 TALER_JSON_from_amount (const struct TALER_Amount *amount) 53 { 54 char *amount_str = TALER_amount_to_string (amount); 55 56 GNUNET_assert (NULL != amount_str); 57 { 58 json_t *j = json_string (amount_str); 59 60 GNUNET_free (amount_str); 61 return j; 62 } 63 } 64 65 66 /** 67 * Parse given JSON object to Amount 68 * 69 * @param cls closure, expected currency, or NULL 70 * @param root the json object representing data 71 * @param[out] spec where to write the data 72 * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error 73 */ 74 static enum GNUNET_GenericReturnValue 75 parse_amount (void *cls, 76 json_t *root, 77 struct GNUNET_JSON_Specification *spec) 78 { 79 const char *currency = cls; 80 struct TALER_Amount *r_amount = spec->ptr; 81 82 (void) cls; 83 if (! json_is_string (root)) 84 { 85 GNUNET_break_op (0); 86 return GNUNET_SYSERR; 87 } 88 if (GNUNET_OK != 89 TALER_string_to_amount (json_string_value (root), 90 r_amount)) 91 { 92 GNUNET_break_op (0); 93 return GNUNET_SYSERR; 94 } 95 if ( (NULL != currency) && 96 (0 != 97 strcasecmp (currency, 98 r_amount->currency)) ) 99 { 100 GNUNET_break_op (0); 101 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 102 "Expected currency `%s', but amount used currency `%s' in field `%s'\n", 103 currency, 104 r_amount->currency, 105 spec->field); 106 return GNUNET_SYSERR; 107 } 108 return GNUNET_OK; 109 } 110 111 112 struct GNUNET_JSON_Specification 113 TALER_JSON_spec_amount (const char *name, 114 const char *currency, 115 struct TALER_Amount *r_amount) 116 { 117 struct GNUNET_JSON_Specification ret = { 118 .parser = &parse_amount, 119 .cleaner = NULL, 120 .cls = (void *) currency, 121 .field = name, 122 .ptr = r_amount, 123 .ptr_size = 0, 124 .size_ptr = NULL 125 }; 126 127 GNUNET_assert (NULL != currency); 128 return ret; 129 } 130 131 132 struct GNUNET_JSON_Specification 133 TALER_JSON_spec_amount_any (const char *name, 134 struct TALER_Amount *r_amount) 135 { 136 struct GNUNET_JSON_Specification ret = { 137 .parser = &parse_amount, 138 .cleaner = NULL, 139 .cls = NULL, 140 .field = name, 141 .ptr = r_amount, 142 .ptr_size = 0, 143 .size_ptr = NULL 144 }; 145 146 return ret; 147 } 148 149 150 /** 151 * Closure for parsing amount arrays. 152 */ 153 struct AmountArrayCtx 154 { 155 /** 156 * Pointer where to store the resulting array length. 157 */ 158 size_t *len; 159 }; 160 161 162 /** 163 * Parse a JSON array of arbitrary amounts. 164 */ 165 static enum GNUNET_GenericReturnValue 166 parse_amount_any_array (void *cls, 167 json_t *root, 168 struct GNUNET_JSON_Specification *spec) 169 { 170 struct AmountArrayCtx *ctx = cls; 171 struct TALER_Amount **out = spec->ptr; 172 173 *out = NULL; 174 if (NULL != ctx->len) 175 *ctx->len = 0; 176 177 if (! json_is_array (root)) 178 { 179 GNUNET_break_op (0); 180 return GNUNET_SYSERR; 181 } 182 183 { 184 size_t len = json_array_size (root); 185 json_t *entry; 186 size_t idx; 187 188 if (NULL != ctx->len) 189 *ctx->len = len; 190 if (0 == len) 191 { 192 *out = NULL; 193 return GNUNET_OK; 194 } 195 *out = GNUNET_new_array (len, 196 struct TALER_Amount); 197 json_array_foreach (root, idx, entry) { 198 const char *amount_str; 199 200 if (! json_is_string (entry)) 201 { 202 GNUNET_break_op (0); 203 return GNUNET_SYSERR; 204 } 205 amount_str = json_string_value (entry); 206 if (GNUNET_OK != 207 TALER_string_to_amount (amount_str, 208 &(*out)[idx])) 209 { 210 GNUNET_break_op (0); 211 return GNUNET_SYSERR; 212 } 213 } 214 } 215 return GNUNET_OK; 216 } 217 218 219 /** 220 * Cleanup helper for the amount array parser. 221 */ 222 static void 223 clean_amount_any_array (void *cls, 224 struct GNUNET_JSON_Specification *spec) 225 { 226 struct AmountArrayCtx *ctx = cls; 227 228 if (NULL != spec->ptr) 229 { 230 GNUNET_free (*(void **) spec->ptr); 231 *(void **) spec->ptr = NULL; 232 } 233 if ( (NULL != ctx) && 234 (NULL != ctx->len) ) 235 *ctx->len = 0; 236 GNUNET_free (ctx); 237 } 238 239 240 struct GNUNET_JSON_Specification 241 TALER_JSON_spec_amount_any_array (const char *field, 242 size_t *amounts_len, 243 struct TALER_Amount **amounts) 244 { 245 struct AmountArrayCtx *ctx; 246 247 GNUNET_assert (NULL != amounts_len); 248 GNUNET_assert (NULL != amounts); 249 *amounts = NULL; 250 *amounts_len = 0; 251 ctx = GNUNET_new (struct AmountArrayCtx); 252 ctx->len = amounts_len; 253 { 254 struct GNUNET_JSON_Specification ret = { 255 .parser = &parse_amount_any_array, 256 .cleaner = &clean_amount_any_array, 257 .cls = ctx, 258 .field = field, 259 .ptr = amounts 260 }; 261 262 return ret; 263 } 264 } 265 266 267 /** 268 * Parse a JSON array of amounts into a price list. 269 * 270 * @param cls closure, NULL 271 * @param root the json array representing the price list 272 * @param[out] spec where to write the data 273 * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error 274 */ 275 static enum GNUNET_GenericReturnValue 276 parse_amount_list (void *cls, 277 json_t *root, 278 struct GNUNET_JSON_Specification *spec) 279 { 280 struct TALER_AmountList *al = spec->ptr; 281 size_t len; 282 json_t *entry; 283 size_t idx; 284 285 (void) cls; 286 al->tal = NULL; 287 al->tal_len = 0; 288 if (! json_is_array (root)) 289 { 290 GNUNET_break_op (0); 291 return GNUNET_SYSERR; 292 } 293 len = json_array_size (root); 294 if (0 == len) 295 return GNUNET_OK; /* empty price list: free */ 296 al->tal = GNUNET_new_array (len, 297 struct TALER_Amount); 298 json_array_foreach (root, idx, entry) 299 { 300 struct TALER_Amount *a = &al->tal[idx]; 301 302 if (! json_is_string (entry)) 303 { 304 GNUNET_break_op (0); 305 TALER_amount_list_free (al); 306 return GNUNET_SYSERR; 307 } 308 if (GNUNET_OK != 309 TALER_string_to_amount (json_string_value (entry), 310 a)) 311 { 312 GNUNET_break_op (0); 313 TALER_amount_list_free (al); 314 return GNUNET_SYSERR; 315 } 316 /* only entries below @a idx are initialized so far, and 317 #TALER_amount_list_find() must not look at the rest */ 318 al->tal_len = idx; 319 if (NULL != 320 TALER_amount_list_find (al, 321 a->currency)) 322 { 323 GNUNET_break_op (0); 324 TALER_amount_list_free (al); 325 return GNUNET_SYSERR; 326 } 327 al->tal_len = idx + 1; 328 } 329 return GNUNET_OK; 330 } 331 332 333 /** 334 * Cleanup helper for the price list parser. 335 * 336 * @param cls closure, NULL 337 * @param[out] spec where to free the data 338 */ 339 static void 340 clean_amount_list (void *cls, 341 struct GNUNET_JSON_Specification *spec) 342 { 343 (void) cls; 344 TALER_amount_list_free (spec->ptr); 345 } 346 347 348 struct GNUNET_JSON_Specification 349 TALER_JSON_spec_amount_list (const char *field, 350 struct TALER_AmountList *al) 351 { 352 struct GNUNET_JSON_Specification ret = { 353 .parser = &parse_amount_list, 354 .cleaner = &clean_amount_list, 355 .cls = NULL, 356 .field = field, 357 .ptr = al 358 }; 359 360 GNUNET_assert (NULL != al); 361 al->tal = NULL; 362 al->tal_len = 0; 363 return ret; 364 } 365 366 367 /** 368 * Parse given JSON object to currency spec. 369 * 370 * @param cls closure, NULL 371 * @param root the json object representing data 372 * @param[out] spec where to write the data 373 * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error 374 */ 375 static enum GNUNET_GenericReturnValue 376 parse_cspec (void *cls, 377 json_t *root, 378 struct GNUNET_JSON_Specification *spec) 379 { 380 struct TALER_CurrencySpecification *r_cspec = spec->ptr; 381 const char *currency = spec->cls; 382 const char *name; 383 uint32_t fid; 384 uint32_t fnd; 385 uint32_t ftzd; 386 const json_t *map; 387 const json_t *ca = NULL; 388 struct GNUNET_JSON_Specification gspec[] = { 389 GNUNET_JSON_spec_string ("name", 390 &name), 391 GNUNET_JSON_spec_uint32 ("num_fractional_input_digits", 392 &fid), 393 GNUNET_JSON_spec_uint32 ("num_fractional_normal_digits", 394 &fnd), 395 GNUNET_JSON_spec_uint32 ("num_fractional_trailing_zero_digits", 396 &ftzd), 397 GNUNET_JSON_spec_object_const ("alt_unit_names", 398 &map), 399 GNUNET_JSON_spec_mark_optional ( 400 GNUNET_JSON_spec_array_const ("common_amounts", 401 &ca), 402 NULL), 403 GNUNET_JSON_spec_end () 404 }; 405 const char *emsg; 406 unsigned int eline; 407 408 memset (r_cspec->currency, 409 0, 410 sizeof (r_cspec->currency)); 411 if (GNUNET_OK != 412 GNUNET_JSON_parse (root, 413 gspec, 414 &emsg, 415 &eline)) 416 { 417 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 418 "Failed to parse %s at %u: %s\n", 419 gspec[eline].field, 420 eline, 421 emsg); 422 GNUNET_break_op (0); 423 return GNUNET_SYSERR; 424 } 425 if (strlen (currency) >= TALER_CURRENCY_LEN) 426 { 427 GNUNET_break_op (0); 428 return GNUNET_SYSERR; 429 } 430 if ( (fid > TALER_AMOUNT_FRAC_LEN) || 431 (fnd > TALER_AMOUNT_FRAC_LEN) || 432 (ftzd > TALER_AMOUNT_FRAC_LEN) ) 433 { 434 GNUNET_break_op (0); 435 return GNUNET_SYSERR; 436 } 437 if (GNUNET_OK != 438 TALER_check_currency (currency)) 439 { 440 GNUNET_break_op (0); 441 return GNUNET_SYSERR; 442 } 443 strcpy (r_cspec->currency, 444 currency); 445 if (GNUNET_OK != 446 TALER_check_currency_scale_map (map)) 447 { 448 GNUNET_break_op (0); 449 return GNUNET_SYSERR; 450 } 451 r_cspec->name = GNUNET_strdup (name); 452 r_cspec->map_alt_unit_names = json_incref ((json_t *) map); 453 if (NULL != ca) 454 { 455 size_t i; 456 json_t *v; 457 458 json_array_foreach ((json_t *) ca, i, v) 459 { 460 struct TALER_Amount val; 461 const char *vstr; 462 463 vstr = json_string_value (v); 464 if ( (NULL == vstr) || 465 (GNUNET_OK != 466 TALER_string_to_amount (vstr, 467 &val)) ) 468 { 469 GNUNET_break_op (0); 470 return GNUNET_SYSERR; 471 } 472 if (0 != strcasecmp (val.currency, 473 r_cspec->currency)) 474 { 475 GNUNET_break_op (0); 476 return GNUNET_SYSERR; 477 } 478 GNUNET_array_append (r_cspec->common_amounts, 479 r_cspec->num_common_amounts, 480 val); 481 } 482 } 483 return GNUNET_OK; 484 } 485 486 487 /** 488 * Cleanup data left from parsing encrypted contract. 489 * 490 * @param cls closure, NULL 491 * @param[out] spec where to free the data 492 */ 493 static void 494 clean_cspec (void *cls, 495 struct GNUNET_JSON_Specification *spec) 496 { 497 struct TALER_CurrencySpecification *cspec = spec->ptr; 498 499 (void) cls; 500 GNUNET_array_grow (cspec->common_amounts, 501 cspec->num_common_amounts, 502 0); 503 GNUNET_free (cspec->name); 504 json_decref (cspec->map_alt_unit_names); 505 } 506 507 508 struct GNUNET_JSON_Specification 509 TALER_JSON_spec_currency_specification ( 510 const char *name, 511 const char *currency, 512 struct TALER_CurrencySpecification *r_cspec) 513 { 514 struct GNUNET_JSON_Specification ret = { 515 .parser = &parse_cspec, 516 .cleaner = &clean_cspec, 517 .cls = (void *) currency, 518 .field = name, 519 .ptr = r_cspec, 520 .ptr_size = sizeof (*r_cspec), 521 .size_ptr = NULL 522 }; 523 524 memset (r_cspec, 525 0, 526 sizeof (*r_cspec)); 527 return ret; 528 } 529 530 531 static enum GNUNET_GenericReturnValue 532 parse_denomination_group (void *cls, 533 json_t *root, 534 struct GNUNET_JSON_Specification *spec) 535 { 536 struct TALER_DenominationGroup *group = spec->ptr; 537 const char *cipher; 538 const char *currency = cls; 539 bool age_mask_missing = false; 540 bool has_age_restricted_suffix = false; 541 struct GNUNET_JSON_Specification gspec[] = { 542 GNUNET_JSON_spec_string ("cipher", 543 &cipher), 544 TALER_JSON_spec_amount ("value", 545 currency, 546 &group->value), 547 TALER_JSON_SPEC_DENOM_FEES ("fee", 548 currency, 549 &group->fees), 550 GNUNET_JSON_spec_mark_optional ( 551 GNUNET_JSON_spec_uint32 ("age_mask", 552 &group->age_mask.bits), 553 &age_mask_missing), 554 GNUNET_JSON_spec_end () 555 }; 556 const char *emsg; 557 unsigned int eline; 558 559 if (GNUNET_OK != 560 GNUNET_JSON_parse (root, 561 gspec, 562 &emsg, 563 &eline)) 564 { 565 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 566 "Failed to parse %s at %u: %s\n", 567 gspec[eline].field, 568 eline, 569 emsg); 570 GNUNET_break_op (0); 571 return GNUNET_SYSERR; 572 } 573 574 group->cipher = string_to_cipher (cipher); 575 if (GNUNET_CRYPTO_BSA_INVALID == group->cipher) 576 { 577 GNUNET_break_op (0); 578 return GNUNET_SYSERR; 579 } 580 581 /* age_mask and suffix must be consistent */ 582 has_age_restricted_suffix = 583 (NULL != strstr (cipher, "+age_restricted")); 584 if (has_age_restricted_suffix && age_mask_missing) 585 { 586 GNUNET_break_op (0); 587 return GNUNET_SYSERR; 588 } 589 590 if (age_mask_missing) 591 group->age_mask.bits = 0; 592 593 return GNUNET_OK; 594 } 595 596 597 struct GNUNET_JSON_Specification 598 TALER_JSON_spec_denomination_group (const char *name, 599 const char *currency, 600 struct TALER_DenominationGroup *group) 601 { 602 struct GNUNET_JSON_Specification ret = { 603 .cls = (void *) currency, 604 .parser = &parse_denomination_group, 605 .field = name, 606 .ptr = group, 607 .ptr_size = sizeof(*group) 608 }; 609 610 return ret; 611 } 612 613 614 /** 615 * Parse given JSON object to an encrypted contract. 616 * 617 * @param cls closure, NULL 618 * @param root the json object representing data 619 * @param[out] spec where to write the data 620 * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error 621 */ 622 static enum GNUNET_GenericReturnValue 623 parse_econtract (void *cls, 624 json_t *root, 625 struct GNUNET_JSON_Specification *spec) 626 { 627 struct TALER_EncryptedContract *econtract = spec->ptr; 628 struct GNUNET_JSON_Specification ispec[] = { 629 GNUNET_JSON_spec_varsize ("econtract", 630 &econtract->econtract, 631 &econtract->econtract_size), 632 GNUNET_JSON_spec_fixed_auto ("econtract_sig", 633 &econtract->econtract_sig), 634 GNUNET_JSON_spec_fixed_auto ("contract_pub", 635 &econtract->contract_pub), 636 GNUNET_JSON_spec_end () 637 }; 638 const char *emsg; 639 unsigned int eline; 640 641 (void) cls; 642 if (GNUNET_OK != 643 GNUNET_JSON_parse (root, 644 ispec, 645 &emsg, 646 &eline)) 647 { 648 GNUNET_break_op (0); 649 return GNUNET_SYSERR; 650 } 651 return GNUNET_OK; 652 } 653 654 655 /** 656 * Cleanup data left from parsing encrypted contract. 657 * 658 * @param cls closure, NULL 659 * @param[out] spec where to free the data 660 */ 661 static void 662 clean_econtract (void *cls, 663 struct GNUNET_JSON_Specification *spec) 664 { 665 struct TALER_EncryptedContract *econtract = spec->ptr; 666 667 (void) cls; 668 GNUNET_free (econtract->econtract); 669 } 670 671 672 struct GNUNET_JSON_Specification 673 TALER_JSON_spec_econtract (const char *name, 674 struct TALER_EncryptedContract *econtract) 675 { 676 struct GNUNET_JSON_Specification ret = { 677 .parser = &parse_econtract, 678 .cleaner = &clean_econtract, 679 .field = name, 680 .ptr = econtract 681 }; 682 683 return ret; 684 } 685 686 687 /** 688 * Parse given JSON object to an age commitmnet 689 * 690 * @param cls closure, NULL 691 * @param root the json object representing data 692 * @param[out] spec where to write the data 693 * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error 694 */ 695 static enum GNUNET_GenericReturnValue 696 parse_age_commitment (void *cls, 697 json_t *root, 698 struct GNUNET_JSON_Specification *spec) 699 { 700 struct TALER_AgeCommitment *age_commitment = spec->ptr; 701 json_t *pk; 702 unsigned int idx; 703 size_t num; 704 705 (void) cls; 706 if ( (NULL == root) || 707 (! json_is_array (root))) 708 { 709 GNUNET_break_op (0); 710 return GNUNET_SYSERR; 711 } 712 713 num = json_array_size (root); 714 if (32 <= num || 0 == num) 715 { 716 GNUNET_break_op (0); 717 return GNUNET_SYSERR; 718 } 719 720 age_commitment->num = num; 721 age_commitment->pubs = 722 GNUNET_new_array (num, 723 struct TALER_AgeCommitmentPublicKeyP); 724 725 json_array_foreach (root, idx, pk) { 726 const char *emsg; 727 unsigned int eline; 728 struct GNUNET_JSON_Specification pkspec[] = { 729 GNUNET_JSON_spec_fixed_auto ( 730 NULL, 731 &age_commitment->pubs[idx].pub), 732 GNUNET_JSON_spec_end () 733 }; 734 735 if (GNUNET_OK != 736 GNUNET_JSON_parse (pk, 737 pkspec, 738 &emsg, 739 &eline)) 740 { 741 GNUNET_break_op (0); 742 GNUNET_free (age_commitment->pubs); 743 age_commitment->num = 0; 744 return GNUNET_SYSERR; 745 } 746 }; 747 748 return GNUNET_OK; 749 } 750 751 752 /** 753 * Cleanup data left from parsing age commitment 754 * 755 * @param cls closure, NULL 756 * @param[out] spec where to free the data 757 */ 758 static void 759 clean_age_commitment (void *cls, 760 struct GNUNET_JSON_Specification *spec) 761 { 762 struct TALER_AgeCommitment *age_commitment = spec->ptr; 763 764 (void) cls; 765 if ( (NULL == age_commitment) || 766 (NULL == age_commitment->pubs) ) 767 return; 768 age_commitment->num = 0; 769 GNUNET_free (age_commitment->pubs); 770 } 771 772 773 struct GNUNET_JSON_Specification 774 TALER_JSON_spec_age_commitment (const char *name, 775 struct TALER_AgeCommitment *age_commitment) 776 { 777 struct GNUNET_JSON_Specification ret = { 778 .parser = &parse_age_commitment, 779 .cleaner = &clean_age_commitment, 780 .field = name, 781 .ptr = age_commitment 782 }; 783 784 return ret; 785 } 786 787 788 struct GNUNET_JSON_Specification 789 TALER_JSON_spec_token_issue_sig (const char *field, 790 struct TALER_TokenIssueSignature *sig) 791 { 792 sig->signature = NULL; 793 return GNUNET_JSON_spec_unblinded_signature (field, 794 &sig->signature); 795 } 796 797 798 struct GNUNET_JSON_Specification 799 TALER_JSON_spec_blinded_token_issue_sig ( 800 const char *field, 801 struct TALER_BlindedTokenIssueSignature *sig) 802 { 803 sig->signature = NULL; 804 return GNUNET_JSON_spec_blinded_signature (field, 805 &sig->signature); 806 } 807 808 809 struct GNUNET_JSON_Specification 810 TALER_JSON_spec_token_envelope (const char *field, 811 struct TALER_TokenEnvelope *env) 812 { 813 env->blinded_pub = NULL; 814 return GNUNET_JSON_spec_blinded_message (field, 815 &env->blinded_pub); 816 } 817 818 819 /** 820 * Parse given JSON object to denomination public key. 821 * 822 * @param cls closure, NULL 823 * @param root the json object representing data 824 * @param[out] spec where to write the data 825 * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error 826 */ 827 static enum GNUNET_GenericReturnValue 828 parse_denom_pub (void *cls, 829 json_t *root, 830 struct GNUNET_JSON_Specification *spec) 831 { 832 struct TALER_DenominationPublicKey *denom_pub = spec->ptr; 833 struct GNUNET_CRYPTO_BlindSignPublicKey *bsign_pub; 834 const char *cipher; 835 bool age_mask_missing = false; 836 struct GNUNET_JSON_Specification dspec[] = { 837 GNUNET_JSON_spec_string ("cipher", 838 &cipher), 839 GNUNET_JSON_spec_mark_optional ( 840 GNUNET_JSON_spec_uint32 ("age_mask", 841 &denom_pub->age_mask.bits), 842 &age_mask_missing), 843 GNUNET_JSON_spec_end () 844 }; 845 const char *emsg; 846 unsigned int eline; 847 848 (void) cls; 849 if (GNUNET_OK != 850 GNUNET_JSON_parse (root, 851 dspec, 852 &emsg, 853 &eline)) 854 { 855 GNUNET_break_op (0); 856 return GNUNET_SYSERR; 857 } 858 859 if (age_mask_missing) 860 denom_pub->age_mask.bits = 0; 861 bsign_pub = GNUNET_new (struct GNUNET_CRYPTO_BlindSignPublicKey); 862 bsign_pub->rc = 1; 863 bsign_pub->cipher = string_to_cipher (cipher); 864 switch (bsign_pub->cipher) 865 { 866 case GNUNET_CRYPTO_BSA_INVALID: 867 break; 868 case GNUNET_CRYPTO_BSA_RSA: 869 { 870 struct GNUNET_JSON_Specification ispec[] = { 871 GNUNET_JSON_spec_rsa_public_key ( 872 "rsa_pub", 873 &bsign_pub->details.rsa_public_key), 874 GNUNET_JSON_spec_end () 875 }; 876 877 if (GNUNET_OK != 878 GNUNET_JSON_parse (root, 879 ispec, 880 &emsg, 881 &eline)) 882 { 883 GNUNET_break_op (0); 884 GNUNET_free (bsign_pub); 885 return GNUNET_SYSERR; 886 } 887 GNUNET_CRYPTO_rsa_public_key_hash (bsign_pub->details.rsa_public_key, 888 &bsign_pub->pub_key_hash); 889 denom_pub->bsign_pub_key = bsign_pub; 890 return GNUNET_OK; 891 } 892 case GNUNET_CRYPTO_BSA_CS: 893 { 894 struct GNUNET_JSON_Specification ispec[] = { 895 GNUNET_JSON_spec_fixed ("cs_pub", 896 &bsign_pub->details.cs_public_key, 897 sizeof (bsign_pub->details.cs_public_key)), 898 GNUNET_JSON_spec_end () 899 }; 900 901 if (GNUNET_OK != 902 GNUNET_JSON_parse (root, 903 ispec, 904 &emsg, 905 &eline)) 906 { 907 GNUNET_break_op (0); 908 GNUNET_free (bsign_pub); 909 return GNUNET_SYSERR; 910 } 911 GNUNET_CRYPTO_hash (&bsign_pub->details.cs_public_key, 912 sizeof(bsign_pub->details.cs_public_key), 913 &bsign_pub->pub_key_hash); 914 denom_pub->bsign_pub_key = bsign_pub; 915 return GNUNET_OK; 916 } 917 } 918 GNUNET_break_op (0); 919 GNUNET_free (bsign_pub); 920 return GNUNET_SYSERR; 921 } 922 923 924 /** 925 * Cleanup data left from parsing denomination public key. 926 * 927 * @param cls closure, NULL 928 * @param[out] spec where to free the data 929 */ 930 static void 931 clean_denom_pub (void *cls, 932 struct GNUNET_JSON_Specification *spec) 933 { 934 struct TALER_DenominationPublicKey *denom_pub = spec->ptr; 935 936 (void) cls; 937 TALER_denom_pub_free (denom_pub); 938 } 939 940 941 struct GNUNET_JSON_Specification 942 TALER_JSON_spec_denom_pub (const char *field, 943 struct TALER_DenominationPublicKey *pk) 944 { 945 struct GNUNET_JSON_Specification ret = { 946 .parser = &parse_denom_pub, 947 .cleaner = &clean_denom_pub, 948 .field = field, 949 .ptr = pk 950 }; 951 952 pk->bsign_pub_key = NULL; 953 return ret; 954 } 955 956 957 /** 958 * Parse given JSON object to token issue public key. 959 * 960 * @param cls closure, NULL 961 * @param root the json object representing data 962 * @param[out] spec where to write the data 963 * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error 964 */ 965 static enum GNUNET_GenericReturnValue 966 parse_token_pub (void *cls, 967 json_t *root, 968 struct GNUNET_JSON_Specification *spec) 969 { 970 struct TALER_TokenIssuePublicKey *token_pub = spec->ptr; 971 struct GNUNET_CRYPTO_BlindSignPublicKey *bsign_pub; 972 const char *cipher; 973 struct GNUNET_JSON_Specification dspec[] = { 974 GNUNET_JSON_spec_string ("cipher", 975 &cipher), 976 GNUNET_JSON_spec_end () 977 }; 978 const char *emsg; 979 unsigned int eline; 980 981 (void) cls; 982 if (GNUNET_OK != 983 GNUNET_JSON_parse (root, 984 dspec, 985 &emsg, 986 &eline)) 987 { 988 GNUNET_break_op (0); 989 return GNUNET_SYSERR; 990 } 991 992 bsign_pub = GNUNET_new (struct GNUNET_CRYPTO_BlindSignPublicKey); 993 bsign_pub->rc = 1; 994 bsign_pub->cipher = string_to_cipher (cipher); 995 switch (bsign_pub->cipher) 996 { 997 case GNUNET_CRYPTO_BSA_INVALID: 998 break; 999 case GNUNET_CRYPTO_BSA_RSA: 1000 { 1001 struct GNUNET_JSON_Specification ispec[] = { 1002 GNUNET_JSON_spec_rsa_public_key ( 1003 "rsa_pub", 1004 &bsign_pub->details.rsa_public_key), 1005 GNUNET_JSON_spec_end () 1006 }; 1007 1008 if (GNUNET_OK != 1009 GNUNET_JSON_parse (root, 1010 ispec, 1011 &emsg, 1012 &eline)) 1013 { 1014 GNUNET_break_op (0); 1015 GNUNET_free (bsign_pub); 1016 return GNUNET_SYSERR; 1017 } 1018 GNUNET_CRYPTO_rsa_public_key_hash (bsign_pub->details.rsa_public_key, 1019 &bsign_pub->pub_key_hash); 1020 token_pub->public_key = bsign_pub; 1021 return GNUNET_OK; 1022 } 1023 case GNUNET_CRYPTO_BSA_CS: 1024 { 1025 struct GNUNET_JSON_Specification ispec[] = { 1026 GNUNET_JSON_spec_fixed ("cs_pub", 1027 &bsign_pub->details.cs_public_key, 1028 sizeof (bsign_pub->details.cs_public_key)), 1029 GNUNET_JSON_spec_end () 1030 }; 1031 1032 if (GNUNET_OK != 1033 GNUNET_JSON_parse (root, 1034 ispec, 1035 &emsg, 1036 &eline)) 1037 { 1038 GNUNET_break_op (0); 1039 GNUNET_free (bsign_pub); 1040 return GNUNET_SYSERR; 1041 } 1042 GNUNET_CRYPTO_hash (&bsign_pub->details.cs_public_key, 1043 sizeof(bsign_pub->details.cs_public_key), 1044 &bsign_pub->pub_key_hash); 1045 token_pub->public_key = bsign_pub; 1046 return GNUNET_OK; 1047 } 1048 } 1049 GNUNET_break_op (0); 1050 GNUNET_free (bsign_pub); 1051 return GNUNET_SYSERR; 1052 } 1053 1054 1055 /** 1056 * Cleanup data left from parsing token issue public key. 1057 * 1058 * @param cls closure, NULL 1059 * @param[out] spec where to free the data 1060 */ 1061 static void 1062 clean_token_pub (void *cls, 1063 struct GNUNET_JSON_Specification *spec) 1064 { 1065 struct TALER_TokenIssuePublicKey *token_pub = spec->ptr; 1066 1067 (void) cls; 1068 TALER_token_issue_pub_free (token_pub); 1069 } 1070 1071 1072 struct GNUNET_JSON_Specification 1073 TALER_JSON_spec_token_pub (const char *field, 1074 struct TALER_TokenIssuePublicKey *pk) 1075 { 1076 struct GNUNET_JSON_Specification ret = { 1077 .field = field, 1078 .parser = &parse_token_pub, 1079 .cleaner = &clean_token_pub, 1080 .ptr = pk 1081 }; 1082 1083 pk->public_key = NULL; 1084 return ret; 1085 } 1086 1087 1088 /** 1089 * Parse given JSON object partially into a denomination public key. 1090 * 1091 * Depending on the cipher in cls, it parses the corresponding public key type. 1092 * 1093 * @param cls closure, enum GNUNET_CRYPTO_BlindSignatureAlgorithm 1094 * @param root the json object representing data 1095 * @param[out] spec where to write the data 1096 * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error 1097 */ 1098 static enum GNUNET_GenericReturnValue 1099 parse_denom_pub_cipher (void *cls, 1100 json_t *root, 1101 struct GNUNET_JSON_Specification *spec) 1102 { 1103 struct TALER_DenominationPublicKey *denom_pub = spec->ptr; 1104 enum GNUNET_CRYPTO_BlindSignatureAlgorithm cipher = 1105 (enum GNUNET_CRYPTO_BlindSignatureAlgorithm) (long) cls; 1106 struct GNUNET_CRYPTO_BlindSignPublicKey *bsign_pub; 1107 const char *emsg; 1108 unsigned int eline; 1109 1110 bsign_pub = GNUNET_new (struct GNUNET_CRYPTO_BlindSignPublicKey); 1111 bsign_pub->cipher = cipher; 1112 bsign_pub->rc = 1; 1113 switch (cipher) 1114 { 1115 case GNUNET_CRYPTO_BSA_INVALID: 1116 break; 1117 case GNUNET_CRYPTO_BSA_RSA: 1118 { 1119 struct GNUNET_JSON_Specification ispec[] = { 1120 GNUNET_JSON_spec_rsa_public_key ( 1121 "rsa_pub", 1122 &bsign_pub->details.rsa_public_key), 1123 GNUNET_JSON_spec_end () 1124 }; 1125 1126 if (GNUNET_OK != 1127 GNUNET_JSON_parse (root, 1128 ispec, 1129 &emsg, 1130 &eline)) 1131 { 1132 GNUNET_break_op (0); 1133 GNUNET_free (bsign_pub); 1134 return GNUNET_SYSERR; 1135 } 1136 GNUNET_CRYPTO_rsa_public_key_hash (bsign_pub->details.rsa_public_key, 1137 &bsign_pub->pub_key_hash); 1138 denom_pub->bsign_pub_key = bsign_pub; 1139 return GNUNET_OK; 1140 } 1141 case GNUNET_CRYPTO_BSA_CS: 1142 { 1143 struct GNUNET_JSON_Specification ispec[] = { 1144 GNUNET_JSON_spec_fixed ("cs_pub", 1145 &bsign_pub->details.cs_public_key, 1146 sizeof (bsign_pub->details.cs_public_key)), 1147 GNUNET_JSON_spec_end () 1148 }; 1149 1150 if (GNUNET_OK != 1151 GNUNET_JSON_parse (root, 1152 ispec, 1153 &emsg, 1154 &eline)) 1155 { 1156 GNUNET_break_op (0); 1157 GNUNET_free (bsign_pub); 1158 return GNUNET_SYSERR; 1159 } 1160 GNUNET_CRYPTO_hash (&bsign_pub->details.cs_public_key, 1161 sizeof(bsign_pub->details.cs_public_key), 1162 &bsign_pub->pub_key_hash); 1163 denom_pub->bsign_pub_key = bsign_pub; 1164 return GNUNET_OK; 1165 } 1166 } 1167 GNUNET_break_op (0); 1168 GNUNET_free (bsign_pub); 1169 return GNUNET_SYSERR; 1170 } 1171 1172 1173 struct GNUNET_JSON_Specification 1174 TALER_JSON_spec_denom_pub_cipher ( 1175 const char *field, 1176 enum GNUNET_CRYPTO_BlindSignatureAlgorithm cipher, 1177 struct TALER_DenominationPublicKey *pk) 1178 { 1179 struct GNUNET_JSON_Specification ret = { 1180 .parser = &parse_denom_pub_cipher, 1181 .cleaner = &clean_denom_pub, 1182 .field = field, 1183 .cls = (void *) cipher, 1184 .ptr = pk 1185 }; 1186 1187 pk->bsign_pub_key = NULL; 1188 return ret; 1189 } 1190 1191 1192 struct GNUNET_JSON_Specification 1193 TALER_JSON_spec_denom_sig (const char *field, 1194 struct TALER_DenominationSignature *sig) 1195 { 1196 sig->unblinded_sig = NULL; 1197 return GNUNET_JSON_spec_unblinded_signature (field, 1198 &sig->unblinded_sig); 1199 } 1200 1201 1202 struct GNUNET_JSON_Specification 1203 TALER_JSON_spec_blinded_denom_sig ( 1204 const char *field, 1205 struct TALER_BlindedDenominationSignature *sig) 1206 { 1207 sig->blinded_sig = NULL; 1208 return GNUNET_JSON_spec_blinded_signature (field, 1209 &sig->blinded_sig); 1210 } 1211 1212 1213 struct GNUNET_JSON_Specification 1214 TALER_JSON_spec_blinded_planchet ( 1215 const char *field, 1216 struct TALER_BlindedPlanchet *blinded_planchet) 1217 { 1218 blinded_planchet->blinded_message = NULL; 1219 return GNUNET_JSON_spec_blinded_message (field, 1220 &blinded_planchet->blinded_message); 1221 } 1222 1223 1224 /** 1225 * Parse given JSON object to exchange withdraw values (/csr). 1226 * 1227 * @param cls closure, NULL 1228 * @param root the json object representing data 1229 * @param[out] spec where to write the data 1230 * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error 1231 */ 1232 static enum GNUNET_GenericReturnValue 1233 parse_exchange_blinding_values (void *cls, 1234 json_t *root, 1235 struct GNUNET_JSON_Specification *spec) 1236 { 1237 struct TALER_ExchangeBlindingValues *ewv = spec->ptr; 1238 struct GNUNET_CRYPTO_BlindingInputValues *bi; 1239 const char *cipher; 1240 struct GNUNET_JSON_Specification dspec[] = { 1241 GNUNET_JSON_spec_string ("cipher", 1242 &cipher), 1243 GNUNET_JSON_spec_end () 1244 }; 1245 const char *emsg; 1246 unsigned int eline; 1247 enum GNUNET_CRYPTO_BlindSignatureAlgorithm ci; 1248 1249 (void) cls; 1250 if (GNUNET_OK != 1251 GNUNET_JSON_parse (root, 1252 dspec, 1253 &emsg, 1254 &eline)) 1255 { 1256 GNUNET_break_op (0); 1257 return GNUNET_SYSERR; 1258 } 1259 ci = string_to_cipher (cipher); 1260 switch (ci) 1261 { 1262 case GNUNET_CRYPTO_BSA_INVALID: 1263 break; 1264 case GNUNET_CRYPTO_BSA_RSA: 1265 ewv->blinding_inputs = TALER_denom_ewv_rsa_singleton ()->blinding_inputs; 1266 return GNUNET_OK; 1267 case GNUNET_CRYPTO_BSA_CS: 1268 bi = GNUNET_new (struct GNUNET_CRYPTO_BlindingInputValues); 1269 bi->cipher = GNUNET_CRYPTO_BSA_CS; 1270 bi->rc = 1; 1271 { 1272 struct GNUNET_JSON_Specification ispec[] = { 1273 GNUNET_JSON_spec_fixed ( 1274 "r_pub_0", 1275 &bi->details.cs_values.r_pub[0], 1276 sizeof (struct GNUNET_CRYPTO_CsRPublic)), 1277 GNUNET_JSON_spec_fixed ( 1278 "r_pub_1", 1279 &bi->details.cs_values.r_pub[1], 1280 sizeof (struct GNUNET_CRYPTO_CsRPublic)), 1281 GNUNET_JSON_spec_end () 1282 }; 1283 1284 if (GNUNET_OK != 1285 GNUNET_JSON_parse (root, 1286 ispec, 1287 &emsg, 1288 &eline)) 1289 { 1290 GNUNET_break_op (0); 1291 GNUNET_free (bi); 1292 return GNUNET_SYSERR; 1293 } 1294 ewv->blinding_inputs = bi; 1295 return GNUNET_OK; 1296 } 1297 } 1298 GNUNET_break_op (0); 1299 return GNUNET_SYSERR; 1300 } 1301 1302 1303 /** 1304 * Cleanup data left from parsing withdraw values 1305 * 1306 * @param cls closure, NULL 1307 * @param[out] spec where to free the data 1308 */ 1309 static void 1310 clean_exchange_blinding_values ( 1311 void *cls, 1312 struct GNUNET_JSON_Specification *spec) 1313 { 1314 struct TALER_ExchangeBlindingValues *ewv = spec->ptr; 1315 1316 (void) cls; 1317 TALER_denom_ewv_free (ewv); 1318 } 1319 1320 1321 struct GNUNET_JSON_Specification 1322 TALER_JSON_spec_exchange_blinding_values ( 1323 const char *field, 1324 struct TALER_ExchangeBlindingValues *ewv) 1325 { 1326 struct GNUNET_JSON_Specification ret = { 1327 .parser = &parse_exchange_blinding_values, 1328 .cleaner = &clean_exchange_blinding_values, 1329 .field = field, 1330 .ptr = ewv 1331 }; 1332 1333 ewv->blinding_inputs = NULL; 1334 return ret; 1335 } 1336 1337 1338 /** 1339 * Closure for #parse_i18n_string. 1340 */ 1341 struct I18nContext 1342 { 1343 /** 1344 * Language pattern to match. 1345 */ 1346 char *lp; 1347 1348 /** 1349 * Name of the field to match. 1350 */ 1351 const char *field; 1352 }; 1353 1354 1355 /** 1356 * Parse given JSON object to internationalized string. 1357 * 1358 * @param cls closure, our `struct I18nContext *` 1359 * @param root the json object representing data 1360 * @param[out] spec where to write the data 1361 * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error 1362 */ 1363 static enum GNUNET_GenericReturnValue 1364 parse_i18n_string (void *cls, 1365 json_t *root, 1366 struct GNUNET_JSON_Specification *spec) 1367 { 1368 struct I18nContext *ctx = cls; 1369 json_t *i18n; 1370 json_t *val; 1371 1372 { 1373 char *i18nf; 1374 1375 GNUNET_asprintf (&i18nf, 1376 "%s_i18n", 1377 ctx->field); 1378 i18n = json_object_get (root, 1379 i18nf); 1380 GNUNET_free (i18nf); 1381 } 1382 1383 val = json_object_get (root, 1384 ctx->field); 1385 if ( (NULL != i18n) && 1386 (NULL != ctx->lp) ) 1387 { 1388 double best = 0.0; 1389 json_t *pos; 1390 const char *lang; 1391 1392 json_object_foreach (i18n, lang, pos) 1393 { 1394 double score; 1395 1396 score = TALER_pattern_matches (ctx->lp, 1397 lang); 1398 if (score > best) 1399 { 1400 best = score; 1401 val = pos; 1402 } 1403 } 1404 } 1405 1406 { 1407 const char *str; 1408 1409 str = json_string_value (val); 1410 *(const char **) spec->ptr = str; 1411 } 1412 return GNUNET_OK; 1413 } 1414 1415 1416 /** 1417 * Function called to clean up data from earlier parsing. 1418 * 1419 * @param cls closure 1420 * @param spec our specification entry with data to clean. 1421 */ 1422 static void 1423 i18n_cleaner (void *cls, 1424 struct GNUNET_JSON_Specification *spec) 1425 { 1426 struct I18nContext *ctx = cls; 1427 1428 (void) spec; 1429 if (NULL != ctx) 1430 { 1431 GNUNET_free (ctx->lp); 1432 GNUNET_free (ctx); 1433 } 1434 } 1435 1436 1437 struct GNUNET_JSON_Specification 1438 TALER_JSON_spec_i18n_string (const char *name, 1439 const char *language_pattern, 1440 const char **strptr) 1441 { 1442 struct I18nContext *ctx = GNUNET_new (struct I18nContext); 1443 struct GNUNET_JSON_Specification ret = { 1444 .parser = &parse_i18n_string, 1445 .cleaner = &i18n_cleaner, 1446 .cls = ctx, 1447 .field = NULL, /* we want the main object */ 1448 .ptr = strptr, 1449 .ptr_size = 0, 1450 .size_ptr = NULL 1451 }; 1452 1453 ctx->lp = (NULL != language_pattern) 1454 ? GNUNET_strdup (language_pattern) 1455 : NULL; 1456 ctx->field = name; 1457 *strptr = NULL; 1458 return ret; 1459 } 1460 1461 1462 struct GNUNET_JSON_Specification 1463 TALER_JSON_spec_i18n_str (const char *name, 1464 const char **strptr) 1465 { 1466 const char *lang = getenv ("LANG"); 1467 const char *dot; 1468 char *l; 1469 struct GNUNET_JSON_Specification ret; 1470 1471 if (NULL != lang) 1472 { 1473 dot = strchr (lang, 1474 '.'); 1475 if (NULL == dot) 1476 l = GNUNET_strdup (lang); 1477 else 1478 l = GNUNET_strndup (lang, 1479 dot - lang); 1480 } 1481 else 1482 { 1483 l = NULL; 1484 } 1485 ret = TALER_JSON_spec_i18n_string (name, 1486 l, 1487 strptr); 1488 GNUNET_free (l); 1489 return ret; 1490 } 1491 1492 1493 /** 1494 * Parse given JSON object with Taler error code. 1495 * 1496 * @param cls closure, NULL 1497 * @param root the json object representing data 1498 * @param[out] spec where to write the data 1499 * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error 1500 */ 1501 static enum GNUNET_GenericReturnValue 1502 parse_ec (void *cls, 1503 json_t *root, 1504 struct GNUNET_JSON_Specification *spec) 1505 { 1506 enum TALER_ErrorCode *ec = spec->ptr; 1507 json_int_t num; 1508 1509 (void) cls; 1510 if (! json_is_integer (root)) 1511 { 1512 GNUNET_break_op (0); 1513 return GNUNET_SYSERR; 1514 } 1515 num = json_integer_value (root); 1516 if (num < 0) 1517 { 1518 GNUNET_break_op (0); 1519 *ec = TALER_EC_INVALID; 1520 return GNUNET_SYSERR; 1521 } 1522 *ec = (enum TALER_ErrorCode) num; 1523 return GNUNET_OK; 1524 } 1525 1526 1527 struct GNUNET_JSON_Specification 1528 TALER_JSON_spec_ec (const char *field, 1529 enum TALER_ErrorCode *ec) 1530 { 1531 struct GNUNET_JSON_Specification ret = { 1532 .parser = &parse_ec, 1533 .field = field, 1534 .ptr = ec 1535 }; 1536 1537 *ec = TALER_EC_NONE; 1538 return ret; 1539 } 1540 1541 1542 /** 1543 * Parse given JSON object to web URL. 1544 * 1545 * @param cls closure, NULL 1546 * @param root the json object representing data 1547 * @param[out] spec where to write the data 1548 * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error 1549 */ 1550 static enum GNUNET_GenericReturnValue 1551 parse_web_url (void *cls, 1552 json_t *root, 1553 struct GNUNET_JSON_Specification *spec) 1554 { 1555 const char *str; 1556 1557 (void) cls; 1558 str = json_string_value (root); 1559 if (NULL == str) 1560 { 1561 GNUNET_break_op (0); 1562 return GNUNET_SYSERR; 1563 } 1564 if (! TALER_is_web_url (str)) 1565 { 1566 GNUNET_break_op (0); 1567 return GNUNET_SYSERR; 1568 } 1569 *(const char **) spec->ptr = str; 1570 return GNUNET_OK; 1571 } 1572 1573 1574 struct GNUNET_JSON_Specification 1575 TALER_JSON_spec_web_url (const char *field, 1576 const char **url) 1577 { 1578 struct GNUNET_JSON_Specification ret = { 1579 .parser = &parse_web_url, 1580 .field = field, 1581 .ptr = url 1582 }; 1583 1584 *url = NULL; 1585 return ret; 1586 } 1587 1588 1589 /** 1590 * Parse given JSON object to web URL, and make a copy. 1591 * 1592 * @param cls closure, NULL 1593 * @param root the json object representing data 1594 * @param[out] spec where to write the data 1595 * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error 1596 */ 1597 static enum GNUNET_GenericReturnValue 1598 parse_web_url_copy (void *cls, 1599 json_t *root, 1600 struct GNUNET_JSON_Specification *spec) 1601 { 1602 const char *str; 1603 1604 (void) cls; 1605 str = json_string_value (root); 1606 if (NULL == str) 1607 { 1608 GNUNET_break_op (0); 1609 return GNUNET_SYSERR; 1610 } 1611 if (! TALER_is_web_url (str)) 1612 { 1613 GNUNET_break_op (0); 1614 return GNUNET_SYSERR; 1615 } 1616 *(char **) spec->ptr = GNUNET_strdup (str); 1617 return GNUNET_OK; 1618 } 1619 1620 1621 struct GNUNET_JSON_Specification 1622 TALER_JSON_spec_web_url_copy (const char *field, 1623 char **url) 1624 { 1625 struct GNUNET_JSON_Specification ret = { 1626 .parser = &parse_web_url_copy, 1627 .field = field, 1628 .ptr = url 1629 }; 1630 1631 *url = NULL; 1632 return ret; 1633 } 1634 1635 1636 /** 1637 * Parse given JSON object to slug. 1638 * 1639 * @param cls closure, NULL 1640 * @param root the json object representing data 1641 * @param[out] spec where to write the data 1642 * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error 1643 */ 1644 static enum GNUNET_GenericReturnValue 1645 parse_slug (void *cls, 1646 json_t *root, 1647 struct GNUNET_JSON_Specification *spec) 1648 { 1649 const char *str; 1650 1651 (void) cls; 1652 str = json_string_value (root); 1653 if (NULL == str) 1654 { 1655 GNUNET_break_op (0); 1656 return GNUNET_SYSERR; 1657 } 1658 if (! TALER_is_slug (str)) 1659 { 1660 GNUNET_break_op (0); 1661 return GNUNET_SYSERR; 1662 } 1663 *(const char **) spec->ptr = str; 1664 return GNUNET_OK; 1665 } 1666 1667 1668 struct GNUNET_JSON_Specification 1669 TALER_JSON_spec_slug (const char *field, 1670 const char **slug) 1671 { 1672 struct GNUNET_JSON_Specification ret = { 1673 .parser = &parse_slug, 1674 .field = field, 1675 .ptr = slug 1676 }; 1677 1678 *slug = NULL; 1679 return ret; 1680 } 1681 1682 1683 /** 1684 * Parse given JSON object to slug. 1685 * 1686 * @param cls closure, NULL 1687 * @param root the json object representing data 1688 * @param[out] spec where to write the data 1689 * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error 1690 */ 1691 static enum GNUNET_GenericReturnValue 1692 parse_slug_copy (void *cls, 1693 json_t *root, 1694 struct GNUNET_JSON_Specification *spec) 1695 { 1696 const char *str; 1697 1698 (void) cls; 1699 str = json_string_value (root); 1700 if (NULL == str) 1701 { 1702 GNUNET_break_op (0); 1703 return GNUNET_SYSERR; 1704 } 1705 if (! TALER_is_slug (str)) 1706 { 1707 GNUNET_break_op (0); 1708 return GNUNET_SYSERR; 1709 } 1710 *(char **) spec->ptr = GNUNET_strdup (str); 1711 return GNUNET_OK; 1712 } 1713 1714 1715 struct GNUNET_JSON_Specification 1716 TALER_JSON_spec_slug_copy (const char *field, 1717 char **slug) 1718 { 1719 struct GNUNET_JSON_Specification ret = { 1720 .parser = &parse_slug_copy, 1721 .field = field, 1722 .ptr = slug 1723 }; 1724 1725 *slug = NULL; 1726 return ret; 1727 } 1728 1729 1730 /** 1731 * Parse given JSON object to a session ID. 1732 * 1733 * @param cls closure, NULL 1734 * @param root the json object representing data 1735 * @param[out] spec where to write the data 1736 * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error 1737 */ 1738 static enum GNUNET_GenericReturnValue 1739 parse_session_id (void *cls, 1740 json_t *root, 1741 struct GNUNET_JSON_Specification *spec) 1742 { 1743 const char *str; 1744 1745 (void) cls; 1746 str = json_string_value (root); 1747 if (NULL == str) 1748 { 1749 GNUNET_break_op (0); 1750 return GNUNET_SYSERR; 1751 } 1752 if (! TALER_is_session_id (str)) 1753 { 1754 GNUNET_break_op (0); 1755 return GNUNET_SYSERR; 1756 } 1757 *(const char **) spec->ptr = str; 1758 return GNUNET_OK; 1759 } 1760 1761 1762 struct GNUNET_JSON_Specification 1763 TALER_JSON_spec_session_id (const char *field, 1764 const char **session_id) 1765 { 1766 struct GNUNET_JSON_Specification ret = { 1767 .parser = &parse_session_id, 1768 .field = field, 1769 .ptr = session_id 1770 }; 1771 1772 *session_id = NULL; 1773 return ret; 1774 } 1775 1776 1777 /** 1778 * Parse given JSON object to a session ID that must not be empty. 1779 * 1780 * @param cls closure, NULL 1781 * @param root the json object representing data 1782 * @param[out] spec where to write the data 1783 * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error 1784 */ 1785 static enum GNUNET_GenericReturnValue 1786 parse_nonempty_session_id (void *cls, 1787 json_t *root, 1788 struct GNUNET_JSON_Specification *spec) 1789 { 1790 if (GNUNET_OK != 1791 parse_session_id (cls, 1792 root, 1793 spec)) 1794 return GNUNET_SYSERR; 1795 if ('\0' == (*(const char **) spec->ptr)[0]) 1796 { 1797 GNUNET_break_op (0); 1798 return GNUNET_SYSERR; 1799 } 1800 return GNUNET_OK; 1801 } 1802 1803 1804 struct GNUNET_JSON_Specification 1805 TALER_JSON_spec_nonempty_session_id (const char *field, 1806 const char **session_id) 1807 { 1808 struct GNUNET_JSON_Specification ret = { 1809 .parser = &parse_nonempty_session_id, 1810 .field = field, 1811 .ptr = session_id 1812 }; 1813 1814 *session_id = NULL; 1815 return ret; 1816 } 1817 1818 1819 /** 1820 * Parse given JSON object to payto:// URI. 1821 * 1822 * @param cls closure, NULL 1823 * @param root the json object representing data 1824 * @param[out] spec where to write the data 1825 * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error 1826 */ 1827 static enum GNUNET_GenericReturnValue 1828 parse_full_payto_uri (void *cls, 1829 json_t *root, 1830 struct GNUNET_JSON_Specification *spec) 1831 { 1832 struct TALER_FullPayto *payto_uri = spec->ptr; 1833 const char *str; 1834 char *err; 1835 1836 (void) cls; 1837 str = json_string_value (root); 1838 if (NULL == str) 1839 { 1840 GNUNET_break_op (0); 1841 return GNUNET_SYSERR; 1842 } 1843 payto_uri->full_payto = (char *) str; 1844 err = TALER_payto_validate (*payto_uri); 1845 if (NULL != err) 1846 { 1847 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 1848 "payto:// malformed: %s\n", 1849 err); 1850 GNUNET_free (err); 1851 payto_uri->full_payto = NULL; 1852 return GNUNET_SYSERR; 1853 } 1854 return GNUNET_OK; 1855 } 1856 1857 1858 struct GNUNET_JSON_Specification 1859 TALER_JSON_spec_full_payto_uri ( 1860 const char *field, 1861 struct TALER_FullPayto *payto_uri) 1862 { 1863 struct GNUNET_JSON_Specification ret = { 1864 .parser = &parse_full_payto_uri, 1865 .field = field, 1866 .ptr = payto_uri 1867 }; 1868 1869 payto_uri->full_payto = NULL; 1870 return ret; 1871 } 1872 1873 1874 /** 1875 * Parse given JSON object to payto:// URI. 1876 * 1877 * @param cls closure, NULL 1878 * @param root the json object representing data 1879 * @param[out] spec where to write the data 1880 * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error 1881 */ 1882 static enum GNUNET_GenericReturnValue 1883 parse_normalized_payto_uri (void *cls, 1884 json_t *root, 1885 struct GNUNET_JSON_Specification *spec) 1886 { 1887 struct TALER_NormalizedPayto *payto_uri = spec->ptr; 1888 const char *str; 1889 1890 (void) cls; 1891 str = json_string_value (root); 1892 if (NULL == str) 1893 { 1894 GNUNET_break_op (0); 1895 return GNUNET_SYSERR; 1896 } 1897 payto_uri->normalized_payto = (char *) str; 1898 { 1899 char *err; 1900 1901 err = TALER_normalized_payto_validate (*payto_uri); 1902 if (NULL != err) 1903 { 1904 GNUNET_break_op (0); 1905 GNUNET_free (err); 1906 payto_uri->normalized_payto = NULL; 1907 return GNUNET_SYSERR; 1908 } 1909 } 1910 return GNUNET_OK; 1911 } 1912 1913 1914 struct GNUNET_JSON_Specification 1915 TALER_JSON_spec_normalized_payto_uri ( 1916 const char *field, 1917 struct TALER_NormalizedPayto *payto_uri) 1918 { 1919 struct GNUNET_JSON_Specification ret = { 1920 .parser = &parse_normalized_payto_uri, 1921 .field = field, 1922 .ptr = payto_uri 1923 }; 1924 1925 payto_uri->normalized_payto = NULL; 1926 return ret; 1927 } 1928 1929 1930 /** 1931 * Parse given JSON object with protocol version. 1932 * 1933 * @param cls closure, NULL 1934 * @param root the json object representing data 1935 * @param[out] spec where to write the data 1936 * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error 1937 */ 1938 static enum GNUNET_GenericReturnValue 1939 parse_protocol_version (void *cls, 1940 json_t *root, 1941 struct GNUNET_JSON_Specification *spec) 1942 { 1943 struct TALER_JSON_ProtocolVersion *pv = spec->ptr; 1944 const char *ver; 1945 char dummy; 1946 1947 (void) cls; 1948 if (! json_is_string (root)) 1949 { 1950 GNUNET_break_op (0); 1951 return GNUNET_SYSERR; 1952 } 1953 ver = json_string_value (root); 1954 if (3 != sscanf (ver, 1955 "%u:%u:%u%c", 1956 &pv->current, 1957 &pv->revision, 1958 &pv->age, 1959 &dummy)) 1960 { 1961 GNUNET_break_op (0); 1962 return GNUNET_SYSERR; 1963 } 1964 return GNUNET_OK; 1965 } 1966 1967 1968 struct GNUNET_JSON_Specification 1969 TALER_JSON_spec_version (const char *field, 1970 struct TALER_JSON_ProtocolVersion *ver) 1971 { 1972 struct GNUNET_JSON_Specification ret = { 1973 .parser = &parse_protocol_version, 1974 .field = field, 1975 .ptr = ver 1976 }; 1977 1978 return ret; 1979 } 1980 1981 1982 /** 1983 * Parse given JSON object to an OTP key. 1984 * 1985 * @param cls closure, NULL 1986 * @param root the json object representing data 1987 * @param[out] spec where to write the data 1988 * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error 1989 */ 1990 static enum GNUNET_GenericReturnValue 1991 parse_otp_key (void *cls, 1992 json_t *root, 1993 struct GNUNET_JSON_Specification *spec) 1994 { 1995 const char *pos_key; 1996 1997 (void) cls; 1998 pos_key = json_string_value (root); 1999 if (NULL == pos_key) 2000 { 2001 GNUNET_break_op (0); 2002 return GNUNET_SYSERR; 2003 } 2004 { 2005 size_t pos_key_length = strlen (pos_key); 2006 void *key; /* pos_key in binary */ 2007 size_t key_len; /* length of the key */ 2008 int dret; 2009 2010 key_len = pos_key_length * 5 / 8; 2011 key = GNUNET_malloc (key_len); 2012 dret = TALER_rfc3548_base32decode (pos_key, 2013 pos_key_length, 2014 key, 2015 key_len); 2016 if (-1 == dret) 2017 { 2018 GNUNET_free (key); 2019 GNUNET_break_op (0); 2020 return GNUNET_SYSERR; 2021 } 2022 GNUNET_free (key); 2023 } 2024 *(const char **) spec->ptr = pos_key; 2025 return GNUNET_OK; 2026 } 2027 2028 2029 struct GNUNET_JSON_Specification 2030 TALER_JSON_spec_otp_key (const char *name, 2031 const char **otp_key) 2032 { 2033 struct GNUNET_JSON_Specification ret = { 2034 .parser = &parse_otp_key, 2035 .field = name, 2036 .ptr = otp_key 2037 }; 2038 2039 *otp_key = NULL; 2040 return ret; 2041 } 2042 2043 2044 /** 2045 * Parse given JSON object to `enum TALER_MerchantConfirmationAlgorithm` 2046 * 2047 * @param cls closure, NULL 2048 * @param root the json object representing data 2049 * @param[out] spec where to write the data 2050 * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error 2051 */ 2052 static enum GNUNET_GenericReturnValue 2053 parse_otp_type (void *cls, 2054 json_t *root, 2055 struct GNUNET_JSON_Specification *spec) 2056 { 2057 static const struct Entry 2058 { 2059 const char *name; 2060 enum TALER_MerchantConfirmationAlgorithm val; 2061 } lt [] = { 2062 { .name = "NONE", 2063 .val = TALER_MCA_NONE }, 2064 { .name = "TOTP_WITHOUT_PRICE", 2065 .val = TALER_MCA_WITHOUT_PRICE }, 2066 { .name = "TOTP_WITH_PRICE", 2067 .val = TALER_MCA_WITH_PRICE }, 2068 { .name = "ECDSA_CHALLENGE", 2069 .val = TALER_MCA_ECDSA_CHALLENGE }, 2070 { .name = "EDDSA_CHALLENGE", 2071 .val = TALER_MCA_EDDSA_CHALLENGE }, 2072 { .name = NULL, 2073 .val = TALER_MCA_NONE }, 2074 }; 2075 enum TALER_MerchantConfirmationAlgorithm *res 2076 = (enum TALER_MerchantConfirmationAlgorithm *) spec->ptr; 2077 2078 (void) cls; 2079 if (json_is_string (root)) 2080 { 2081 const char *str; 2082 2083 str = json_string_value (root); 2084 if (NULL == str) 2085 { 2086 GNUNET_break_op (0); 2087 return GNUNET_SYSERR; 2088 } 2089 for (unsigned int i = 0; NULL != lt[i].name; i++) 2090 { 2091 if (0 == strcasecmp (str, 2092 lt[i].name)) 2093 { 2094 *res = lt[i].val; 2095 return GNUNET_OK; 2096 } 2097 } 2098 GNUNET_break_op (0); 2099 } 2100 if (json_is_integer (root)) 2101 { 2102 json_int_t val; 2103 2104 val = json_integer_value (root); 2105 for (unsigned int i = 0; NULL != lt[i].name; i++) 2106 { 2107 if (val == lt[i].val) 2108 { 2109 *res = lt[i].val; 2110 return GNUNET_OK; 2111 } 2112 } 2113 GNUNET_break_op (0); 2114 return GNUNET_SYSERR; 2115 } 2116 GNUNET_break_op (0); 2117 return GNUNET_SYSERR; 2118 } 2119 2120 2121 struct GNUNET_JSON_Specification 2122 TALER_JSON_spec_otp_type (const char *name, 2123 enum TALER_MerchantConfirmationAlgorithm *mca) 2124 { 2125 struct GNUNET_JSON_Specification ret = { 2126 .parser = &parse_otp_type, 2127 .field = name, 2128 .ptr = mca 2129 }; 2130 2131 *mca = TALER_MCA_NONE; 2132 return ret; 2133 } 2134 2135 2136 /** 2137 * Parse given JSON object to `enum TALER_KYCLOGIC_KycTriggerEvent` 2138 * 2139 * @param cls closure, NULL 2140 * @param root the json object representing data 2141 * @param[out] spec where to write the data 2142 * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error 2143 */ 2144 static enum GNUNET_GenericReturnValue 2145 parse_kycte (void *cls, 2146 json_t *root, 2147 struct GNUNET_JSON_Specification *spec) 2148 { 2149 static const struct Entry 2150 { 2151 const char *name; 2152 enum TALER_KYCLOGIC_KycTriggerEvent val; 2153 } lt [] = { 2154 { .name = "NONE", 2155 .val = TALER_KYCLOGIC_KYC_TRIGGER_NONE }, 2156 { .name = "WITHDRAW", 2157 .val = TALER_KYCLOGIC_KYC_TRIGGER_WITHDRAW }, 2158 { .name = "DEPOSIT", 2159 .val = TALER_KYCLOGIC_KYC_TRIGGER_DEPOSIT }, 2160 { .name = "MERGE", 2161 .val = TALER_KYCLOGIC_KYC_TRIGGER_P2P_RECEIVE }, 2162 { .name = "BALANCE", 2163 .val = TALER_KYCLOGIC_KYC_TRIGGER_WALLET_BALANCE }, 2164 { .name = "CLOSE", 2165 .val = TALER_KYCLOGIC_KYC_TRIGGER_RESERVE_CLOSE }, 2166 { .name = "AGGREGATE", 2167 .val = TALER_KYCLOGIC_KYC_TRIGGER_AGGREGATE }, 2168 { .name = "TRANSACTION", 2169 .val = TALER_KYCLOGIC_KYC_TRIGGER_TRANSACTION }, 2170 { .name = "REFUND", 2171 .val = TALER_KYCLOGIC_KYC_TRIGGER_REFUND }, 2172 { .name = NULL, 2173 .val = TALER_KYCLOGIC_KYC_TRIGGER_NONE }, 2174 }; 2175 enum TALER_KYCLOGIC_KycTriggerEvent *res 2176 = (enum TALER_KYCLOGIC_KycTriggerEvent *) spec->ptr; 2177 2178 (void) cls; 2179 if (json_is_string (root)) 2180 { 2181 const char *str; 2182 2183 str = json_string_value (root); 2184 if (NULL == str) 2185 { 2186 GNUNET_break_op (0); 2187 return GNUNET_SYSERR; 2188 } 2189 for (unsigned int i = 0; NULL != lt[i].name; i++) 2190 { 2191 if (0 == strcasecmp (str, 2192 lt[i].name)) 2193 { 2194 *res = lt[i].val; 2195 return GNUNET_OK; 2196 } 2197 } 2198 GNUNET_break_op (0); 2199 return GNUNET_SYSERR; 2200 } 2201 if (json_is_integer (root)) 2202 { 2203 json_int_t val; 2204 2205 val = json_integer_value (root); 2206 for (unsigned int i = 0; NULL != lt[i].name; i++) 2207 { 2208 if (val == lt[i].val) 2209 { 2210 *res = lt[i].val; 2211 return GNUNET_OK; 2212 } 2213 } 2214 GNUNET_break_op (0); 2215 return GNUNET_SYSERR; 2216 } 2217 GNUNET_break_op (0); 2218 return GNUNET_SYSERR; 2219 } 2220 2221 2222 struct GNUNET_JSON_Specification 2223 TALER_JSON_spec_kycte (const char *name, 2224 enum TALER_KYCLOGIC_KycTriggerEvent *kte) 2225 { 2226 struct GNUNET_JSON_Specification ret = { 2227 .parser = &parse_kycte, 2228 .field = name, 2229 .ptr = kte 2230 }; 2231 2232 *kte = TALER_KYCLOGIC_KYC_TRIGGER_NONE; 2233 return ret; 2234 } 2235 2236 2237 /** 2238 * Parser combinator of a tuple of parsers, for parsing 2239 * an array of expected size and element types. 2240 * 2241 * @param cls closure, array of specs, NULL terminated 2242 * @param root the json root 2243 * @param[out] spec where to write the data 2244 */ 2245 static enum GNUNET_GenericReturnValue 2246 parse_tuple_of (void *cls, 2247 json_t *root, 2248 struct GNUNET_JSON_Specification *spec) 2249 { 2250 struct GNUNET_JSON_Specification *specs = cls; 2251 static size_t max_specs = 100; 2252 bool found_end = false; 2253 2254 enum GNUNET_GenericReturnValue ret; 2255 2256 if (! json_is_array (root)) 2257 { 2258 return GNUNET_SYSERR; 2259 } 2260 2261 { 2262 size_t num; 2263 for (num = 0; num< max_specs; num++) 2264 { 2265 if (NULL == specs[num].parser) 2266 { 2267 found_end = true; 2268 break; 2269 } 2270 } 2271 GNUNET_assert (found_end); 2272 2273 if (num != json_array_size (root)) 2274 { 2275 GNUNET_break_op (0); 2276 return GNUNET_SYSERR; 2277 } 2278 } 2279 2280 { 2281 json_t *j_entry; 2282 size_t idx; 2283 2284 json_array_foreach (root, idx, j_entry) { 2285 ret = GNUNET_JSON_parse (j_entry, 2286 &specs[idx], 2287 NULL, 2288 NULL); 2289 if (GNUNET_OK != ret) 2290 { 2291 GNUNET_break_op (0); 2292 return GNUNET_SYSERR; 2293 } 2294 } 2295 } 2296 2297 return GNUNET_OK; 2298 } 2299 2300 2301 struct GNUNET_JSON_Specification 2302 TALER_JSON_spec_tuple_of ( 2303 const char *field, 2304 struct GNUNET_JSON_Specification specs[]) 2305 { 2306 struct GNUNET_JSON_Specification ret = { 2307 .parser = &parse_tuple_of, 2308 .field = field, 2309 .cls = specs 2310 }; 2311 2312 return ret; 2313 } 2314 2315 2316 /** 2317 * Parser for an array of unknown length but 2318 * of elements of the same type with the same 2319 * fixed length. 2320 * 2321 * @param cls closure, entry_size 2322 * @param root the json root 2323 * @param spec the output spec 2324 */ 2325 static enum GNUNET_GenericReturnValue 2326 parse_array_fixed (void *cls, 2327 json_t *root, 2328 struct GNUNET_JSON_Specification *spec) 2329 { 2330 enum GNUNET_GenericReturnValue ret; 2331 size_t entry_size = (size_t) cls; 2332 size_t num_entries; 2333 2334 GNUNET_assert (0< entry_size); 2335 num_entries = spec->ptr_size / entry_size; 2336 GNUNET_assert (0 < num_entries); 2337 2338 2339 if (! json_is_array (root)) 2340 { 2341 GNUNET_break_op (0); 2342 return GNUNET_SYSERR; 2343 } 2344 if (num_entries != json_array_size (root)) 2345 { 2346 GNUNET_break_op (0); 2347 return GNUNET_SYSERR; 2348 } 2349 2350 { 2351 json_t *j_entry; 2352 size_t idx; 2353 void *ptr = spec->ptr; 2354 void *end = spec->ptr + spec->ptr_size; 2355 2356 json_array_foreach (root, idx, j_entry) { 2357 struct GNUNET_JSON_Specification esp[] = { 2358 GNUNET_JSON_spec_fixed (NULL, 2359 ptr, 2360 entry_size), 2361 GNUNET_JSON_spec_end () 2362 }; 2363 GNUNET_assert (ptr < end); 2364 ret = GNUNET_JSON_parse (j_entry, 2365 esp, 2366 NULL, 2367 NULL); 2368 if (GNUNET_OK != ret) 2369 { 2370 GNUNET_break_op (0); 2371 return GNUNET_SYSERR; 2372 } 2373 ptr += entry_size; 2374 } 2375 } 2376 return GNUNET_OK; 2377 } 2378 2379 2380 struct GNUNET_JSON_Specification 2381 TALER_JSON_spec_array_fixed ( 2382 const char *field, 2383 size_t num_entries, 2384 void *entries, 2385 size_t entry_size) 2386 { 2387 struct GNUNET_JSON_Specification ret = { 2388 .parser = &parse_array_fixed, 2389 .ptr = entries, 2390 .ptr_size = entry_size * num_entries, 2391 .field = field, 2392 .cls = (void *) entry_size, 2393 }; 2394 2395 GNUNET_assert ((num_entries <= 1) || 2396 (entry_size * num_entries > entry_size)); 2397 return ret; 2398 } 2399 2400 2401 /** 2402 * Closure for the parser of arrays of fixed size data 2403 * of unknown array length 2404 */ 2405 struct closure_array_of_data 2406 { 2407 /** 2408 * Fixed (known) size per entry 2409 */ 2410 size_t entry_size; 2411 2412 /** 2413 * Pointer where to put the number of elements 2414 * allocated, i.e. the number of elements in the 2415 * json array. 2416 */ 2417 size_t *num_entries; 2418 }; 2419 2420 /** 2421 * Parser for an array of data of known element size, 2422 * but unknown array length 2423 */ 2424 static enum GNUNET_GenericReturnValue 2425 parse_array_of_data (void *cls, 2426 json_t *root, 2427 struct GNUNET_JSON_Specification *spec) 2428 { 2429 enum GNUNET_GenericReturnValue ret; 2430 struct closure_array_of_data *info = cls; 2431 size_t num_entries; 2432 2433 if (! json_is_array (root)) 2434 { 2435 GNUNET_break_op (0); 2436 return GNUNET_SYSERR; 2437 } 2438 num_entries = json_array_size (root); 2439 *info->num_entries = num_entries; 2440 if (0 == num_entries) 2441 { 2442 *(char **) spec->ptr = NULL; 2443 return GNUNET_OK; 2444 } 2445 2446 spec->ptr_size = num_entries * info->entry_size; 2447 GNUNET_assert (spec->ptr_size > num_entries); 2448 *((char **) spec->ptr) = GNUNET_malloc (spec->ptr_size); 2449 2450 { 2451 json_t *j_entry; 2452 size_t idx; 2453 char *ptr = *(char **) spec->ptr; 2454 char *end = ptr + spec->ptr_size; 2455 2456 json_array_foreach (root, idx, j_entry) { 2457 struct GNUNET_JSON_Specification esp[] = { 2458 GNUNET_JSON_spec_fixed (NULL, 2459 ptr, 2460 info->entry_size), 2461 GNUNET_JSON_spec_end () 2462 }; 2463 GNUNET_assert (ptr < end); 2464 ret = GNUNET_JSON_parse (j_entry, 2465 esp, 2466 NULL, 2467 NULL); 2468 if (GNUNET_OK != ret) 2469 { 2470 GNUNET_break_op (0); 2471 return GNUNET_SYSERR; 2472 } 2473 ptr += info->entry_size; 2474 } 2475 } 2476 return GNUNET_OK; 2477 } 2478 2479 2480 /** 2481 * Cleanup data left from parsing an array of fixed size (but unknown length). 2482 * 2483 * @param cls closure_of_array_data 2484 * @param[out] spec where to free the data 2485 */ 2486 static void 2487 cleaner_array_of_data (void *cls, 2488 struct GNUNET_JSON_Specification *spec) 2489 { 2490 struct closure_array_of_data *info = cls; 2491 2492 GNUNET_free (*(void **) spec->ptr); 2493 GNUNET_free (info); 2494 } 2495 2496 2497 struct GNUNET_JSON_Specification 2498 TALER_JSON_spec_array_of_data ( 2499 const char *field, 2500 size_t entry_size, 2501 size_t *num_entries, 2502 void **entries) 2503 { 2504 struct closure_array_of_data *cls; 2505 2506 GNUNET_assert (0< entry_size); 2507 *entries = NULL; 2508 *num_entries = 0; 2509 cls = GNUNET_new (struct closure_array_of_data); 2510 cls->num_entries = num_entries; 2511 cls->entry_size = entry_size; 2512 { 2513 struct GNUNET_JSON_Specification ret = { 2514 .parser = &parse_array_of_data, 2515 .ptr = entries, 2516 .field = field, 2517 .cleaner = &cleaner_array_of_data, 2518 .cls = (void *) cls, 2519 }; 2520 2521 return ret; 2522 } 2523 } 2524 2525 2526 struct GNUNET_JSON_Specification 2527 TALER_JSON_spec_array_of_denom_pub_h ( 2528 const char *field, 2529 size_t *num_entries, 2530 struct TALER_DenominationHashP **entries) 2531 { 2532 *num_entries = 0; 2533 *entries = NULL; 2534 return TALER_JSON_spec_array_of_data ( 2535 field, 2536 sizeof (struct TALER_DenominationHashP), 2537 num_entries, 2538 (void **) entries); 2539 } 2540 2541 2542 /** 2543 * Parser for an array of blinded denomination signatures, 2544 * of unknown array length 2545 */ 2546 static enum GNUNET_GenericReturnValue 2547 parse_array_of_blinded_denom_sigs (void *cls, 2548 json_t *root, 2549 struct GNUNET_JSON_Specification *spec) 2550 { 2551 enum GNUNET_GenericReturnValue ret; 2552 struct TALER_BlindedDenominationSignature *sigs = spec->ptr; 2553 size_t expected_num_entries = (size_t) cls; 2554 size_t num_entries; 2555 2556 if (! json_is_array (root)) 2557 { 2558 GNUNET_break_op (0); 2559 return GNUNET_SYSERR; 2560 } 2561 num_entries = json_array_size (root); 2562 if (num_entries != expected_num_entries) 2563 { 2564 GNUNET_break_op (0); 2565 return GNUNET_SYSERR; 2566 } 2567 2568 { 2569 json_t *j_entry; 2570 size_t idx; 2571 struct TALER_BlindedDenominationSignature *ptr = sigs; 2572 2573 json_array_foreach (root, idx, j_entry) { 2574 struct GNUNET_JSON_Specification esp[] = { 2575 TALER_JSON_spec_blinded_denom_sig (NULL, 2576 ptr), 2577 GNUNET_JSON_spec_end () 2578 }; 2579 ret = GNUNET_JSON_parse (j_entry, 2580 esp, 2581 NULL, 2582 NULL); 2583 if (GNUNET_OK != ret) 2584 { 2585 GNUNET_break_op (0); 2586 for (size_t i = 0; i < idx; i++) 2587 { 2588 TALER_blinded_denom_sig_free (&sigs[i]); 2589 sigs[i].blinded_sig = NULL; 2590 } 2591 return GNUNET_SYSERR; 2592 } 2593 ptr++; 2594 } 2595 } 2596 return GNUNET_OK; 2597 } 2598 2599 2600 /** 2601 * Cleanup data left from parsing an array of blinded signatures. 2602 * 2603 * @param cls pointer to a size_t with the length of the array 2604 * @param[out] spec where to free the data 2605 */ 2606 static void 2607 cleaner_array_of_blinded_denom_sigs ( 2608 void *cls, 2609 struct GNUNET_JSON_Specification *spec) 2610 { 2611 struct TALER_BlindedDenominationSignature *sigs = spec->ptr; 2612 size_t num_entries = (size_t) cls; 2613 2614 for (size_t i = 0; i < num_entries; i++) 2615 { 2616 if (NULL != sigs[i].blinded_sig) 2617 { 2618 TALER_blinded_denom_sig_free (&sigs[i]); 2619 sigs[i].blinded_sig = NULL; 2620 } 2621 } 2622 } 2623 2624 2625 struct GNUNET_JSON_Specification 2626 TALER_JSON_spec_array_of_blinded_denom_sigs ( 2627 const char *field, 2628 size_t num_entries, 2629 struct TALER_BlindedDenominationSignature *entries) 2630 { 2631 struct GNUNET_JSON_Specification ret = { 2632 .parser = &parse_array_of_blinded_denom_sigs, 2633 .ptr = entries, 2634 .field = field, 2635 .cleaner = &cleaner_array_of_blinded_denom_sigs, 2636 .cls = (void *) num_entries, 2637 }; 2638 2639 for (size_t i = 0; i<num_entries; i++) 2640 entries[i].blinded_sig = NULL; 2641 return ret; 2642 } 2643 2644 2645 /* end of json/json_helper.c */