json_helper.c (63184B)
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 denom_pub->bsign_pub_key = bsign_pub; 888 return GNUNET_OK; 889 } 890 case GNUNET_CRYPTO_BSA_CS: 891 { 892 struct GNUNET_JSON_Specification ispec[] = { 893 GNUNET_JSON_spec_fixed ("cs_pub", 894 &bsign_pub->details.cs_public_key, 895 sizeof (bsign_pub->details.cs_public_key)), 896 GNUNET_JSON_spec_end () 897 }; 898 899 if (GNUNET_OK != 900 GNUNET_JSON_parse (root, 901 ispec, 902 &emsg, 903 &eline)) 904 { 905 GNUNET_break_op (0); 906 GNUNET_free (bsign_pub); 907 return GNUNET_SYSERR; 908 } 909 denom_pub->bsign_pub_key = bsign_pub; 910 return GNUNET_OK; 911 } 912 } 913 GNUNET_break_op (0); 914 GNUNET_free (bsign_pub); 915 return GNUNET_SYSERR; 916 } 917 918 919 /** 920 * Cleanup data left from parsing denomination public key. 921 * 922 * @param cls closure, NULL 923 * @param[out] spec where to free the data 924 */ 925 static void 926 clean_denom_pub (void *cls, 927 struct GNUNET_JSON_Specification *spec) 928 { 929 struct TALER_DenominationPublicKey *denom_pub = spec->ptr; 930 931 (void) cls; 932 TALER_denom_pub_free (denom_pub); 933 } 934 935 936 struct GNUNET_JSON_Specification 937 TALER_JSON_spec_denom_pub (const char *field, 938 struct TALER_DenominationPublicKey *pk) 939 { 940 struct GNUNET_JSON_Specification ret = { 941 .parser = &parse_denom_pub, 942 .cleaner = &clean_denom_pub, 943 .field = field, 944 .ptr = pk 945 }; 946 947 pk->bsign_pub_key = NULL; 948 return ret; 949 } 950 951 952 /** 953 * Parse given JSON object to token issue public key. 954 * 955 * @param cls closure, NULL 956 * @param root the json object representing data 957 * @param[out] spec where to write the data 958 * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error 959 */ 960 static enum GNUNET_GenericReturnValue 961 parse_token_pub (void *cls, 962 json_t *root, 963 struct GNUNET_JSON_Specification *spec) 964 { 965 struct TALER_TokenIssuePublicKey *token_pub = spec->ptr; 966 struct GNUNET_CRYPTO_BlindSignPublicKey *bsign_pub; 967 const char *cipher; 968 struct GNUNET_JSON_Specification dspec[] = { 969 GNUNET_JSON_spec_string ("cipher", 970 &cipher), 971 GNUNET_JSON_spec_end () 972 }; 973 const char *emsg; 974 unsigned int eline; 975 976 (void) cls; 977 if (GNUNET_OK != 978 GNUNET_JSON_parse (root, 979 dspec, 980 &emsg, 981 &eline)) 982 { 983 GNUNET_break_op (0); 984 return GNUNET_SYSERR; 985 } 986 987 bsign_pub = GNUNET_new (struct GNUNET_CRYPTO_BlindSignPublicKey); 988 bsign_pub->rc = 1; 989 bsign_pub->cipher = string_to_cipher (cipher); 990 switch (bsign_pub->cipher) 991 { 992 case GNUNET_CRYPTO_BSA_INVALID: 993 break; 994 case GNUNET_CRYPTO_BSA_RSA: 995 { 996 struct GNUNET_JSON_Specification ispec[] = { 997 GNUNET_JSON_spec_rsa_public_key ( 998 "rsa_pub", 999 &bsign_pub->details.rsa_public_key), 1000 GNUNET_JSON_spec_end () 1001 }; 1002 1003 if (GNUNET_OK != 1004 GNUNET_JSON_parse (root, 1005 ispec, 1006 &emsg, 1007 &eline)) 1008 { 1009 GNUNET_break_op (0); 1010 GNUNET_free (bsign_pub); 1011 return GNUNET_SYSERR; 1012 } 1013 GNUNET_CRYPTO_rsa_public_key_hash (bsign_pub->details.rsa_public_key, 1014 &bsign_pub->pub_key_hash); 1015 token_pub->public_key = bsign_pub; 1016 return GNUNET_OK; 1017 } 1018 case GNUNET_CRYPTO_BSA_CS: 1019 { 1020 struct GNUNET_JSON_Specification ispec[] = { 1021 GNUNET_JSON_spec_fixed ("cs_pub", 1022 &bsign_pub->details.cs_public_key, 1023 sizeof (bsign_pub->details.cs_public_key)), 1024 GNUNET_JSON_spec_end () 1025 }; 1026 1027 if (GNUNET_OK != 1028 GNUNET_JSON_parse (root, 1029 ispec, 1030 &emsg, 1031 &eline)) 1032 { 1033 GNUNET_break_op (0); 1034 GNUNET_free (bsign_pub); 1035 return GNUNET_SYSERR; 1036 } 1037 GNUNET_CRYPTO_hash (&bsign_pub->details.cs_public_key, 1038 sizeof(bsign_pub->details.cs_public_key), 1039 &bsign_pub->pub_key_hash); 1040 token_pub->public_key = bsign_pub; 1041 return GNUNET_OK; 1042 } 1043 } 1044 GNUNET_break_op (0); 1045 GNUNET_free (bsign_pub); 1046 return GNUNET_SYSERR; 1047 } 1048 1049 1050 /** 1051 * Cleanup data left from parsing token issue public key. 1052 * 1053 * @param cls closure, NULL 1054 * @param[out] spec where to free the data 1055 */ 1056 static void 1057 clean_token_pub (void *cls, 1058 struct GNUNET_JSON_Specification *spec) 1059 { 1060 struct TALER_TokenIssuePublicKey *token_pub = spec->ptr; 1061 1062 (void) cls; 1063 TALER_token_issue_pub_free (token_pub); 1064 } 1065 1066 1067 struct GNUNET_JSON_Specification 1068 TALER_JSON_spec_token_pub (const char *field, 1069 struct TALER_TokenIssuePublicKey *pk) 1070 { 1071 struct GNUNET_JSON_Specification ret = { 1072 .field = field, 1073 .parser = &parse_token_pub, 1074 .cleaner = &clean_token_pub, 1075 .ptr = pk 1076 }; 1077 1078 pk->public_key = NULL; 1079 return ret; 1080 } 1081 1082 1083 /** 1084 * Parse given JSON object partially into a denomination public key. 1085 * 1086 * Depending on the cipher in cls, it parses the corresponding public key type. 1087 * 1088 * @param cls closure, enum GNUNET_CRYPTO_BlindSignatureAlgorithm 1089 * @param root the json object representing data 1090 * @param[out] spec where to write the data 1091 * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error 1092 */ 1093 static enum GNUNET_GenericReturnValue 1094 parse_denom_pub_cipher (void *cls, 1095 json_t *root, 1096 struct GNUNET_JSON_Specification *spec) 1097 { 1098 struct TALER_DenominationPublicKey *denom_pub = spec->ptr; 1099 enum GNUNET_CRYPTO_BlindSignatureAlgorithm cipher = 1100 (enum GNUNET_CRYPTO_BlindSignatureAlgorithm) (long) cls; 1101 struct GNUNET_CRYPTO_BlindSignPublicKey *bsign_pub; 1102 const char *emsg; 1103 unsigned int eline; 1104 1105 bsign_pub = GNUNET_new (struct GNUNET_CRYPTO_BlindSignPublicKey); 1106 bsign_pub->cipher = cipher; 1107 bsign_pub->rc = 1; 1108 switch (cipher) 1109 { 1110 case GNUNET_CRYPTO_BSA_INVALID: 1111 break; 1112 case GNUNET_CRYPTO_BSA_RSA: 1113 { 1114 struct GNUNET_JSON_Specification ispec[] = { 1115 GNUNET_JSON_spec_rsa_public_key ( 1116 "rsa_pub", 1117 &bsign_pub->details.rsa_public_key), 1118 GNUNET_JSON_spec_end () 1119 }; 1120 1121 if (GNUNET_OK != 1122 GNUNET_JSON_parse (root, 1123 ispec, 1124 &emsg, 1125 &eline)) 1126 { 1127 GNUNET_break_op (0); 1128 GNUNET_free (bsign_pub); 1129 return GNUNET_SYSERR; 1130 } 1131 denom_pub->bsign_pub_key = bsign_pub; 1132 return GNUNET_OK; 1133 } 1134 case GNUNET_CRYPTO_BSA_CS: 1135 { 1136 struct GNUNET_JSON_Specification ispec[] = { 1137 GNUNET_JSON_spec_fixed ("cs_pub", 1138 &bsign_pub->details.cs_public_key, 1139 sizeof (bsign_pub->details.cs_public_key)), 1140 GNUNET_JSON_spec_end () 1141 }; 1142 1143 if (GNUNET_OK != 1144 GNUNET_JSON_parse (root, 1145 ispec, 1146 &emsg, 1147 &eline)) 1148 { 1149 GNUNET_break_op (0); 1150 GNUNET_free (bsign_pub); 1151 return GNUNET_SYSERR; 1152 } 1153 denom_pub->bsign_pub_key = bsign_pub; 1154 return GNUNET_OK; 1155 } 1156 } 1157 GNUNET_break_op (0); 1158 GNUNET_free (bsign_pub); 1159 return GNUNET_SYSERR; 1160 } 1161 1162 1163 struct GNUNET_JSON_Specification 1164 TALER_JSON_spec_denom_pub_cipher ( 1165 const char *field, 1166 enum GNUNET_CRYPTO_BlindSignatureAlgorithm cipher, 1167 struct TALER_DenominationPublicKey *pk) 1168 { 1169 struct GNUNET_JSON_Specification ret = { 1170 .parser = &parse_denom_pub_cipher, 1171 .cleaner = &clean_denom_pub, 1172 .field = field, 1173 .cls = (void *) cipher, 1174 .ptr = pk 1175 }; 1176 1177 pk->bsign_pub_key = NULL; 1178 return ret; 1179 } 1180 1181 1182 struct GNUNET_JSON_Specification 1183 TALER_JSON_spec_denom_sig (const char *field, 1184 struct TALER_DenominationSignature *sig) 1185 { 1186 sig->unblinded_sig = NULL; 1187 return GNUNET_JSON_spec_unblinded_signature (field, 1188 &sig->unblinded_sig); 1189 } 1190 1191 1192 struct GNUNET_JSON_Specification 1193 TALER_JSON_spec_blinded_denom_sig ( 1194 const char *field, 1195 struct TALER_BlindedDenominationSignature *sig) 1196 { 1197 sig->blinded_sig = NULL; 1198 return GNUNET_JSON_spec_blinded_signature (field, 1199 &sig->blinded_sig); 1200 } 1201 1202 1203 struct GNUNET_JSON_Specification 1204 TALER_JSON_spec_blinded_planchet ( 1205 const char *field, 1206 struct TALER_BlindedPlanchet *blinded_planchet) 1207 { 1208 blinded_planchet->blinded_message = NULL; 1209 return GNUNET_JSON_spec_blinded_message (field, 1210 &blinded_planchet->blinded_message); 1211 } 1212 1213 1214 /** 1215 * Parse given JSON object to exchange withdraw values (/csr). 1216 * 1217 * @param cls closure, NULL 1218 * @param root the json object representing data 1219 * @param[out] spec where to write the data 1220 * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error 1221 */ 1222 static enum GNUNET_GenericReturnValue 1223 parse_exchange_blinding_values (void *cls, 1224 json_t *root, 1225 struct GNUNET_JSON_Specification *spec) 1226 { 1227 struct TALER_ExchangeBlindingValues *ewv = spec->ptr; 1228 struct GNUNET_CRYPTO_BlindingInputValues *bi; 1229 const char *cipher; 1230 struct GNUNET_JSON_Specification dspec[] = { 1231 GNUNET_JSON_spec_string ("cipher", 1232 &cipher), 1233 GNUNET_JSON_spec_end () 1234 }; 1235 const char *emsg; 1236 unsigned int eline; 1237 enum GNUNET_CRYPTO_BlindSignatureAlgorithm ci; 1238 1239 (void) cls; 1240 if (GNUNET_OK != 1241 GNUNET_JSON_parse (root, 1242 dspec, 1243 &emsg, 1244 &eline)) 1245 { 1246 GNUNET_break_op (0); 1247 return GNUNET_SYSERR; 1248 } 1249 ci = string_to_cipher (cipher); 1250 switch (ci) 1251 { 1252 case GNUNET_CRYPTO_BSA_INVALID: 1253 break; 1254 case GNUNET_CRYPTO_BSA_RSA: 1255 ewv->blinding_inputs = TALER_denom_ewv_rsa_singleton ()->blinding_inputs; 1256 return GNUNET_OK; 1257 case GNUNET_CRYPTO_BSA_CS: 1258 bi = GNUNET_new (struct GNUNET_CRYPTO_BlindingInputValues); 1259 bi->cipher = GNUNET_CRYPTO_BSA_CS; 1260 bi->rc = 1; 1261 { 1262 struct GNUNET_JSON_Specification ispec[] = { 1263 GNUNET_JSON_spec_fixed ( 1264 "r_pub_0", 1265 &bi->details.cs_values.r_pub[0], 1266 sizeof (struct GNUNET_CRYPTO_CsRPublic)), 1267 GNUNET_JSON_spec_fixed ( 1268 "r_pub_1", 1269 &bi->details.cs_values.r_pub[1], 1270 sizeof (struct GNUNET_CRYPTO_CsRPublic)), 1271 GNUNET_JSON_spec_end () 1272 }; 1273 1274 if (GNUNET_OK != 1275 GNUNET_JSON_parse (root, 1276 ispec, 1277 &emsg, 1278 &eline)) 1279 { 1280 GNUNET_break_op (0); 1281 GNUNET_free (bi); 1282 return GNUNET_SYSERR; 1283 } 1284 ewv->blinding_inputs = bi; 1285 return GNUNET_OK; 1286 } 1287 } 1288 GNUNET_break_op (0); 1289 return GNUNET_SYSERR; 1290 } 1291 1292 1293 /** 1294 * Cleanup data left from parsing withdraw values 1295 * 1296 * @param cls closure, NULL 1297 * @param[out] spec where to free the data 1298 */ 1299 static void 1300 clean_exchange_blinding_values ( 1301 void *cls, 1302 struct GNUNET_JSON_Specification *spec) 1303 { 1304 struct TALER_ExchangeBlindingValues *ewv = spec->ptr; 1305 1306 (void) cls; 1307 TALER_denom_ewv_free (ewv); 1308 } 1309 1310 1311 struct GNUNET_JSON_Specification 1312 TALER_JSON_spec_exchange_blinding_values ( 1313 const char *field, 1314 struct TALER_ExchangeBlindingValues *ewv) 1315 { 1316 struct GNUNET_JSON_Specification ret = { 1317 .parser = &parse_exchange_blinding_values, 1318 .cleaner = &clean_exchange_blinding_values, 1319 .field = field, 1320 .ptr = ewv 1321 }; 1322 1323 ewv->blinding_inputs = NULL; 1324 return ret; 1325 } 1326 1327 1328 /** 1329 * Closure for #parse_i18n_string. 1330 */ 1331 struct I18nContext 1332 { 1333 /** 1334 * Language pattern to match. 1335 */ 1336 char *lp; 1337 1338 /** 1339 * Name of the field to match. 1340 */ 1341 const char *field; 1342 }; 1343 1344 1345 /** 1346 * Parse given JSON object to internationalized string. 1347 * 1348 * @param cls closure, our `struct I18nContext *` 1349 * @param root the json object representing data 1350 * @param[out] spec where to write the data 1351 * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error 1352 */ 1353 static enum GNUNET_GenericReturnValue 1354 parse_i18n_string (void *cls, 1355 json_t *root, 1356 struct GNUNET_JSON_Specification *spec) 1357 { 1358 struct I18nContext *ctx = cls; 1359 json_t *i18n; 1360 json_t *val; 1361 1362 { 1363 char *i18nf; 1364 1365 GNUNET_asprintf (&i18nf, 1366 "%s_i18n", 1367 ctx->field); 1368 i18n = json_object_get (root, 1369 i18nf); 1370 GNUNET_free (i18nf); 1371 } 1372 1373 val = json_object_get (root, 1374 ctx->field); 1375 if ( (NULL != i18n) && 1376 (NULL != ctx->lp) ) 1377 { 1378 double best = 0.0; 1379 json_t *pos; 1380 const char *lang; 1381 1382 json_object_foreach (i18n, lang, pos) 1383 { 1384 double score; 1385 1386 score = TALER_pattern_matches (ctx->lp, 1387 lang); 1388 if (score > best) 1389 { 1390 best = score; 1391 val = pos; 1392 } 1393 } 1394 } 1395 1396 { 1397 const char *str; 1398 1399 str = json_string_value (val); 1400 *(const char **) spec->ptr = str; 1401 } 1402 return GNUNET_OK; 1403 } 1404 1405 1406 /** 1407 * Function called to clean up data from earlier parsing. 1408 * 1409 * @param cls closure 1410 * @param spec our specification entry with data to clean. 1411 */ 1412 static void 1413 i18n_cleaner (void *cls, 1414 struct GNUNET_JSON_Specification *spec) 1415 { 1416 struct I18nContext *ctx = cls; 1417 1418 (void) spec; 1419 if (NULL != ctx) 1420 { 1421 GNUNET_free (ctx->lp); 1422 GNUNET_free (ctx); 1423 } 1424 } 1425 1426 1427 struct GNUNET_JSON_Specification 1428 TALER_JSON_spec_i18n_string (const char *name, 1429 const char *language_pattern, 1430 const char **strptr) 1431 { 1432 struct I18nContext *ctx = GNUNET_new (struct I18nContext); 1433 struct GNUNET_JSON_Specification ret = { 1434 .parser = &parse_i18n_string, 1435 .cleaner = &i18n_cleaner, 1436 .cls = ctx, 1437 .field = NULL, /* we want the main object */ 1438 .ptr = strptr, 1439 .ptr_size = 0, 1440 .size_ptr = NULL 1441 }; 1442 1443 ctx->lp = (NULL != language_pattern) 1444 ? GNUNET_strdup (language_pattern) 1445 : NULL; 1446 ctx->field = name; 1447 *strptr = NULL; 1448 return ret; 1449 } 1450 1451 1452 struct GNUNET_JSON_Specification 1453 TALER_JSON_spec_i18n_str (const char *name, 1454 const char **strptr) 1455 { 1456 const char *lang = getenv ("LANG"); 1457 char *dot; 1458 char *l; 1459 struct GNUNET_JSON_Specification ret; 1460 1461 if (NULL != lang) 1462 { 1463 dot = strchr (lang, 1464 '.'); 1465 if (NULL == dot) 1466 l = GNUNET_strdup (lang); 1467 else 1468 l = GNUNET_strndup (lang, 1469 dot - lang); 1470 } 1471 else 1472 { 1473 l = NULL; 1474 } 1475 ret = TALER_JSON_spec_i18n_string (name, 1476 l, 1477 strptr); 1478 GNUNET_free (l); 1479 return ret; 1480 } 1481 1482 1483 /** 1484 * Parse given JSON object with Taler error code. 1485 * 1486 * @param cls closure, NULL 1487 * @param root the json object representing data 1488 * @param[out] spec where to write the data 1489 * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error 1490 */ 1491 static enum GNUNET_GenericReturnValue 1492 parse_ec (void *cls, 1493 json_t *root, 1494 struct GNUNET_JSON_Specification *spec) 1495 { 1496 enum TALER_ErrorCode *ec = spec->ptr; 1497 json_int_t num; 1498 1499 (void) cls; 1500 if (! json_is_integer (root)) 1501 { 1502 GNUNET_break_op (0); 1503 return GNUNET_SYSERR; 1504 } 1505 num = json_integer_value (root); 1506 if (num < 0) 1507 { 1508 GNUNET_break_op (0); 1509 *ec = TALER_EC_INVALID; 1510 return GNUNET_SYSERR; 1511 } 1512 *ec = (enum TALER_ErrorCode) num; 1513 return GNUNET_OK; 1514 } 1515 1516 1517 struct GNUNET_JSON_Specification 1518 TALER_JSON_spec_ec (const char *field, 1519 enum TALER_ErrorCode *ec) 1520 { 1521 struct GNUNET_JSON_Specification ret = { 1522 .parser = &parse_ec, 1523 .field = field, 1524 .ptr = ec 1525 }; 1526 1527 *ec = TALER_EC_NONE; 1528 return ret; 1529 } 1530 1531 1532 /** 1533 * Parse given JSON object to web URL. 1534 * 1535 * @param cls closure, NULL 1536 * @param root the json object representing data 1537 * @param[out] spec where to write the data 1538 * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error 1539 */ 1540 static enum GNUNET_GenericReturnValue 1541 parse_web_url (void *cls, 1542 json_t *root, 1543 struct GNUNET_JSON_Specification *spec) 1544 { 1545 const char *str; 1546 1547 (void) cls; 1548 str = json_string_value (root); 1549 if (NULL == str) 1550 { 1551 GNUNET_break_op (0); 1552 return GNUNET_SYSERR; 1553 } 1554 if (! TALER_is_web_url (str)) 1555 { 1556 GNUNET_break_op (0); 1557 return GNUNET_SYSERR; 1558 } 1559 *(const char **) spec->ptr = str; 1560 return GNUNET_OK; 1561 } 1562 1563 1564 struct GNUNET_JSON_Specification 1565 TALER_JSON_spec_web_url (const char *field, 1566 const char **url) 1567 { 1568 struct GNUNET_JSON_Specification ret = { 1569 .parser = &parse_web_url, 1570 .field = field, 1571 .ptr = url 1572 }; 1573 1574 *url = NULL; 1575 return ret; 1576 } 1577 1578 1579 /** 1580 * Parse given JSON object to web URL, and make a copy. 1581 * 1582 * @param cls closure, NULL 1583 * @param root the json object representing data 1584 * @param[out] spec where to write the data 1585 * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error 1586 */ 1587 static enum GNUNET_GenericReturnValue 1588 parse_web_url_copy (void *cls, 1589 json_t *root, 1590 struct GNUNET_JSON_Specification *spec) 1591 { 1592 const char *str; 1593 1594 (void) cls; 1595 str = json_string_value (root); 1596 if (NULL == str) 1597 { 1598 GNUNET_break_op (0); 1599 return GNUNET_SYSERR; 1600 } 1601 if (! TALER_is_web_url (str)) 1602 { 1603 GNUNET_break_op (0); 1604 return GNUNET_SYSERR; 1605 } 1606 *(char **) spec->ptr = GNUNET_strdup (str); 1607 return GNUNET_OK; 1608 } 1609 1610 1611 struct GNUNET_JSON_Specification 1612 TALER_JSON_spec_web_url_copy (const char *field, 1613 char **url) 1614 { 1615 struct GNUNET_JSON_Specification ret = { 1616 .parser = &parse_web_url_copy, 1617 .field = field, 1618 .ptr = url 1619 }; 1620 1621 *url = NULL; 1622 return ret; 1623 } 1624 1625 1626 /** 1627 * Parse given JSON object to slug. 1628 * 1629 * @param cls closure, NULL 1630 * @param root the json object representing data 1631 * @param[out] spec where to write the data 1632 * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error 1633 */ 1634 static enum GNUNET_GenericReturnValue 1635 parse_slug (void *cls, 1636 json_t *root, 1637 struct GNUNET_JSON_Specification *spec) 1638 { 1639 const char *str; 1640 1641 (void) cls; 1642 str = json_string_value (root); 1643 if (NULL == str) 1644 { 1645 GNUNET_break_op (0); 1646 return GNUNET_SYSERR; 1647 } 1648 if (! TALER_is_slug (str)) 1649 { 1650 GNUNET_break_op (0); 1651 return GNUNET_SYSERR; 1652 } 1653 *(const char **) spec->ptr = str; 1654 return GNUNET_OK; 1655 } 1656 1657 1658 struct GNUNET_JSON_Specification 1659 TALER_JSON_spec_slug (const char *field, 1660 const char **slug) 1661 { 1662 struct GNUNET_JSON_Specification ret = { 1663 .parser = &parse_slug, 1664 .field = field, 1665 .ptr = slug 1666 }; 1667 1668 *slug = NULL; 1669 return ret; 1670 } 1671 1672 1673 /** 1674 * Parse given JSON object to slug. 1675 * 1676 * @param cls closure, NULL 1677 * @param root the json object representing data 1678 * @param[out] spec where to write the data 1679 * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error 1680 */ 1681 static enum GNUNET_GenericReturnValue 1682 parse_slug_copy (void *cls, 1683 json_t *root, 1684 struct GNUNET_JSON_Specification *spec) 1685 { 1686 const char *str; 1687 1688 (void) cls; 1689 str = json_string_value (root); 1690 if (NULL == str) 1691 { 1692 GNUNET_break_op (0); 1693 return GNUNET_SYSERR; 1694 } 1695 if (! TALER_is_slug (str)) 1696 { 1697 GNUNET_break_op (0); 1698 return GNUNET_SYSERR; 1699 } 1700 *(char **) spec->ptr = GNUNET_strdup (str); 1701 return GNUNET_OK; 1702 } 1703 1704 1705 struct GNUNET_JSON_Specification 1706 TALER_JSON_spec_slug_copy (const char *field, 1707 char **slug) 1708 { 1709 struct GNUNET_JSON_Specification ret = { 1710 .parser = &parse_slug_copy, 1711 .field = field, 1712 .ptr = slug 1713 }; 1714 1715 *slug = NULL; 1716 return ret; 1717 } 1718 1719 1720 /** 1721 * Parse given JSON object to a session ID. 1722 * 1723 * @param cls closure, NULL 1724 * @param root the json object representing data 1725 * @param[out] spec where to write the data 1726 * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error 1727 */ 1728 static enum GNUNET_GenericReturnValue 1729 parse_session_id (void *cls, 1730 json_t *root, 1731 struct GNUNET_JSON_Specification *spec) 1732 { 1733 const char *str; 1734 1735 (void) cls; 1736 str = json_string_value (root); 1737 if (NULL == str) 1738 { 1739 GNUNET_break_op (0); 1740 return GNUNET_SYSERR; 1741 } 1742 if (! TALER_is_session_id (str)) 1743 { 1744 GNUNET_break_op (0); 1745 return GNUNET_SYSERR; 1746 } 1747 *(const char **) spec->ptr = str; 1748 return GNUNET_OK; 1749 } 1750 1751 1752 struct GNUNET_JSON_Specification 1753 TALER_JSON_spec_session_id (const char *field, 1754 const char **session_id) 1755 { 1756 struct GNUNET_JSON_Specification ret = { 1757 .parser = &parse_session_id, 1758 .field = field, 1759 .ptr = session_id 1760 }; 1761 1762 *session_id = NULL; 1763 return ret; 1764 } 1765 1766 1767 /** 1768 * Parse given JSON object to a session ID that must not be empty. 1769 * 1770 * @param cls closure, NULL 1771 * @param root the json object representing data 1772 * @param[out] spec where to write the data 1773 * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error 1774 */ 1775 static enum GNUNET_GenericReturnValue 1776 parse_nonempty_session_id (void *cls, 1777 json_t *root, 1778 struct GNUNET_JSON_Specification *spec) 1779 { 1780 if (GNUNET_OK != 1781 parse_session_id (cls, 1782 root, 1783 spec)) 1784 return GNUNET_SYSERR; 1785 if ('\0' == (*(const char **) spec->ptr)[0]) 1786 { 1787 GNUNET_break_op (0); 1788 return GNUNET_SYSERR; 1789 } 1790 return GNUNET_OK; 1791 } 1792 1793 1794 struct GNUNET_JSON_Specification 1795 TALER_JSON_spec_nonempty_session_id (const char *field, 1796 const char **session_id) 1797 { 1798 struct GNUNET_JSON_Specification ret = { 1799 .parser = &parse_nonempty_session_id, 1800 .field = field, 1801 .ptr = session_id 1802 }; 1803 1804 *session_id = NULL; 1805 return ret; 1806 } 1807 1808 1809 /** 1810 * Parse given JSON object to payto:// URI. 1811 * 1812 * @param cls closure, NULL 1813 * @param root the json object representing data 1814 * @param[out] spec where to write the data 1815 * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error 1816 */ 1817 static enum GNUNET_GenericReturnValue 1818 parse_full_payto_uri (void *cls, 1819 json_t *root, 1820 struct GNUNET_JSON_Specification *spec) 1821 { 1822 struct TALER_FullPayto *payto_uri = spec->ptr; 1823 const char *str; 1824 char *err; 1825 1826 (void) cls; 1827 str = json_string_value (root); 1828 if (NULL == str) 1829 { 1830 GNUNET_break_op (0); 1831 return GNUNET_SYSERR; 1832 } 1833 payto_uri->full_payto = (char *) str; 1834 err = TALER_payto_validate (*payto_uri); 1835 if (NULL != err) 1836 { 1837 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 1838 "payto:// malformed: %s\n", 1839 err); 1840 GNUNET_free (err); 1841 payto_uri->full_payto = NULL; 1842 return GNUNET_SYSERR; 1843 } 1844 return GNUNET_OK; 1845 } 1846 1847 1848 struct GNUNET_JSON_Specification 1849 TALER_JSON_spec_full_payto_uri ( 1850 const char *field, 1851 struct TALER_FullPayto *payto_uri) 1852 { 1853 struct GNUNET_JSON_Specification ret = { 1854 .parser = &parse_full_payto_uri, 1855 .field = field, 1856 .ptr = payto_uri 1857 }; 1858 1859 payto_uri->full_payto = NULL; 1860 return ret; 1861 } 1862 1863 1864 /** 1865 * Parse given JSON object to payto:// URI. 1866 * 1867 * @param cls closure, NULL 1868 * @param root the json object representing data 1869 * @param[out] spec where to write the data 1870 * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error 1871 */ 1872 static enum GNUNET_GenericReturnValue 1873 parse_normalized_payto_uri (void *cls, 1874 json_t *root, 1875 struct GNUNET_JSON_Specification *spec) 1876 { 1877 struct TALER_NormalizedPayto *payto_uri = spec->ptr; 1878 const char *str; 1879 1880 (void) cls; 1881 str = json_string_value (root); 1882 if (NULL == str) 1883 { 1884 GNUNET_break_op (0); 1885 return GNUNET_SYSERR; 1886 } 1887 payto_uri->normalized_payto = (char *) str; 1888 { 1889 char *err; 1890 1891 err = TALER_normalized_payto_validate (*payto_uri); 1892 if (NULL != err) 1893 { 1894 GNUNET_break_op (0); 1895 GNUNET_free (err); 1896 payto_uri->normalized_payto = NULL; 1897 return GNUNET_SYSERR; 1898 } 1899 } 1900 return GNUNET_OK; 1901 } 1902 1903 1904 struct GNUNET_JSON_Specification 1905 TALER_JSON_spec_normalized_payto_uri ( 1906 const char *field, 1907 struct TALER_NormalizedPayto *payto_uri) 1908 { 1909 struct GNUNET_JSON_Specification ret = { 1910 .parser = &parse_normalized_payto_uri, 1911 .field = field, 1912 .ptr = payto_uri 1913 }; 1914 1915 payto_uri->normalized_payto = NULL; 1916 return ret; 1917 } 1918 1919 1920 /** 1921 * Parse given JSON object with protocol version. 1922 * 1923 * @param cls closure, NULL 1924 * @param root the json object representing data 1925 * @param[out] spec where to write the data 1926 * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error 1927 */ 1928 static enum GNUNET_GenericReturnValue 1929 parse_protocol_version (void *cls, 1930 json_t *root, 1931 struct GNUNET_JSON_Specification *spec) 1932 { 1933 struct TALER_JSON_ProtocolVersion *pv = spec->ptr; 1934 const char *ver; 1935 char dummy; 1936 1937 (void) cls; 1938 if (! json_is_string (root)) 1939 { 1940 GNUNET_break_op (0); 1941 return GNUNET_SYSERR; 1942 } 1943 ver = json_string_value (root); 1944 if (3 != sscanf (ver, 1945 "%u:%u:%u%c", 1946 &pv->current, 1947 &pv->revision, 1948 &pv->age, 1949 &dummy)) 1950 { 1951 GNUNET_break_op (0); 1952 return GNUNET_SYSERR; 1953 } 1954 return GNUNET_OK; 1955 } 1956 1957 1958 struct GNUNET_JSON_Specification 1959 TALER_JSON_spec_version (const char *field, 1960 struct TALER_JSON_ProtocolVersion *ver) 1961 { 1962 struct GNUNET_JSON_Specification ret = { 1963 .parser = &parse_protocol_version, 1964 .field = field, 1965 .ptr = ver 1966 }; 1967 1968 return ret; 1969 } 1970 1971 1972 /** 1973 * Parse given JSON object to an OTP key. 1974 * 1975 * @param cls closure, NULL 1976 * @param root the json object representing data 1977 * @param[out] spec where to write the data 1978 * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error 1979 */ 1980 static enum GNUNET_GenericReturnValue 1981 parse_otp_key (void *cls, 1982 json_t *root, 1983 struct GNUNET_JSON_Specification *spec) 1984 { 1985 const char *pos_key; 1986 1987 (void) cls; 1988 pos_key = json_string_value (root); 1989 if (NULL == pos_key) 1990 { 1991 GNUNET_break_op (0); 1992 return GNUNET_SYSERR; 1993 } 1994 { 1995 size_t pos_key_length = strlen (pos_key); 1996 void *key; /* pos_key in binary */ 1997 size_t key_len; /* length of the key */ 1998 int dret; 1999 2000 key_len = pos_key_length * 5 / 8; 2001 key = GNUNET_malloc (key_len); 2002 dret = TALER_rfc3548_base32decode (pos_key, 2003 pos_key_length, 2004 key, 2005 key_len); 2006 if (-1 == dret) 2007 { 2008 GNUNET_free (key); 2009 GNUNET_break_op (0); 2010 return GNUNET_SYSERR; 2011 } 2012 GNUNET_free (key); 2013 } 2014 *(const char **) spec->ptr = pos_key; 2015 return GNUNET_OK; 2016 } 2017 2018 2019 struct GNUNET_JSON_Specification 2020 TALER_JSON_spec_otp_key (const char *name, 2021 const char **otp_key) 2022 { 2023 struct GNUNET_JSON_Specification ret = { 2024 .parser = &parse_otp_key, 2025 .field = name, 2026 .ptr = otp_key 2027 }; 2028 2029 *otp_key = NULL; 2030 return ret; 2031 } 2032 2033 2034 /** 2035 * Parse given JSON object to `enum TALER_MerchantConfirmationAlgorithm` 2036 * 2037 * @param cls closure, NULL 2038 * @param root the json object representing data 2039 * @param[out] spec where to write the data 2040 * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error 2041 */ 2042 static enum GNUNET_GenericReturnValue 2043 parse_otp_type (void *cls, 2044 json_t *root, 2045 struct GNUNET_JSON_Specification *spec) 2046 { 2047 static const struct Entry 2048 { 2049 const char *name; 2050 enum TALER_MerchantConfirmationAlgorithm val; 2051 } lt [] = { 2052 { .name = "NONE", 2053 .val = TALER_MCA_NONE }, 2054 { .name = "TOTP_WITHOUT_PRICE", 2055 .val = TALER_MCA_WITHOUT_PRICE }, 2056 { .name = "TOTP_WITH_PRICE", 2057 .val = TALER_MCA_WITH_PRICE }, 2058 { .name = "ECDSA_CHALLENGE", 2059 .val = TALER_MCA_ECDSA_CHALLENGE }, 2060 { .name = "EDDSA_CHALLENGE", 2061 .val = TALER_MCA_EDDSA_CHALLENGE }, 2062 { .name = NULL, 2063 .val = TALER_MCA_NONE }, 2064 }; 2065 enum TALER_MerchantConfirmationAlgorithm *res 2066 = (enum TALER_MerchantConfirmationAlgorithm *) spec->ptr; 2067 2068 (void) cls; 2069 if (json_is_string (root)) 2070 { 2071 const char *str; 2072 2073 str = json_string_value (root); 2074 if (NULL == str) 2075 { 2076 GNUNET_break_op (0); 2077 return GNUNET_SYSERR; 2078 } 2079 for (unsigned int i = 0; NULL != lt[i].name; i++) 2080 { 2081 if (0 == strcasecmp (str, 2082 lt[i].name)) 2083 { 2084 *res = lt[i].val; 2085 return GNUNET_OK; 2086 } 2087 } 2088 GNUNET_break_op (0); 2089 } 2090 if (json_is_integer (root)) 2091 { 2092 json_int_t val; 2093 2094 val = json_integer_value (root); 2095 for (unsigned int i = 0; NULL != lt[i].name; i++) 2096 { 2097 if (val == lt[i].val) 2098 { 2099 *res = lt[i].val; 2100 return GNUNET_OK; 2101 } 2102 } 2103 GNUNET_break_op (0); 2104 return GNUNET_SYSERR; 2105 } 2106 GNUNET_break_op (0); 2107 return GNUNET_SYSERR; 2108 } 2109 2110 2111 struct GNUNET_JSON_Specification 2112 TALER_JSON_spec_otp_type (const char *name, 2113 enum TALER_MerchantConfirmationAlgorithm *mca) 2114 { 2115 struct GNUNET_JSON_Specification ret = { 2116 .parser = &parse_otp_type, 2117 .field = name, 2118 .ptr = mca 2119 }; 2120 2121 *mca = TALER_MCA_NONE; 2122 return ret; 2123 } 2124 2125 2126 /** 2127 * Parse given JSON object to `enum TALER_KYCLOGIC_KycTriggerEvent` 2128 * 2129 * @param cls closure, NULL 2130 * @param root the json object representing data 2131 * @param[out] spec where to write the data 2132 * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error 2133 */ 2134 static enum GNUNET_GenericReturnValue 2135 parse_kycte (void *cls, 2136 json_t *root, 2137 struct GNUNET_JSON_Specification *spec) 2138 { 2139 static const struct Entry 2140 { 2141 const char *name; 2142 enum TALER_KYCLOGIC_KycTriggerEvent val; 2143 } lt [] = { 2144 { .name = "NONE", 2145 .val = TALER_KYCLOGIC_KYC_TRIGGER_NONE }, 2146 { .name = "WITHDRAW", 2147 .val = TALER_KYCLOGIC_KYC_TRIGGER_WITHDRAW }, 2148 { .name = "DEPOSIT", 2149 .val = TALER_KYCLOGIC_KYC_TRIGGER_DEPOSIT }, 2150 { .name = "MERGE", 2151 .val = TALER_KYCLOGIC_KYC_TRIGGER_P2P_RECEIVE }, 2152 { .name = "BALANCE", 2153 .val = TALER_KYCLOGIC_KYC_TRIGGER_WALLET_BALANCE }, 2154 { .name = "CLOSE", 2155 .val = TALER_KYCLOGIC_KYC_TRIGGER_RESERVE_CLOSE }, 2156 { .name = "AGGREGATE", 2157 .val = TALER_KYCLOGIC_KYC_TRIGGER_AGGREGATE }, 2158 { .name = "TRANSACTION", 2159 .val = TALER_KYCLOGIC_KYC_TRIGGER_TRANSACTION }, 2160 { .name = "REFUND", 2161 .val = TALER_KYCLOGIC_KYC_TRIGGER_REFUND }, 2162 { .name = NULL, 2163 .val = TALER_KYCLOGIC_KYC_TRIGGER_NONE }, 2164 }; 2165 enum TALER_KYCLOGIC_KycTriggerEvent *res 2166 = (enum TALER_KYCLOGIC_KycTriggerEvent *) spec->ptr; 2167 2168 (void) cls; 2169 if (json_is_string (root)) 2170 { 2171 const char *str; 2172 2173 str = json_string_value (root); 2174 if (NULL == str) 2175 { 2176 GNUNET_break_op (0); 2177 return GNUNET_SYSERR; 2178 } 2179 for (unsigned int i = 0; NULL != lt[i].name; i++) 2180 { 2181 if (0 == strcasecmp (str, 2182 lt[i].name)) 2183 { 2184 *res = lt[i].val; 2185 return GNUNET_OK; 2186 } 2187 } 2188 GNUNET_break_op (0); 2189 return GNUNET_SYSERR; 2190 } 2191 if (json_is_integer (root)) 2192 { 2193 json_int_t val; 2194 2195 val = json_integer_value (root); 2196 for (unsigned int i = 0; NULL != lt[i].name; i++) 2197 { 2198 if (val == lt[i].val) 2199 { 2200 *res = lt[i].val; 2201 return GNUNET_OK; 2202 } 2203 } 2204 GNUNET_break_op (0); 2205 return GNUNET_SYSERR; 2206 } 2207 GNUNET_break_op (0); 2208 return GNUNET_SYSERR; 2209 } 2210 2211 2212 struct GNUNET_JSON_Specification 2213 TALER_JSON_spec_kycte (const char *name, 2214 enum TALER_KYCLOGIC_KycTriggerEvent *kte) 2215 { 2216 struct GNUNET_JSON_Specification ret = { 2217 .parser = &parse_kycte, 2218 .field = name, 2219 .ptr = kte 2220 }; 2221 2222 *kte = TALER_KYCLOGIC_KYC_TRIGGER_NONE; 2223 return ret; 2224 } 2225 2226 2227 /** 2228 * Parser combinator of a tuple of parsers, for parsing 2229 * an array of expected size and element types. 2230 * 2231 * @param cls closure, array of specs, NULL terminated 2232 * @param root the json root 2233 * @param[out] spec where to write the data 2234 */ 2235 static enum GNUNET_GenericReturnValue 2236 parse_tuple_of (void *cls, 2237 json_t *root, 2238 struct GNUNET_JSON_Specification *spec) 2239 { 2240 struct GNUNET_JSON_Specification *specs = cls; 2241 static size_t max_specs = 100; 2242 bool found_end = false; 2243 2244 enum GNUNET_GenericReturnValue ret; 2245 2246 if (! json_is_array (root)) 2247 { 2248 return GNUNET_SYSERR; 2249 } 2250 2251 { 2252 size_t num; 2253 for (num = 0; num< max_specs; num++) 2254 { 2255 if (NULL == specs[num].parser) 2256 { 2257 found_end = true; 2258 break; 2259 } 2260 } 2261 GNUNET_assert (found_end); 2262 2263 if (num != json_array_size (root)) 2264 { 2265 GNUNET_break_op (0); 2266 return GNUNET_SYSERR; 2267 } 2268 } 2269 2270 { 2271 json_t *j_entry; 2272 size_t idx; 2273 2274 json_array_foreach (root, idx, j_entry) { 2275 ret = GNUNET_JSON_parse (j_entry, 2276 &specs[idx], 2277 NULL, 2278 NULL); 2279 if (GNUNET_OK != ret) 2280 { 2281 GNUNET_break_op (0); 2282 return GNUNET_SYSERR; 2283 } 2284 } 2285 } 2286 2287 return GNUNET_OK; 2288 } 2289 2290 2291 struct GNUNET_JSON_Specification 2292 TALER_JSON_spec_tuple_of ( 2293 const char *field, 2294 struct GNUNET_JSON_Specification specs[]) 2295 { 2296 struct GNUNET_JSON_Specification ret = { 2297 .parser = &parse_tuple_of, 2298 .field = field, 2299 .cls = specs 2300 }; 2301 2302 return ret; 2303 } 2304 2305 2306 /** 2307 * Parser for an array of unknown length but 2308 * of elements of the same type with the same 2309 * fixed length. 2310 * 2311 * @param cls closure, entry_size 2312 * @param root the json root 2313 * @param spec the output spec 2314 */ 2315 static enum GNUNET_GenericReturnValue 2316 parse_array_fixed (void *cls, 2317 json_t *root, 2318 struct GNUNET_JSON_Specification *spec) 2319 { 2320 enum GNUNET_GenericReturnValue ret; 2321 size_t entry_size = (size_t) cls; 2322 size_t num_entries; 2323 2324 GNUNET_assert (0< entry_size); 2325 num_entries = spec->ptr_size / entry_size; 2326 GNUNET_assert (0 < num_entries); 2327 2328 2329 if (! json_is_array (root)) 2330 { 2331 GNUNET_break_op (0); 2332 return GNUNET_SYSERR; 2333 } 2334 if (num_entries != json_array_size (root)) 2335 { 2336 GNUNET_break_op (0); 2337 return GNUNET_SYSERR; 2338 } 2339 2340 { 2341 json_t *j_entry; 2342 size_t idx; 2343 void *ptr = spec->ptr; 2344 void *end = spec->ptr + spec->ptr_size; 2345 2346 json_array_foreach (root, idx, j_entry) { 2347 struct GNUNET_JSON_Specification esp[] = { 2348 GNUNET_JSON_spec_fixed (NULL, 2349 ptr, 2350 entry_size), 2351 GNUNET_JSON_spec_end () 2352 }; 2353 GNUNET_assert (ptr < end); 2354 ret = GNUNET_JSON_parse (j_entry, 2355 esp, 2356 NULL, 2357 NULL); 2358 if (GNUNET_OK != ret) 2359 { 2360 GNUNET_break_op (0); 2361 return GNUNET_SYSERR; 2362 } 2363 ptr += entry_size; 2364 } 2365 } 2366 return GNUNET_OK; 2367 } 2368 2369 2370 struct GNUNET_JSON_Specification 2371 TALER_JSON_spec_array_fixed ( 2372 const char *field, 2373 size_t num_entries, 2374 void *entries, 2375 size_t entry_size) 2376 { 2377 struct GNUNET_JSON_Specification ret = { 2378 .parser = &parse_array_fixed, 2379 .ptr = entries, 2380 .ptr_size = entry_size * num_entries, 2381 .field = field, 2382 .cls = (void *) entry_size, 2383 }; 2384 2385 GNUNET_assert ((num_entries <= 1) || 2386 (entry_size * num_entries > entry_size)); 2387 return ret; 2388 } 2389 2390 2391 /** 2392 * Closure for the parser of arrays of fixed size data 2393 * of unknown array length 2394 */ 2395 struct closure_array_of_data 2396 { 2397 /** 2398 * Fixed (known) size per entry 2399 */ 2400 size_t entry_size; 2401 2402 /** 2403 * Pointer where to put the number of elements 2404 * allocated, i.e. the number of elements in the 2405 * json array. 2406 */ 2407 size_t *num_entries; 2408 }; 2409 2410 /** 2411 * Parser for an array of data of known element size, 2412 * but unknown array length 2413 */ 2414 static enum GNUNET_GenericReturnValue 2415 parse_array_of_data (void *cls, 2416 json_t *root, 2417 struct GNUNET_JSON_Specification *spec) 2418 { 2419 enum GNUNET_GenericReturnValue ret; 2420 struct closure_array_of_data *info = cls; 2421 size_t num_entries; 2422 2423 if (! json_is_array (root)) 2424 { 2425 GNUNET_break_op (0); 2426 return GNUNET_SYSERR; 2427 } 2428 num_entries = json_array_size (root); 2429 *info->num_entries = num_entries; 2430 if (0 == num_entries) 2431 { 2432 *(char **) spec->ptr = NULL; 2433 return GNUNET_OK; 2434 } 2435 2436 spec->ptr_size = num_entries * info->entry_size; 2437 GNUNET_assert (spec->ptr_size > num_entries); 2438 *((char **) spec->ptr) = GNUNET_malloc (spec->ptr_size); 2439 2440 { 2441 json_t *j_entry; 2442 size_t idx; 2443 char *ptr = *(char **) spec->ptr; 2444 char *end = ptr + spec->ptr_size; 2445 2446 json_array_foreach (root, idx, j_entry) { 2447 struct GNUNET_JSON_Specification esp[] = { 2448 GNUNET_JSON_spec_fixed (NULL, 2449 ptr, 2450 info->entry_size), 2451 GNUNET_JSON_spec_end () 2452 }; 2453 GNUNET_assert (ptr < end); 2454 ret = GNUNET_JSON_parse (j_entry, 2455 esp, 2456 NULL, 2457 NULL); 2458 if (GNUNET_OK != ret) 2459 { 2460 GNUNET_break_op (0); 2461 return GNUNET_SYSERR; 2462 } 2463 ptr += info->entry_size; 2464 } 2465 } 2466 return GNUNET_OK; 2467 } 2468 2469 2470 /** 2471 * Cleanup data left from parsing an array of fixed size (but unknown length). 2472 * 2473 * @param cls closure_of_array_data 2474 * @param[out] spec where to free the data 2475 */ 2476 static void 2477 cleaner_array_of_data (void *cls, 2478 struct GNUNET_JSON_Specification *spec) 2479 { 2480 struct closure_array_of_data *info = cls; 2481 2482 GNUNET_free (*(void **) spec->ptr); 2483 GNUNET_free (info); 2484 } 2485 2486 2487 struct GNUNET_JSON_Specification 2488 TALER_JSON_spec_array_of_data ( 2489 const char *field, 2490 size_t entry_size, 2491 size_t *num_entries, 2492 void **entries) 2493 { 2494 struct closure_array_of_data *cls; 2495 2496 GNUNET_assert (0< entry_size); 2497 *entries = NULL; 2498 *num_entries = 0; 2499 cls = GNUNET_new (struct closure_array_of_data); 2500 cls->num_entries = num_entries; 2501 cls->entry_size = entry_size; 2502 { 2503 struct GNUNET_JSON_Specification ret = { 2504 .parser = &parse_array_of_data, 2505 .ptr = entries, 2506 .field = field, 2507 .cleaner = &cleaner_array_of_data, 2508 .cls = (void *) cls, 2509 }; 2510 2511 return ret; 2512 } 2513 } 2514 2515 2516 struct GNUNET_JSON_Specification 2517 TALER_JSON_spec_array_of_denom_pub_h ( 2518 const char *field, 2519 size_t *num_entries, 2520 struct TALER_DenominationHashP **entries) 2521 { 2522 *num_entries = 0; 2523 *entries = NULL; 2524 return TALER_JSON_spec_array_of_data ( 2525 field, 2526 sizeof (struct TALER_DenominationHashP), 2527 num_entries, 2528 (void **) entries); 2529 } 2530 2531 2532 /** 2533 * Parser for an array of blinded denomination signatures, 2534 * of unknown array length 2535 */ 2536 static enum GNUNET_GenericReturnValue 2537 parse_array_of_blinded_denom_sigs (void *cls, 2538 json_t *root, 2539 struct GNUNET_JSON_Specification *spec) 2540 { 2541 enum GNUNET_GenericReturnValue ret; 2542 struct TALER_BlindedDenominationSignature *sigs = spec->ptr; 2543 size_t expected_num_entries = (size_t) cls; 2544 size_t num_entries; 2545 2546 if (! json_is_array (root)) 2547 { 2548 GNUNET_break_op (0); 2549 return GNUNET_SYSERR; 2550 } 2551 num_entries = json_array_size (root); 2552 if (num_entries != expected_num_entries) 2553 { 2554 GNUNET_break_op (0); 2555 return GNUNET_SYSERR; 2556 } 2557 2558 { 2559 json_t *j_entry; 2560 size_t idx; 2561 struct TALER_BlindedDenominationSignature *ptr = sigs; 2562 2563 json_array_foreach (root, idx, j_entry) { 2564 struct GNUNET_JSON_Specification esp[] = { 2565 TALER_JSON_spec_blinded_denom_sig (NULL, 2566 ptr), 2567 GNUNET_JSON_spec_end () 2568 }; 2569 ret = GNUNET_JSON_parse (j_entry, 2570 esp, 2571 NULL, 2572 NULL); 2573 if (GNUNET_OK != ret) 2574 { 2575 GNUNET_break_op (0); 2576 for (size_t i = 0; i < idx; i++) 2577 { 2578 TALER_blinded_denom_sig_free (&sigs[i]); 2579 sigs[i].blinded_sig = NULL; 2580 } 2581 return GNUNET_SYSERR; 2582 } 2583 ptr++; 2584 } 2585 } 2586 return GNUNET_OK; 2587 } 2588 2589 2590 /** 2591 * Cleanup data left from parsing an array of blinded signatures. 2592 * 2593 * @param cls pointer to a size_t with the length of the array 2594 * @param[out] spec where to free the data 2595 */ 2596 static void 2597 cleaner_array_of_blinded_denom_sigs ( 2598 void *cls, 2599 struct GNUNET_JSON_Specification *spec) 2600 { 2601 struct TALER_BlindedDenominationSignature *sigs = spec->ptr; 2602 size_t num_entries = (size_t) cls; 2603 2604 for (size_t i = 0; i < num_entries; i++) 2605 { 2606 if (NULL != sigs[i].blinded_sig) 2607 { 2608 TALER_blinded_denom_sig_free (&sigs[i]); 2609 sigs[i].blinded_sig = NULL; 2610 } 2611 } 2612 } 2613 2614 2615 struct GNUNET_JSON_Specification 2616 TALER_JSON_spec_array_of_blinded_denom_sigs ( 2617 const char *field, 2618 size_t num_entries, 2619 struct TALER_BlindedDenominationSignature *entries) 2620 { 2621 struct GNUNET_JSON_Specification ret = { 2622 .parser = &parse_array_of_blinded_denom_sigs, 2623 .ptr = entries, 2624 .field = field, 2625 .cleaner = &cleaner_array_of_blinded_denom_sigs, 2626 .cls = (void *) num_entries, 2627 }; 2628 2629 for (size_t i = 0; i<num_entries; i++) 2630 entries[i].blinded_sig = NULL; 2631 return ret; 2632 } 2633 2634 2635 /* end of json/json_helper.c */