anastasis_api_redux_parse.c (71375B)
1 /* 2 This file is part of Anastasis 3 Copyright (C) 2020, 2021, 2022 Anastasis SARL 4 5 Anastasis 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 Anastasis 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 Anastasis; see the file COPYING.GPL. If not, see <http://www.gnu.org/licenses/> 15 */ 16 /** 17 * @file reducer/anastasis_api_redux_parse.c 18 * @brief parse a reducer state from its JSON encoding 19 * @author Christian Grothoff 20 * 21 * Parsing is strict: every object is checked against the closed set of 22 * fields declared for it, so a typo or a field from a foreign reducer 23 * implementation is an error rather than something silently carried along. 24 * 25 * On any failure the partially built state is handed to 26 * ANASTASIS_REDUX_state_free_(), which is safe because every array length is 27 * assigned before the array is populated. 28 */ 29 #include "platform.h" 30 #include "anastasis_redux.h" 31 #include "anastasis_api_redux.h" 32 #include "anastasis_api_redux_state.h" 33 #include "validation.h" 34 #include <taler/taler_json_lib.h> 35 36 37 /** 38 * Buffer for the error detail returned by 39 * ANASTASIS_REDUX_state_parse_(). The reducer is single-threaded (it 40 * runs off the GNUnet scheduler), and the caller copies the detail into 41 * its error state immediately, so one static buffer is enough. 42 */ 43 static char parse_detail[256]; 44 45 46 /** 47 * Record @a field as the location of a parse error. 48 * 49 * @param where name of the enclosing object 50 * @param field offending field, may be NULL 51 * @return pointer to the formatted detail 52 */ 53 static const char * 54 set_detail (const char *where, 55 const char *field) 56 { 57 if (NULL == field) 58 GNUNET_snprintf (parse_detail, 59 sizeof (parse_detail), 60 "%s", 61 where); 62 else 63 GNUNET_snprintf (parse_detail, 64 sizeof (parse_detail), 65 "%s.%s", 66 where, 67 field); 68 return parse_detail; 69 } 70 71 72 /** 73 * Check that @a obj is an object and has no members beyond those listed 74 * in @a allowed. 75 * 76 * @param obj object to check 77 * @param where name of @a obj, for error reporting 78 * @param allowed NULL-terminated array of permitted field names 79 * @param[out] detail set to the offending field on failure 80 * @return #GNUNET_OK if @a obj is acceptable 81 */ 82 static enum GNUNET_GenericReturnValue 83 check_fields (const json_t *obj, 84 const char *where, 85 const char *const*allowed, 86 const char **detail) 87 { 88 const char *key; 89 json_t *val; 90 91 if (! json_is_object (obj)) 92 { 93 *detail = set_detail (where, 94 NULL); 95 return GNUNET_SYSERR; 96 } 97 json_object_foreach ((json_t *) obj, key, val) 98 { 99 bool found = false; 100 101 for (unsigned int i = 0; NULL != allowed[i]; i++) 102 if (0 == strcmp (key, 103 allowed[i])) 104 { 105 found = true; 106 break; 107 } 108 if (! found) 109 { 110 *detail = set_detail (where, 111 key); 112 return GNUNET_SYSERR; 113 } 114 } 115 return GNUNET_OK; 116 } 117 118 119 /** 120 * Duplicate @a s, or return NULL if @a s is NULL. 121 * 122 * @param s string to duplicate 123 * @return copy of @a s 124 */ 125 static char * 126 dup_or_null (const char *s) 127 { 128 if (NULL == s) 129 return NULL; 130 return GNUNET_strdup (s); 131 } 132 133 134 /** 135 * Take a reference to the i18n map @a obj, or return NULL. 136 * 137 * The reducer never looks inside a translation map; it only ever carries 138 * it from the resource files to the user interface. So there is nothing 139 * to type here, and the object is kept verbatim. 140 * 141 * @param obj object mapping language tags to strings, may be NULL 142 * @return new reference to @a obj, or NULL 143 */ 144 static json_t * 145 incref_or_null (const json_t *obj) 146 { 147 if (NULL == obj) 148 return NULL; 149 return json_incref ((json_t *) obj); 150 } 151 152 153 /** 154 * Parse the `continents` array. 155 * 156 * @param arr the array, may be NULL 157 * @param[out] common state to fill in 158 * @param[out] detail set to the offending field on failure 159 * @return #GNUNET_OK on success 160 */ 161 static enum GNUNET_GenericReturnValue 162 parse_continents (const json_t *arr, 163 struct ANASTASIS_ReduxCommon *common, 164 const char **detail) 165 { 166 static const char *const allowed[] = { 167 "name", 168 "name_i18n", 169 NULL 170 }; 171 size_t index; 172 json_t *val; 173 174 if (NULL == arr) 175 return GNUNET_OK; 176 if (! json_is_array (arr)) 177 { 178 *detail = set_detail ("continents", 179 NULL); 180 return GNUNET_SYSERR; 181 } 182 common->have_continents = true; 183 common->continents_len = (unsigned int) json_array_size (arr); 184 common->continents = GNUNET_new_array (common->continents_len, 185 struct ANASTASIS_ReduxContinent); 186 json_array_foreach (arr, index, val) 187 { 188 struct ANASTASIS_ReduxContinent *c = &common->continents[index]; 189 const char *name; 190 const json_t *i18n = NULL; 191 struct GNUNET_JSON_Specification spec[] = { 192 GNUNET_JSON_spec_string ("name", 193 &name), 194 GNUNET_JSON_spec_mark_optional ( 195 GNUNET_JSON_spec_object_const ("name_i18n", 196 &i18n), 197 NULL), 198 GNUNET_JSON_spec_end () 199 }; 200 201 if (json_is_string (val)) 202 { 203 /* hand-written states name continents directly */ 204 c->name = GNUNET_strdup (json_string_value (val)); 205 c->bare = true; 206 continue; 207 } 208 if (GNUNET_OK != 209 check_fields (val, 210 "continents", 211 allowed, 212 detail)) 213 return GNUNET_SYSERR; 214 if (GNUNET_OK != 215 GNUNET_JSON_parse (val, 216 spec, 217 NULL, NULL)) 218 { 219 *detail = set_detail ("continents", 220 "name"); 221 return GNUNET_SYSERR; 222 } 223 c->name = GNUNET_strdup (name); 224 c->name_i18n = incref_or_null (i18n); 225 } 226 return GNUNET_OK; 227 } 228 229 230 /** 231 * Parse the `countries` array. 232 * 233 * @param arr the array, may be NULL 234 * @param[out] common state to fill in 235 * @param[out] detail set to the offending field on failure 236 * @return #GNUNET_OK on success 237 */ 238 static enum GNUNET_GenericReturnValue 239 parse_countries (const json_t *arr, 240 struct ANASTASIS_ReduxCommon *common, 241 const char **detail) 242 { 243 static const char *const allowed[] = { 244 "code", 245 "name", 246 "continent", 247 "call_code", 248 "name_i18n", 249 "continent_i18n", 250 "currency", 251 NULL 252 }; 253 size_t index; 254 json_t *val; 255 256 if (NULL == arr) 257 return GNUNET_OK; 258 if (! json_is_array (arr)) 259 { 260 *detail = set_detail ("countries", 261 NULL); 262 return GNUNET_SYSERR; 263 } 264 common->have_countries = true; 265 common->countries_len = (unsigned int) json_array_size (arr); 266 common->countries = GNUNET_new_array (common->countries_len, 267 struct ANASTASIS_ReduxCountry); 268 json_array_foreach (arr, index, val) 269 { 270 struct ANASTASIS_ReduxCountry *c = &common->countries[index]; 271 const char *code; 272 const char *name; 273 const char *continent; 274 const char *call_code = NULL; 275 const char *currency = NULL; 276 const json_t *name_i18n = NULL; 277 const json_t *continent_i18n = NULL; 278 struct GNUNET_JSON_Specification spec[] = { 279 GNUNET_JSON_spec_string ("code", 280 &code), 281 GNUNET_JSON_spec_string ("name", 282 &name), 283 GNUNET_JSON_spec_string ("continent", 284 &continent), 285 GNUNET_JSON_spec_mark_optional ( 286 GNUNET_JSON_spec_string ("call_code", 287 &call_code), 288 NULL), 289 GNUNET_JSON_spec_mark_optional ( 290 GNUNET_JSON_spec_object_const ("name_i18n", 291 &name_i18n), 292 NULL), 293 GNUNET_JSON_spec_mark_optional ( 294 GNUNET_JSON_spec_object_const ("continent_i18n", 295 &continent_i18n), 296 NULL), 297 GNUNET_JSON_spec_mark_optional ( 298 GNUNET_JSON_spec_string ("currency", 299 ¤cy), 300 NULL), 301 GNUNET_JSON_spec_end () 302 }; 303 304 if (GNUNET_OK != 305 check_fields (val, 306 "countries", 307 allowed, 308 detail)) 309 return GNUNET_SYSERR; 310 if (GNUNET_OK != 311 GNUNET_JSON_parse (val, 312 spec, 313 NULL, NULL)) 314 { 315 *detail = set_detail ("countries", 316 NULL); 317 return GNUNET_SYSERR; 318 } 319 c->code = GNUNET_strdup (code); 320 c->name = GNUNET_strdup (name); 321 c->continent = GNUNET_strdup (continent); 322 c->call_code = dup_or_null (call_code); 323 c->currency = dup_or_null (currency); 324 c->name_i18n = incref_or_null (name_i18n); 325 c->continent_i18n = incref_or_null (continent_i18n); 326 } 327 return GNUNET_OK; 328 } 329 330 331 /** 332 * Parse the `required_attributes` array. 333 * 334 * @param arr the array, may be NULL 335 * @param[out] common state to fill in 336 * @param[out] detail set to the offending field on failure 337 * @return #GNUNET_OK on success 338 */ 339 static enum GNUNET_GenericReturnValue 340 parse_required_attributes (const json_t *arr, 341 struct ANASTASIS_ReduxCommon *common, 342 const char **detail) 343 { 344 static const char *const allowed[] = { 345 "type", 346 "name", 347 "label", 348 "widget", 349 "uuid", 350 "tooltip", 351 "label_i18n", 352 "validation-regex", 353 "validation-logic", 354 "autocomplete", 355 "optional", 356 NULL 357 }; 358 size_t index; 359 json_t *val; 360 361 if (NULL == arr) 362 return GNUNET_OK; 363 if (! json_is_array (arr)) 364 { 365 *detail = set_detail ("required_attributes", 366 NULL); 367 return GNUNET_SYSERR; 368 } 369 common->have_required_attributes = true; 370 common->required_attributes_len = (unsigned int) json_array_size (arr); 371 common->required_attributes 372 = GNUNET_new_array (common->required_attributes_len, 373 struct ANASTASIS_ReduxAttributeSpec); 374 json_array_foreach (arr, index, val) 375 { 376 struct ANASTASIS_ReduxAttributeSpec *a 377 = &common->required_attributes[index]; 378 const char *type; 379 const char *name; 380 const char *label; 381 const char *widget; 382 const char *uuid = NULL; 383 const char *tooltip = NULL; 384 const char *regex = NULL; 385 const char *logic = NULL; 386 const char *autocomplete = NULL; 387 const json_t *label_i18n = NULL; 388 bool no_optional; 389 struct GNUNET_JSON_Specification spec[] = { 390 GNUNET_JSON_spec_string ("type", 391 &type), 392 GNUNET_JSON_spec_string ("name", 393 &name), 394 GNUNET_JSON_spec_string ("label", 395 &label), 396 GNUNET_JSON_spec_string ("widget", 397 &widget), 398 GNUNET_JSON_spec_mark_optional ( 399 GNUNET_JSON_spec_string ("uuid", 400 &uuid), 401 NULL), 402 GNUNET_JSON_spec_mark_optional ( 403 GNUNET_JSON_spec_string ("tooltip", 404 &tooltip), 405 NULL), 406 GNUNET_JSON_spec_mark_optional ( 407 GNUNET_JSON_spec_string ("validation-regex", 408 ®ex), 409 NULL), 410 GNUNET_JSON_spec_mark_optional ( 411 GNUNET_JSON_spec_string ("validation-logic", 412 &logic), 413 NULL), 414 GNUNET_JSON_spec_mark_optional ( 415 GNUNET_JSON_spec_string ("autocomplete", 416 &autocomplete), 417 NULL), 418 GNUNET_JSON_spec_mark_optional ( 419 GNUNET_JSON_spec_object_const ("label_i18n", 420 &label_i18n), 421 NULL), 422 GNUNET_JSON_spec_mark_optional ( 423 GNUNET_JSON_spec_bool ("optional", 424 &a->optional), 425 &no_optional), 426 GNUNET_JSON_spec_end () 427 }; 428 429 if (GNUNET_OK != 430 check_fields (val, 431 "required_attributes", 432 allowed, 433 detail)) 434 return GNUNET_SYSERR; 435 if (GNUNET_OK != 436 GNUNET_JSON_parse (val, 437 spec, 438 NULL, NULL)) 439 { 440 *detail = set_detail ("required_attributes", 441 NULL); 442 return GNUNET_SYSERR; 443 } 444 a->type = GNUNET_strdup (type); 445 a->name = GNUNET_strdup (name); 446 a->label = GNUNET_strdup (label); 447 a->widget = GNUNET_strdup (widget); 448 a->uuid = dup_or_null (uuid); 449 a->tooltip = dup_or_null (tooltip); 450 a->validation_regex = dup_or_null (regex); 451 if ( (NULL != logic) && 452 (NULL == ANASTASIS_REDUX_validation_lookup_ (logic)) ) 453 { 454 /* reject unknown validation logic already here, so that it cannot even 455 be round-tripped through a state we hand back to the application */ 456 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 457 "Validation function `%s' is not known\n", 458 logic); 459 *detail = set_detail ("required_attributes", 460 "validation-logic"); 461 return GNUNET_SYSERR; 462 } 463 a->validation_logic = dup_or_null (logic); 464 a->autocomplete = dup_or_null (autocomplete); 465 a->have_optional = ! no_optional; 466 a->label_i18n = incref_or_null (label_i18n); 467 } 468 return GNUNET_OK; 469 } 470 471 472 /** 473 * Parse one entry of the `authentication_providers` object. 474 * 475 * @param url the provider URL (the key) 476 * @param val the provider details (the value) 477 * @param[out] p provider entry to fill in 478 * @param[out] detail set to the offending field on failure 479 * @return #GNUNET_OK on success 480 */ 481 static enum GNUNET_GenericReturnValue 482 parse_provider (const char *url, 483 const json_t *val, 484 struct ANASTASIS_ReduxProvider *p, 485 const char **detail) 486 { 487 static const char *const allowed[] = { 488 "status", 489 "methods", 490 "annual_fee", 491 "annual_fees", 492 "truth_upload_fee", 493 "truth_upload_fees", 494 "liability_limit", 495 "liability_limits", 496 "business_name", 497 "storage_limit_in_megabytes", 498 "provider_salt", 499 "http_status", 500 "error_code", 501 "currency", 502 "currencies", 503 NULL 504 }; 505 const char *status; 506 struct GNUNET_JSON_Specification sspec[] = { 507 GNUNET_JSON_spec_string ("status", 508 &status), 509 GNUNET_JSON_spec_end () 510 }; 511 512 ANASTASIS_REDUX_provider_url_set_ (&p->url, 513 url); 514 if (GNUNET_OK != 515 check_fields (val, 516 "authentication_providers", 517 allowed, 518 detail)) 519 return GNUNET_SYSERR; 520 if (GNUNET_OK != 521 GNUNET_JSON_parse (val, 522 sspec, 523 NULL, NULL)) 524 { 525 *detail = set_detail ("authentication_providers", 526 "status"); 527 return GNUNET_SYSERR; 528 } 529 if (0 == strcmp (status, 530 "not-contacted")) 531 { 532 p->status = ANASTASIS_RPS_NOT_CONTACTED; 533 return GNUNET_OK; 534 } 535 if (0 == strcmp (status, 536 "error")) 537 { 538 uint64_t ec = 0; 539 struct GNUNET_JSON_Specification espec[] = { 540 GNUNET_JSON_spec_mark_optional ( 541 GNUNET_JSON_spec_uint64 ("error_code", 542 &ec), 543 NULL), 544 GNUNET_JSON_spec_mark_optional ( 545 GNUNET_JSON_spec_uint32 ("http_status", 546 &p->error.http_status), 547 NULL), 548 GNUNET_JSON_spec_end () 549 }; 550 551 p->status = ANASTASIS_RPS_ERROR; 552 if (GNUNET_OK != 553 GNUNET_JSON_parse (val, 554 espec, 555 NULL, NULL)) 556 { 557 *detail = set_detail ("authentication_providers", 558 "error_code"); 559 return GNUNET_SYSERR; 560 } 561 p->error.ec = (enum TALER_ErrorCode) ec; 562 return GNUNET_OK; 563 } 564 if (0 == strcmp (status, 565 "ok")) 566 p->status = ANASTASIS_RPS_OK; 567 else if (0 == strcmp (status, 568 "disabled")) 569 p->status = ANASTASIS_RPS_DISABLED; 570 else 571 { 572 *detail = set_detail ("authentication_providers", 573 "status"); 574 return GNUNET_SYSERR; 575 } 576 577 /* Both "ok" and (usually) "disabled" carry the /config we obtained 578 earlier; a provider that was disabled before we ever talked to it 579 does not. */ 580 { 581 struct ANASTASIS_ReduxProviderConfig *cfg = &p->config; 582 const char *business_name; 583 const char *currency = NULL; 584 const json_t *methods; 585 const json_t *currencies = NULL; 586 bool no_config = false; 587 struct GNUNET_JSON_Specification cspec[] = { 588 GNUNET_JSON_spec_array_const ("methods", 589 &methods), 590 TALER_JSON_spec_amount_any ("annual_fee", 591 &cfg->annual_fee), 592 TALER_JSON_spec_amount_any ("truth_upload_fee", 593 &cfg->truth_upload_fee), 594 TALER_JSON_spec_amount_any ("liability_limit", 595 &cfg->liability_limit), 596 /* Optional so that a state serialized by an older reducer still 597 parses; synthesized from the scalars below when absent. */ 598 GNUNET_JSON_spec_mark_optional ( 599 TALER_JSON_spec_amount_list ("annual_fees", 600 &cfg->annual_fees), 601 NULL), 602 GNUNET_JSON_spec_mark_optional ( 603 TALER_JSON_spec_amount_list ("truth_upload_fees", 604 &cfg->truth_upload_fees), 605 NULL), 606 GNUNET_JSON_spec_mark_optional ( 607 TALER_JSON_spec_amount_list ("liability_limits", 608 &cfg->liability_limits), 609 NULL), 610 GNUNET_JSON_spec_mark_optional ( 611 GNUNET_JSON_spec_array_const ("currencies", 612 ¤cies), 613 NULL), 614 GNUNET_JSON_spec_string ("business_name", 615 &business_name), 616 GNUNET_JSON_spec_uint32 ("storage_limit_in_megabytes", 617 &cfg->storage_limit_in_megabytes), 618 GNUNET_JSON_spec_fixed_auto ("provider_salt", 619 &cfg->provider_salt), 620 GNUNET_JSON_spec_uint32 ("http_status", 621 &cfg->http_status), 622 GNUNET_JSON_spec_mark_optional ( 623 GNUNET_JSON_spec_string ("currency", 624 ¤cy), 625 NULL), 626 GNUNET_JSON_spec_end () 627 }; 628 size_t index; 629 json_t *m; 630 631 if (NULL == json_object_get (val, 632 "methods")) 633 no_config = true; 634 if (no_config) 635 { 636 if (ANASTASIS_RPS_OK == p->status) 637 { 638 *detail = set_detail ("authentication_providers", 639 "methods"); 640 return GNUNET_SYSERR; 641 } 642 return GNUNET_OK; 643 } 644 if (GNUNET_OK != 645 GNUNET_JSON_parse (val, 646 cspec, 647 NULL, NULL)) 648 { 649 *detail = set_detail ("authentication_providers", 650 NULL); 651 return GNUNET_SYSERR; 652 } 653 p->have_config = true; 654 cfg->business_name = GNUNET_strdup (business_name); 655 cfg->currency = dup_or_null (currency); 656 if (0 == cfg->annual_fees.tal_len) 657 GNUNET_array_append (cfg->annual_fees.tal, 658 cfg->annual_fees.tal_len, 659 cfg->annual_fee); 660 if (0 == cfg->truth_upload_fees.tal_len) 661 GNUNET_array_append (cfg->truth_upload_fees.tal, 662 cfg->truth_upload_fees.tal_len, 663 cfg->truth_upload_fee); 664 if (0 == cfg->liability_limits.tal_len) 665 GNUNET_array_append (cfg->liability_limits.tal, 666 cfg->liability_limits.tal_len, 667 cfg->liability_limit); 668 if (NULL != currencies) 669 { 670 size_t cidx; 671 json_t *cv; 672 673 json_array_foreach (currencies, cidx, cv) 674 { 675 if (! json_is_string (cv)) 676 { 677 *detail = set_detail ("authentication_providers", 678 "currencies"); 679 return GNUNET_SYSERR; 680 } 681 GNUNET_array_append (cfg->currencies, 682 cfg->currencies_len, 683 GNUNET_strdup (json_string_value (cv))); 684 } 685 } 686 if (0 == cfg->currencies_len) 687 GNUNET_array_append (cfg->currencies, 688 cfg->currencies_len, 689 GNUNET_strdup (cfg->annual_fee.currency)); 690 cfg->methods_len = (unsigned int) json_array_size (methods); 691 cfg->methods = GNUNET_new_array (cfg->methods_len, 692 struct ANASTASIS_ReduxMethodSpec); 693 json_array_foreach (methods, index, m) 694 { 695 static const char *const mallowed[] = { 696 "type", 697 "usage_fee", 698 "usage_fees", 699 NULL 700 }; 701 struct ANASTASIS_ReduxMethodSpec *ms = &cfg->methods[index]; 702 const char *type; 703 struct GNUNET_JSON_Specification mspec[] = { 704 GNUNET_JSON_spec_string ("type", 705 &type), 706 TALER_JSON_spec_amount_any ("usage_fee", 707 &ms->usage_fee), 708 GNUNET_JSON_spec_mark_optional ( 709 TALER_JSON_spec_amount_list ("usage_fees", 710 &ms->usage_fees), 711 NULL), 712 GNUNET_JSON_spec_end () 713 }; 714 715 if (GNUNET_OK != 716 check_fields (m, 717 "authentication_providers.methods", 718 mallowed, 719 detail)) 720 return GNUNET_SYSERR; 721 if (GNUNET_OK != 722 GNUNET_JSON_parse (m, 723 mspec, 724 NULL, NULL)) 725 { 726 *detail = set_detail ("authentication_providers.methods", 727 NULL); 728 return GNUNET_SYSERR; 729 } 730 ms->type = GNUNET_strdup (type); 731 if (0 == ms->usage_fees.tal_len) 732 GNUNET_array_append (ms->usage_fees.tal, 733 ms->usage_fees.tal_len, 734 ms->usage_fee); 735 } 736 } 737 return GNUNET_OK; 738 } 739 740 741 /** 742 * Parse the `authentication_providers` object. 743 * 744 * @param obj the object, may be NULL 745 * @param[out] common state to fill in 746 * @param[out] detail set to the offending field on failure 747 * @return #GNUNET_OK on success 748 */ 749 static enum GNUNET_GenericReturnValue 750 parse_providers (const json_t *obj, 751 struct ANASTASIS_ReduxCommon *common, 752 const char **detail) 753 { 754 const char *url; 755 json_t *val; 756 unsigned int off = 0; 757 758 if (NULL == obj) 759 return GNUNET_OK; 760 if (! json_is_object (obj)) 761 { 762 *detail = set_detail ("authentication_providers", 763 NULL); 764 return GNUNET_SYSERR; 765 } 766 common->have_providers = true; 767 common->providers_len = (unsigned int) json_object_size (obj); 768 common->providers = GNUNET_new_array (common->providers_len, 769 struct ANASTASIS_ReduxProvider); 770 json_object_foreach ((json_t *) obj, url, val) 771 { 772 if (GNUNET_OK != 773 parse_provider (url, 774 val, 775 &common->providers[off], 776 detail)) 777 return GNUNET_SYSERR; 778 off++; 779 } 780 return GNUNET_OK; 781 } 782 783 784 /** 785 * Parse the fields shared by the backup and recovery variants. 786 * 787 * @param json the state 788 * @param[out] common state to fill in 789 * @param[out] detail set to the offending field on failure 790 * @return #GNUNET_OK on success 791 */ 792 static enum GNUNET_GenericReturnValue 793 parse_common (const json_t *json, 794 struct ANASTASIS_ReduxCommon *common, 795 const char **detail) 796 { 797 const json_t *continents = NULL; 798 const json_t *countries = NULL; 799 const json_t *required_attributes = NULL; 800 const json_t *providers = NULL; 801 const json_t *identity_attributes = NULL; 802 const json_t *currencies = NULL; 803 const char *selected_continent = NULL; 804 const char *selected_country = NULL; 805 const char *preferred_currency = NULL; 806 struct GNUNET_JSON_Specification spec[] = { 807 GNUNET_JSON_spec_mark_optional ( 808 GNUNET_JSON_spec_array_const ("continents", 809 &continents), 810 NULL), 811 GNUNET_JSON_spec_mark_optional ( 812 GNUNET_JSON_spec_array_const ("countries", 813 &countries), 814 NULL), 815 GNUNET_JSON_spec_mark_optional ( 816 GNUNET_JSON_spec_array_const ("required_attributes", 817 &required_attributes), 818 NULL), 819 GNUNET_JSON_spec_mark_optional ( 820 GNUNET_JSON_spec_object_const ("authentication_providers", 821 &providers), 822 NULL), 823 GNUNET_JSON_spec_mark_optional ( 824 GNUNET_JSON_spec_object_const ("identity_attributes", 825 &identity_attributes), 826 NULL), 827 GNUNET_JSON_spec_mark_optional ( 828 GNUNET_JSON_spec_array_const ("currencies", 829 ¤cies), 830 NULL), 831 GNUNET_JSON_spec_mark_optional ( 832 GNUNET_JSON_spec_string ("selected_continent", 833 &selected_continent), 834 NULL), 835 GNUNET_JSON_spec_mark_optional ( 836 GNUNET_JSON_spec_string ("selected_country", 837 &selected_country), 838 NULL), 839 GNUNET_JSON_spec_mark_optional ( 840 GNUNET_JSON_spec_string ("preferred_currency", 841 &preferred_currency), 842 NULL), 843 GNUNET_JSON_spec_end () 844 }; 845 846 if (GNUNET_OK != 847 GNUNET_JSON_parse (json, 848 spec, 849 NULL, NULL)) 850 { 851 *detail = set_detail ("state", 852 NULL); 853 return GNUNET_SYSERR; 854 } 855 common->selected_continent = dup_or_null (selected_continent); 856 common->selected_country = dup_or_null (selected_country); 857 common->preferred_currency = dup_or_null (preferred_currency); 858 common->identity_attributes = json_incref ((json_t *) identity_attributes); 859 if (NULL != currencies) 860 { 861 size_t index; 862 json_t *val; 863 864 common->have_currencies = true; 865 common->currencies_len = (unsigned int) json_array_size (currencies); 866 common->currencies = GNUNET_new_array (common->currencies_len, 867 char *); 868 json_array_foreach (currencies, index, val) 869 { 870 if (! json_is_string (val)) 871 { 872 *detail = set_detail ("currencies", 873 NULL); 874 return GNUNET_SYSERR; 875 } 876 common->currencies[index] = GNUNET_strdup (json_string_value (val)); 877 } 878 } 879 if ( (GNUNET_OK != 880 parse_continents (continents, 881 common, 882 detail)) || 883 (GNUNET_OK != 884 parse_countries (countries, 885 common, 886 detail)) || 887 (GNUNET_OK != 888 parse_required_attributes (required_attributes, 889 common, 890 detail)) || 891 (GNUNET_OK != 892 parse_providers (providers, 893 common, 894 detail)) ) 895 return GNUNET_SYSERR; 896 return GNUNET_OK; 897 } 898 899 900 /** 901 * Parse the `authentication_methods` array. 902 * 903 * @param arr the array, may be NULL 904 * @param[out] b backup state to fill in 905 * @param[out] detail set to the offending field on failure 906 * @return #GNUNET_OK on success 907 */ 908 static enum GNUNET_GenericReturnValue 909 parse_auth_methods (const json_t *arr, 910 struct ANASTASIS_ReduxBackup *b, 911 const char **detail) 912 { 913 static const char *const allowed[] = { 914 "type", 915 "instructions", 916 "challenge", 917 "mime_type", 918 NULL 919 }; 920 size_t index; 921 json_t *val; 922 923 if (NULL == arr) 924 return GNUNET_OK; 925 b->have_authentication_methods = true; 926 b->authentication_methods_len = (unsigned int) json_array_size (arr); 927 b->authentication_methods 928 = GNUNET_new_array (b->authentication_methods_len, 929 struct ANASTASIS_ReduxAuthMethod); 930 json_array_foreach (arr, index, val) 931 { 932 struct ANASTASIS_ReduxAuthMethod *am = &b->authentication_methods[index]; 933 const char *type; 934 const char *instructions; 935 const char *mime_type = NULL; 936 void *challenge; 937 size_t challenge_size; 938 struct GNUNET_JSON_Specification spec[] = { 939 GNUNET_JSON_spec_string ("type", 940 &type), 941 GNUNET_JSON_spec_string ("instructions", 942 &instructions), 943 GNUNET_JSON_spec_varsize ("challenge", 944 &challenge, 945 &challenge_size), 946 GNUNET_JSON_spec_mark_optional ( 947 GNUNET_JSON_spec_string ("mime_type", 948 &mime_type), 949 NULL), 950 GNUNET_JSON_spec_end () 951 }; 952 953 if (GNUNET_OK != 954 check_fields (val, 955 "authentication_methods", 956 allowed, 957 detail)) 958 return GNUNET_SYSERR; 959 if (GNUNET_OK != 960 GNUNET_JSON_parse (val, 961 spec, 962 NULL, NULL)) 963 { 964 *detail = set_detail ("authentication_methods", 965 NULL); 966 return GNUNET_SYSERR; 967 } 968 am->type = GNUNET_strdup (type); 969 am->instructions = GNUNET_strdup (instructions); 970 am->mime_type = dup_or_null (mime_type); 971 am->challenge = GNUNET_memdup (challenge, 972 challenge_size); 973 am->challenge_size = challenge_size; 974 GNUNET_JSON_parse_free (spec); 975 } 976 return GNUNET_OK; 977 } 978 979 980 /** 981 * Parse the `policies` array. 982 * 983 * @param arr the array, may be NULL 984 * @param[out] b backup state to fill in 985 * @param[out] detail set to the offending field on failure 986 * @return #GNUNET_OK on success 987 */ 988 static enum GNUNET_GenericReturnValue 989 parse_policies (const json_t *arr, 990 struct ANASTASIS_ReduxBackup *b, 991 const char **detail) 992 { 993 static const char *const pallowed[] = { 994 "methods", 995 "recovery_cost", 996 NULL 997 }; 998 static const char *const mallowed[] = { 999 "authentication_method", 1000 "provider", 1001 "truth", 1002 NULL 1003 }; 1004 size_t index; 1005 json_t *val; 1006 1007 if (NULL == arr) 1008 return GNUNET_OK; 1009 b->have_policies = true; 1010 b->policies_len = (unsigned int) json_array_size (arr); 1011 b->policies = GNUNET_new_array (b->policies_len, 1012 struct ANASTASIS_ReduxPolicy); 1013 json_array_foreach (arr, index, val) 1014 { 1015 struct ANASTASIS_ReduxPolicy *p = &b->policies[index]; 1016 const json_t *methods; 1017 size_t mindex; 1018 json_t *m; 1019 bool no_cost; 1020 struct GNUNET_JSON_Specification spec[] = { 1021 GNUNET_JSON_spec_array_const ("methods", 1022 &methods), 1023 GNUNET_JSON_spec_mark_optional ( 1024 TALER_JSON_spec_amount_any ("recovery_cost", 1025 &p->recovery_cost), 1026 &no_cost), 1027 GNUNET_JSON_spec_end () 1028 }; 1029 1030 if (GNUNET_OK != 1031 check_fields (val, 1032 "policies", 1033 pallowed, 1034 detail)) 1035 return GNUNET_SYSERR; 1036 if (GNUNET_OK != 1037 GNUNET_JSON_parse (val, 1038 spec, 1039 NULL, NULL)) 1040 { 1041 *detail = set_detail ("policies", 1042 "methods"); 1043 return GNUNET_SYSERR; 1044 } 1045 p->have_recovery_cost = ! no_cost; 1046 p->methods_len = (unsigned int) json_array_size (methods); 1047 p->methods = GNUNET_new_array (p->methods_len, 1048 struct ANASTASIS_ReduxPolicyMethod); 1049 json_array_foreach (methods, mindex, m) 1050 { 1051 struct ANASTASIS_ReduxPolicyMethod *pm = &p->methods[mindex]; 1052 const char *provider; 1053 const json_t *truth = NULL; 1054 struct GNUNET_JSON_Specification mspec[] = { 1055 GNUNET_JSON_spec_uint32 ("authentication_method", 1056 &pm->authentication_method.idx), 1057 GNUNET_JSON_spec_string ("provider", 1058 &provider), 1059 GNUNET_JSON_spec_mark_optional ( 1060 GNUNET_JSON_spec_object_const ("truth", 1061 &truth), 1062 NULL), 1063 GNUNET_JSON_spec_end () 1064 }; 1065 1066 if (GNUNET_OK != 1067 check_fields (m, 1068 "policies.methods", 1069 mallowed, 1070 detail)) 1071 return GNUNET_SYSERR; 1072 if (GNUNET_OK != 1073 GNUNET_JSON_parse (m, 1074 mspec, 1075 NULL, NULL)) 1076 { 1077 *detail = set_detail ("policies.methods", 1078 NULL); 1079 return GNUNET_SYSERR; 1080 } 1081 ANASTASIS_REDUX_provider_url_set_ (&pm->provider, 1082 provider); 1083 if (NULL != truth) 1084 { 1085 uint32_t us; 1086 struct GNUNET_JSON_Specification tspec[] = { 1087 GNUNET_JSON_spec_uint32 ("upload_status", 1088 &us), 1089 GNUNET_JSON_spec_end () 1090 }; 1091 1092 if (GNUNET_OK != 1093 GNUNET_JSON_parse (truth, 1094 tspec, 1095 NULL, NULL)) 1096 { 1097 *detail = set_detail ("policies.methods.truth", 1098 "upload_status"); 1099 return GNUNET_SYSERR; 1100 } 1101 pm->upload_status = (enum ANASTASIS_UploadStatus) us; 1102 pm->truth = ANASTASIS_truth_from_json (truth); 1103 if (NULL == pm->truth) 1104 { 1105 *detail = set_detail ("policies.methods", 1106 "truth"); 1107 return GNUNET_SYSERR; 1108 } 1109 } 1110 } 1111 } 1112 return GNUNET_OK; 1113 } 1114 1115 1116 /** 1117 * Parse the `policy_providers` array. 1118 * 1119 * @param arr the array, may be NULL 1120 * @param[out] b backup state to fill in 1121 * @param[out] detail set to the offending field on failure 1122 * @return #GNUNET_OK on success 1123 */ 1124 static enum GNUNET_GenericReturnValue 1125 parse_policy_providers (const json_t *arr, 1126 struct ANASTASIS_ReduxBackup *b, 1127 const char **detail) 1128 { 1129 static const char *const allowed[] = { 1130 "provider_url", 1131 "payment_secret", 1132 NULL 1133 }; 1134 size_t index; 1135 json_t *val; 1136 1137 if (NULL == arr) 1138 return GNUNET_OK; 1139 b->have_policy_providers = true; 1140 b->policy_providers_len = (unsigned int) json_array_size (arr); 1141 b->policy_providers = GNUNET_new_array (b->policy_providers_len, 1142 struct 1143 ANASTASIS_ReduxPolicyProvider); 1144 json_array_foreach (arr, index, val) 1145 { 1146 struct ANASTASIS_ReduxPolicyProvider *pp = &b->policy_providers[index]; 1147 const char *url; 1148 bool no_ps; 1149 struct GNUNET_JSON_Specification spec[] = { 1150 GNUNET_JSON_spec_string ("provider_url", 1151 &url), 1152 GNUNET_JSON_spec_mark_optional ( 1153 GNUNET_JSON_spec_fixed_auto ("payment_secret", 1154 &pp->payment_secret), 1155 &no_ps), 1156 GNUNET_JSON_spec_end () 1157 }; 1158 1159 if (GNUNET_OK != 1160 check_fields (val, 1161 "policy_providers", 1162 allowed, 1163 detail)) 1164 return GNUNET_SYSERR; 1165 if (GNUNET_OK != 1166 GNUNET_JSON_parse (val, 1167 spec, 1168 NULL, NULL)) 1169 { 1170 *detail = set_detail ("policy_providers", 1171 NULL); 1172 return GNUNET_SYSERR; 1173 } 1174 ANASTASIS_REDUX_provider_url_set_ (&pp->provider_url, 1175 url); 1176 pp->have_payment_secret = ! no_ps; 1177 } 1178 return GNUNET_OK; 1179 } 1180 1181 1182 /** 1183 * Parse the `success_details` object. 1184 * 1185 * @param obj the object, may be NULL 1186 * @param[out] b backup state to fill in 1187 * @param[out] detail set to the offending field on failure 1188 * @return #GNUNET_OK on success 1189 */ 1190 static enum GNUNET_GenericReturnValue 1191 parse_success_details (const json_t *obj, 1192 struct ANASTASIS_ReduxBackup *b, 1193 const char **detail) 1194 { 1195 static const char *const allowed[] = { 1196 "policy_version", 1197 "policy_expiration", 1198 NULL 1199 }; 1200 const char *url; 1201 json_t *val; 1202 unsigned int off = 0; 1203 1204 if (NULL == obj) 1205 return GNUNET_OK; 1206 b->have_success_details = true; 1207 b->success_details_len = (unsigned int) json_object_size (obj); 1208 b->success_details = GNUNET_new_array (b->success_details_len, 1209 struct ANASTASIS_ReduxSuccessDetail); 1210 json_object_foreach ((json_t *) obj, url, val) 1211 { 1212 struct ANASTASIS_ReduxSuccessDetail *sd = &b->success_details[off]; 1213 struct GNUNET_JSON_Specification spec[] = { 1214 GNUNET_JSON_spec_uint32 ("policy_version", 1215 &sd->policy_version), 1216 GNUNET_JSON_spec_timestamp ("policy_expiration", 1217 &sd->policy_expiration), 1218 GNUNET_JSON_spec_end () 1219 }; 1220 1221 if (GNUNET_OK != 1222 check_fields (val, 1223 "success_details", 1224 allowed, 1225 detail)) 1226 return GNUNET_SYSERR; 1227 if (GNUNET_OK != 1228 GNUNET_JSON_parse (val, 1229 spec, 1230 NULL, NULL)) 1231 { 1232 *detail = set_detail ("success_details", 1233 NULL); 1234 return GNUNET_SYSERR; 1235 } 1236 ANASTASIS_REDUX_provider_url_set_ (&sd->provider_url, 1237 url); 1238 off++; 1239 } 1240 return GNUNET_OK; 1241 } 1242 1243 1244 /** 1245 * Parse the backup-specific parts of @a json. 1246 * 1247 * @param json the state 1248 * @param[out] b backup state to fill in 1249 * @param[out] detail set to the offending field on failure 1250 * @return #GNUNET_OK on success 1251 */ 1252 static enum GNUNET_GenericReturnValue 1253 parse_backup (const json_t *json, 1254 struct ANASTASIS_ReduxBackup *b, 1255 const char **detail) 1256 { 1257 const char *state_str; 1258 const json_t *auth_methods = NULL; 1259 const json_t *policies = NULL; 1260 const json_t *policy_providers = NULL; 1261 const json_t *upload_fees = NULL; 1262 const json_t *payments = NULL; 1263 const json_t *policy_payment_requests = NULL; 1264 const json_t *success_details = NULL; 1265 const json_t *core_secret = NULL; 1266 const json_t *pay_arguments = NULL; 1267 const char *secret_name = NULL; 1268 bool no_expiration; 1269 struct GNUNET_JSON_Specification spec[] = { 1270 GNUNET_JSON_spec_string ("backup_state", 1271 &state_str), 1272 GNUNET_JSON_spec_mark_optional ( 1273 GNUNET_JSON_spec_array_const ("authentication_methods", 1274 &auth_methods), 1275 NULL), 1276 GNUNET_JSON_spec_mark_optional ( 1277 GNUNET_JSON_spec_array_const ("policies", 1278 &policies), 1279 NULL), 1280 GNUNET_JSON_spec_mark_optional ( 1281 GNUNET_JSON_spec_array_const ("policy_providers", 1282 &policy_providers), 1283 NULL), 1284 GNUNET_JSON_spec_mark_optional ( 1285 GNUNET_JSON_spec_array_const ("upload_fees", 1286 &upload_fees), 1287 NULL), 1288 GNUNET_JSON_spec_mark_optional ( 1289 GNUNET_JSON_spec_array_const ("payments", 1290 &payments), 1291 NULL), 1292 GNUNET_JSON_spec_mark_optional ( 1293 GNUNET_JSON_spec_array_const ("policy_payment_requests", 1294 &policy_payment_requests), 1295 NULL), 1296 GNUNET_JSON_spec_mark_optional ( 1297 GNUNET_JSON_spec_object_const ("success_details", 1298 &success_details), 1299 NULL), 1300 GNUNET_JSON_spec_mark_optional ( 1301 GNUNET_JSON_spec_object_const ("core_secret", 1302 &core_secret), 1303 NULL), 1304 GNUNET_JSON_spec_mark_optional ( 1305 GNUNET_JSON_spec_object_const ("pay_arguments", 1306 &pay_arguments), 1307 NULL), 1308 GNUNET_JSON_spec_mark_optional ( 1309 GNUNET_JSON_spec_string ("secret_name", 1310 &secret_name), 1311 NULL), 1312 GNUNET_JSON_spec_mark_optional ( 1313 GNUNET_JSON_spec_timestamp ("expiration", 1314 &b->expiration), 1315 &no_expiration), 1316 GNUNET_JSON_spec_end () 1317 }; 1318 1319 if (GNUNET_OK != 1320 GNUNET_JSON_parse (json, 1321 spec, 1322 NULL, NULL)) 1323 { 1324 *detail = set_detail ("state", 1325 "backup_state"); 1326 return GNUNET_SYSERR; 1327 } 1328 b->state = ANASTASIS_backup_state_from_string_ (state_str); 1329 if (ANASTASIS_BACKUP_STATE_INVALID == b->state) 1330 { 1331 *detail = set_detail ("state", 1332 "backup_state"); 1333 return GNUNET_SYSERR; 1334 } 1335 b->have_expiration = ! no_expiration; 1336 b->secret_name = dup_or_null (secret_name); 1337 b->core_secret = json_incref ((json_t *) core_secret); 1338 if ( (GNUNET_OK != 1339 parse_auth_methods (auth_methods, 1340 b, 1341 detail)) || 1342 (GNUNET_OK != 1343 parse_policies (policies, 1344 b, 1345 detail)) || 1346 (GNUNET_OK != 1347 parse_policy_providers (policy_providers, 1348 b, 1349 detail)) || 1350 (GNUNET_OK != 1351 parse_success_details (success_details, 1352 b, 1353 detail)) ) 1354 return GNUNET_SYSERR; 1355 if (NULL != upload_fees) 1356 { 1357 static const char *const allowed[] = { 1358 "fee", 1359 NULL 1360 }; 1361 size_t index; 1362 json_t *val; 1363 1364 b->have_upload_fees = true; 1365 b->upload_fees_len = (unsigned int) json_array_size (upload_fees); 1366 b->upload_fees = GNUNET_new_array (b->upload_fees_len, 1367 struct TALER_Amount); 1368 json_array_foreach (upload_fees, index, val) 1369 { 1370 struct GNUNET_JSON_Specification fspec[] = { 1371 TALER_JSON_spec_amount_any ("fee", 1372 &b->upload_fees[index]), 1373 GNUNET_JSON_spec_end () 1374 }; 1375 1376 if ( (GNUNET_OK != 1377 check_fields (val, 1378 "upload_fees", 1379 allowed, 1380 detail)) || 1381 (GNUNET_OK != 1382 GNUNET_JSON_parse (val, 1383 fspec, 1384 NULL, NULL)) ) 1385 { 1386 *detail = set_detail ("upload_fees", 1387 "fee"); 1388 return GNUNET_SYSERR; 1389 } 1390 } 1391 } 1392 if (NULL != payments) 1393 { 1394 size_t index; 1395 json_t *val; 1396 1397 b->have_payments = true; 1398 b->payments_len = (unsigned int) json_array_size (payments); 1399 b->payments = GNUNET_new_array (b->payments_len, 1400 char *); 1401 json_array_foreach (payments, index, val) 1402 { 1403 if (! json_is_string (val)) 1404 { 1405 *detail = set_detail ("payments", 1406 NULL); 1407 return GNUNET_SYSERR; 1408 } 1409 b->payments[index] = GNUNET_strdup (json_string_value (val)); 1410 } 1411 } 1412 if (NULL != policy_payment_requests) 1413 { 1414 static const char *const allowed[] = { 1415 "payto", 1416 "provider", 1417 NULL 1418 }; 1419 size_t index; 1420 json_t *val; 1421 1422 b->have_policy_payment_requests = true; 1423 b->policy_payment_requests_len 1424 = (unsigned int) json_array_size (policy_payment_requests); 1425 b->policy_payment_requests 1426 = GNUNET_new_array (b->policy_payment_requests_len, 1427 struct ANASTASIS_ReduxPolicyPaymentRequest); 1428 json_array_foreach (policy_payment_requests, index, val) 1429 { 1430 struct ANASTASIS_ReduxPolicyPaymentRequest *ppr 1431 = &b->policy_payment_requests[index]; 1432 const char *payto; 1433 const char *provider; 1434 struct GNUNET_JSON_Specification pspec[] = { 1435 GNUNET_JSON_spec_string ("payto", 1436 &payto), 1437 GNUNET_JSON_spec_string ("provider", 1438 &provider), 1439 GNUNET_JSON_spec_end () 1440 }; 1441 1442 if ( (GNUNET_OK != 1443 check_fields (val, 1444 "policy_payment_requests", 1445 allowed, 1446 detail)) || 1447 (GNUNET_OK != 1448 GNUNET_JSON_parse (val, 1449 pspec, 1450 NULL, NULL)) ) 1451 { 1452 *detail = set_detail ("policy_payment_requests", 1453 NULL); 1454 return GNUNET_SYSERR; 1455 } 1456 ppr->payto = GNUNET_strdup (payto); 1457 ANASTASIS_REDUX_provider_url_set_ (&ppr->provider, 1458 provider); 1459 } 1460 } 1461 if (NULL != pay_arguments) 1462 { 1463 static const char *const allowed[] = { 1464 "timeout", 1465 NULL 1466 }; 1467 bool no_timeout; 1468 struct GNUNET_JSON_Specification pspec[] = { 1469 GNUNET_JSON_spec_mark_optional ( 1470 GNUNET_JSON_spec_relative_time ("timeout", 1471 &b->pay_arguments.timeout), 1472 &no_timeout), 1473 GNUNET_JSON_spec_end () 1474 }; 1475 1476 if ( (GNUNET_OK != 1477 check_fields (pay_arguments, 1478 "pay_arguments", 1479 allowed, 1480 detail)) || 1481 (GNUNET_OK != 1482 GNUNET_JSON_parse (pay_arguments, 1483 pspec, 1484 NULL, NULL)) ) 1485 { 1486 *detail = set_detail ("pay_arguments", 1487 "timeout"); 1488 return GNUNET_SYSERR; 1489 } 1490 b->have_pay_arguments = true; 1491 b->pay_arguments.have_timeout = ! no_timeout; 1492 } 1493 return GNUNET_OK; 1494 } 1495 1496 1497 /** 1498 * Parse the `recovery_information` object. 1499 * 1500 * @param obj the object 1501 * @param[out] rr recovery state to fill in 1502 * @param[out] detail set to the offending field on failure 1503 * @return #GNUNET_OK on success 1504 */ 1505 static enum GNUNET_GenericReturnValue 1506 parse_recovery_info (const json_t *obj, 1507 struct ANASTASIS_ReduxRecovery *rr, 1508 const char **detail) 1509 { 1510 static const char *const allowed[] = { 1511 "challenges", 1512 "policies", 1513 "secret_name", 1514 "provider_url", 1515 "version", 1516 NULL 1517 }; 1518 static const char *const callowed[] = { 1519 "uuid", 1520 "uuid-display", 1521 "type", 1522 "instructions", 1523 "answer", 1524 "payment_secret", 1525 NULL 1526 }; 1527 static const char *const pallowed[] = { 1528 "uuid", 1529 NULL 1530 }; 1531 struct ANASTASIS_ReduxRecoveryInfo *ri; 1532 const json_t *challenges; 1533 const json_t *policies; 1534 const char *secret_name = NULL; 1535 const char *provider_url; 1536 size_t index; 1537 json_t *val; 1538 struct GNUNET_JSON_Specification spec[] = { 1539 GNUNET_JSON_spec_array_const ("challenges", 1540 &challenges), 1541 GNUNET_JSON_spec_array_const ("policies", 1542 &policies), 1543 GNUNET_JSON_spec_mark_optional ( 1544 GNUNET_JSON_spec_string ("secret_name", 1545 &secret_name), 1546 NULL), 1547 GNUNET_JSON_spec_string ("provider_url", 1548 &provider_url), 1549 GNUNET_JSON_spec_end () 1550 }; 1551 1552 ri = GNUNET_new (struct ANASTASIS_ReduxRecoveryInfo); 1553 rr->ri = ri; 1554 if (GNUNET_OK != 1555 check_fields (obj, 1556 "recovery_information", 1557 allowed, 1558 detail)) 1559 return GNUNET_SYSERR; 1560 { 1561 struct GNUNET_JSON_Specification vspec[] = { 1562 GNUNET_JSON_spec_uint32 ("version", 1563 &ri->version), 1564 GNUNET_JSON_spec_end () 1565 }; 1566 1567 if (GNUNET_OK != 1568 GNUNET_JSON_parse (obj, 1569 vspec, 1570 NULL, NULL)) 1571 { 1572 *detail = set_detail ("recovery_information", 1573 "version"); 1574 return GNUNET_SYSERR; 1575 } 1576 } 1577 if (GNUNET_OK != 1578 GNUNET_JSON_parse (obj, 1579 spec, 1580 NULL, NULL)) 1581 { 1582 *detail = set_detail ("recovery_information", 1583 NULL); 1584 return GNUNET_SYSERR; 1585 } 1586 ri->secret_name = dup_or_null (secret_name); 1587 ANASTASIS_REDUX_provider_url_set_ (&ri->provider_url, 1588 provider_url); 1589 ri->challenges_len = (unsigned int) json_array_size (challenges); 1590 ri->challenges = GNUNET_new_array (ri->challenges_len, 1591 struct ANASTASIS_ReduxChallengeInfo); 1592 json_array_foreach (challenges, index, val) 1593 { 1594 struct ANASTASIS_ReduxChallengeInfo *ci = &ri->challenges[index]; 1595 const char *type; 1596 const char *instructions; 1597 const char *answer = NULL; 1598 bool no_ps; 1599 struct GNUNET_JSON_Specification cspec[] = { 1600 GNUNET_JSON_spec_fixed_auto ("uuid", 1601 &ci->uuid), 1602 GNUNET_JSON_spec_string ("type", 1603 &type), 1604 GNUNET_JSON_spec_string ("instructions", 1605 &instructions), 1606 GNUNET_JSON_spec_mark_optional ( 1607 GNUNET_JSON_spec_string ("answer", 1608 &answer), 1609 NULL), 1610 GNUNET_JSON_spec_mark_optional ( 1611 GNUNET_JSON_spec_fixed_auto ("payment_secret", 1612 &ci->payment_secret), 1613 &no_ps), 1614 GNUNET_JSON_spec_end () 1615 }; 1616 1617 if (GNUNET_OK != 1618 check_fields (val, 1619 "recovery_information.challenges", 1620 callowed, 1621 detail)) 1622 return GNUNET_SYSERR; 1623 if (GNUNET_OK != 1624 GNUNET_JSON_parse (val, 1625 cspec, 1626 NULL, NULL)) 1627 { 1628 *detail = set_detail ("recovery_information.challenges", 1629 NULL); 1630 return GNUNET_SYSERR; 1631 } 1632 ci->type = GNUNET_strdup (type); 1633 ci->instructions = GNUNET_strdup (instructions); 1634 ci->answer = dup_or_null (answer); 1635 ci->have_payment_secret = ! no_ps; 1636 } 1637 ri->policies_len = (unsigned int) json_array_size (policies); 1638 ri->policies = GNUNET_new_array (ri->policies_len, 1639 struct ANASTASIS_ReduxRecoveryPolicy); 1640 json_array_foreach (policies, index, val) 1641 { 1642 struct ANASTASIS_ReduxRecoveryPolicy *p = &ri->policies[index]; 1643 size_t uindex; 1644 json_t *u; 1645 1646 if (! json_is_array (val)) 1647 { 1648 *detail = set_detail ("recovery_information", 1649 "policies"); 1650 return GNUNET_SYSERR; 1651 } 1652 p->uuids_len = (unsigned int) json_array_size (val); 1653 p->uuids = GNUNET_new_array (p->uuids_len, 1654 struct ANASTASIS_CRYPTO_TruthUUIDP); 1655 json_array_foreach (val, uindex, u) 1656 { 1657 struct GNUNET_JSON_Specification uspec[] = { 1658 GNUNET_JSON_spec_fixed_auto ("uuid", 1659 &p->uuids[uindex]), 1660 GNUNET_JSON_spec_end () 1661 }; 1662 1663 if ( (GNUNET_OK != 1664 check_fields (u, 1665 "recovery_information.policies", 1666 pallowed, 1667 detail)) || 1668 (GNUNET_OK != 1669 GNUNET_JSON_parse (u, 1670 uspec, 1671 NULL, NULL)) ) 1672 { 1673 *detail = set_detail ("recovery_information.policies", 1674 "uuid"); 1675 return GNUNET_SYSERR; 1676 } 1677 } 1678 } 1679 return GNUNET_OK; 1680 } 1681 1682 1683 /** 1684 * Parse one entry of the `challenge_feedback` object. 1685 * 1686 * @param val the feedback details 1687 * @param[out] fb feedback entry to fill in 1688 * @param[out] detail set to the offending field on failure 1689 * @return #GNUNET_OK on success 1690 */ 1691 static enum GNUNET_GenericReturnValue 1692 parse_feedback_details (const json_t *val, 1693 struct ANASTASIS_ReduxFeedback *fb, 1694 const char **detail) 1695 { 1696 static const char *const allowed[] = { 1697 "state", 1698 "display_hint", 1699 "filename", 1700 "address_hint", 1701 "taler_pay_uri", 1702 "provider", 1703 "payment_secret", 1704 "http_status", 1705 "error_code", 1706 "target_iban", 1707 "target_business_name", 1708 "wire_transfer_subject", 1709 "challenge_amount", 1710 "request_limit", 1711 "request_frequency", 1712 NULL 1713 }; 1714 const char *state; 1715 const char *display_hint = NULL; 1716 struct GNUNET_JSON_Specification spec[] = { 1717 GNUNET_JSON_spec_string ("state", 1718 &state), 1719 GNUNET_JSON_spec_mark_optional ( 1720 GNUNET_JSON_spec_string ("display_hint", 1721 &display_hint), 1722 NULL), 1723 GNUNET_JSON_spec_end () 1724 }; 1725 1726 if (GNUNET_OK != 1727 check_fields (val, 1728 "challenge_feedback", 1729 allowed, 1730 detail)) 1731 return GNUNET_SYSERR; 1732 if (GNUNET_OK != 1733 GNUNET_JSON_parse (val, 1734 spec, 1735 NULL, NULL)) 1736 { 1737 *detail = set_detail ("challenge_feedback", 1738 "state"); 1739 return GNUNET_SYSERR; 1740 } 1741 fb->display_hint = dup_or_null (display_hint); 1742 if (0 == strcmp (state, 1743 "code-in-file")) 1744 { 1745 const char *filename; 1746 struct GNUNET_JSON_Specification dspec[] = { 1747 GNUNET_JSON_spec_string ("filename", 1748 &filename), 1749 GNUNET_JSON_spec_end () 1750 }; 1751 1752 fb->status = ANASTASIS_RFS_CODE_IN_FILE; 1753 if (GNUNET_OK != 1754 GNUNET_JSON_parse (val, 1755 dspec, 1756 NULL, NULL)) 1757 { 1758 *detail = set_detail ("challenge_feedback", 1759 "filename"); 1760 return GNUNET_SYSERR; 1761 } 1762 fb->details.code_in_file.filename = GNUNET_strdup (filename); 1763 return GNUNET_OK; 1764 } 1765 if (0 == strcmp (state, 1766 "send-to-address")) 1767 { 1768 const char *address_hint = NULL; 1769 struct GNUNET_JSON_Specification dspec[] = { 1770 GNUNET_JSON_spec_mark_optional ( 1771 GNUNET_JSON_spec_string ("address_hint", 1772 &address_hint), 1773 NULL), 1774 GNUNET_JSON_spec_end () 1775 }; 1776 1777 fb->status = ANASTASIS_RFS_SEND_TO_ADDRESS; 1778 if (GNUNET_OK != 1779 GNUNET_JSON_parse (val, 1780 dspec, 1781 NULL, NULL)) 1782 { 1783 *detail = set_detail ("challenge_feedback", 1784 "address_hint"); 1785 return GNUNET_SYSERR; 1786 } 1787 fb->details.send_to_address.address_hint = dup_or_null (address_hint); 1788 return GNUNET_OK; 1789 } 1790 if (0 == strcmp (state, 1791 "taler-payment")) 1792 { 1793 const char *uri; 1794 const char *provider; 1795 struct GNUNET_JSON_Specification dspec[] = { 1796 GNUNET_JSON_spec_string ("taler_pay_uri", 1797 &uri), 1798 GNUNET_JSON_spec_string ("provider", 1799 &provider), 1800 GNUNET_JSON_spec_fixed_auto ("payment_secret", 1801 &fb->details.taler_payment.payment_secret), 1802 GNUNET_JSON_spec_end () 1803 }; 1804 1805 fb->status = ANASTASIS_RFS_TALER_PAYMENT; 1806 if (GNUNET_OK != 1807 GNUNET_JSON_parse (val, 1808 dspec, 1809 NULL, NULL)) 1810 { 1811 *detail = set_detail ("challenge_feedback", 1812 "taler_pay_uri"); 1813 return GNUNET_SYSERR; 1814 } 1815 fb->details.taler_payment.taler_pay_uri = GNUNET_strdup (uri); 1816 ANASTASIS_REDUX_provider_url_set_ (&fb->details.taler_payment.provider, 1817 provider); 1818 return GNUNET_OK; 1819 } 1820 if ( (0 == strcmp (state, 1821 "server-failure")) || 1822 (0 == strcmp (state, 1823 "truth-unknown")) ) 1824 { 1825 uint64_t ec; 1826 struct GNUNET_JSON_Specification dspec[] = { 1827 GNUNET_JSON_spec_uint64 ("error_code", 1828 &ec), 1829 GNUNET_JSON_spec_uint32 ("http_status", 1830 &fb->details.server_failure.http_status), 1831 GNUNET_JSON_spec_end () 1832 }; 1833 1834 fb->status = (0 == strcmp (state, 1835 "server-failure")) 1836 ? ANASTASIS_RFS_SERVER_FAILURE 1837 : ANASTASIS_RFS_TRUTH_UNKNOWN; 1838 if (GNUNET_OK != 1839 GNUNET_JSON_parse (val, 1840 dspec, 1841 NULL, NULL)) 1842 { 1843 *detail = set_detail ("challenge_feedback", 1844 "error_code"); 1845 return GNUNET_SYSERR; 1846 } 1847 fb->details.server_failure.ec = (enum TALER_ErrorCode) ec; 1848 return GNUNET_OK; 1849 } 1850 if (0 == strcmp (state, 1851 "iban-instructions")) 1852 { 1853 const char *iban; 1854 const char *business_name; 1855 const char *subject; 1856 struct GNUNET_JSON_Specification dspec[] = { 1857 GNUNET_JSON_spec_string ("target_iban", 1858 &iban), 1859 GNUNET_JSON_spec_string ("target_business_name", 1860 &business_name), 1861 GNUNET_JSON_spec_string ("wire_transfer_subject", 1862 &subject), 1863 TALER_JSON_spec_amount_any ("challenge_amount", 1864 &fb->details.iban_instructions.amount), 1865 GNUNET_JSON_spec_end () 1866 }; 1867 1868 fb->status = ANASTASIS_RFS_IBAN_INSTRUCTIONS; 1869 if (GNUNET_OK != 1870 GNUNET_JSON_parse (val, 1871 dspec, 1872 NULL, NULL)) 1873 { 1874 *detail = set_detail ("challenge_feedback", 1875 "target_iban"); 1876 return GNUNET_SYSERR; 1877 } 1878 fb->details.iban_instructions.target_iban = GNUNET_strdup (iban); 1879 fb->details.iban_instructions.target_business_name 1880 = GNUNET_strdup (business_name); 1881 fb->details.iban_instructions.wire_transfer_subject 1882 = GNUNET_strdup (subject); 1883 return GNUNET_OK; 1884 } 1885 if (0 == strcmp (state, 1886 "solved")) 1887 { 1888 fb->status = ANASTASIS_RFS_SOLVED; 1889 return GNUNET_OK; 1890 } 1891 if (0 == strcmp (state, 1892 "incorrect-answer")) 1893 { 1894 uint64_t ec; 1895 struct GNUNET_JSON_Specification dspec[] = { 1896 GNUNET_JSON_spec_uint64 ("error_code", 1897 &ec), 1898 GNUNET_JSON_spec_end () 1899 }; 1900 1901 fb->status = ANASTASIS_RFS_INCORRECT_ANSWER; 1902 if (GNUNET_OK != 1903 GNUNET_JSON_parse (val, 1904 dspec, 1905 NULL, NULL)) 1906 { 1907 *detail = set_detail ("challenge_feedback", 1908 "error_code"); 1909 return GNUNET_SYSERR; 1910 } 1911 fb->details.incorrect_answer.ec = (enum TALER_ErrorCode) ec; 1912 return GNUNET_OK; 1913 } 1914 if (0 == strcmp (state, 1915 "rate-limit-exceeded")) 1916 { 1917 uint64_t ec; 1918 struct GNUNET_JSON_Specification dspec[] = { 1919 GNUNET_JSON_spec_uint64 ("error_code", 1920 &ec), 1921 GNUNET_JSON_spec_uint64 ("request_limit", 1922 &fb->details.rate_limit_exceeded.request_limit), 1923 GNUNET_JSON_spec_relative_time ( 1924 "request_frequency", 1925 &fb->details.rate_limit_exceeded.request_frequency), 1926 GNUNET_JSON_spec_end () 1927 }; 1928 1929 fb->status = ANASTASIS_RFS_RATE_LIMIT_EXCEEDED; 1930 if (GNUNET_OK != 1931 GNUNET_JSON_parse (val, 1932 dspec, 1933 NULL, NULL)) 1934 { 1935 *detail = set_detail ("challenge_feedback", 1936 "request_limit"); 1937 return GNUNET_SYSERR; 1938 } 1939 fb->details.rate_limit_exceeded.ec = (enum TALER_ErrorCode) ec; 1940 return GNUNET_OK; 1941 } 1942 *detail = set_detail ("challenge_feedback", 1943 "state"); 1944 return GNUNET_SYSERR; 1945 } 1946 1947 1948 /** 1949 * Parse the recovery-specific parts of @a json. 1950 * 1951 * @param json the state 1952 * @param[out] rr recovery state to fill in 1953 * @param[out] detail set to the offending field on failure 1954 * @return #GNUNET_OK on success 1955 */ 1956 static enum GNUNET_GenericReturnValue 1957 parse_recovery (const json_t *json, 1958 struct ANASTASIS_ReduxRecovery *rr, 1959 const char **detail) 1960 { 1961 const char *state_str; 1962 const json_t *recovery_information = NULL; 1963 const json_t *recovery_document = NULL; 1964 const json_t *challenge_feedback = NULL; 1965 const json_t *core_secret = NULL; 1966 bool no_selected; 1967 struct GNUNET_JSON_Specification spec[] = { 1968 GNUNET_JSON_spec_string ("recovery_state", 1969 &state_str), 1970 GNUNET_JSON_spec_mark_optional ( 1971 GNUNET_JSON_spec_object_const ("recovery_information", 1972 &recovery_information), 1973 NULL), 1974 GNUNET_JSON_spec_mark_optional ( 1975 GNUNET_JSON_spec_object_const ("recovery_document", 1976 &recovery_document), 1977 NULL), 1978 GNUNET_JSON_spec_mark_optional ( 1979 GNUNET_JSON_spec_object_const ("challenge_feedback", 1980 &challenge_feedback), 1981 NULL), 1982 GNUNET_JSON_spec_mark_optional ( 1983 GNUNET_JSON_spec_object_const ("core_secret", 1984 &core_secret), 1985 NULL), 1986 GNUNET_JSON_spec_mark_optional ( 1987 GNUNET_JSON_spec_fixed_auto ("selected_challenge_uuid", 1988 &rr->selected_challenge), 1989 &no_selected), 1990 GNUNET_JSON_spec_end () 1991 }; 1992 1993 if (GNUNET_OK != 1994 GNUNET_JSON_parse (json, 1995 spec, 1996 NULL, NULL)) 1997 { 1998 *detail = set_detail ("state", 1999 "recovery_state"); 2000 return GNUNET_SYSERR; 2001 } 2002 rr->state = ANASTASIS_recovery_state_from_string_ (state_str); 2003 if (ANASTASIS_RECOVERY_STATE_INVALID == rr->state) 2004 { 2005 *detail = set_detail ("state", 2006 "recovery_state"); 2007 return GNUNET_SYSERR; 2008 } 2009 rr->have_selected_challenge = ! no_selected; 2010 rr->core_secret = json_incref ((json_t *) core_secret); 2011 if (NULL != recovery_information) 2012 { 2013 if (GNUNET_OK != 2014 parse_recovery_info (recovery_information, 2015 rr, 2016 detail)) 2017 return GNUNET_SYSERR; 2018 } 2019 if (NULL != recovery_document) 2020 { 2021 /* Hand the blob straight to src/lib: it owns that schema. The 2022 handle comes back inert -- no callbacks, no network activity -- 2023 until a handler calls ANASTASIS_recovery_resume(). */ 2024 rr->r = ANASTASIS_recovery_deserialize (ANASTASIS_REDUX_ctx_, 2025 recovery_document); 2026 if (NULL == rr->r) 2027 { 2028 *detail = set_detail ("state", 2029 "recovery_document"); 2030 return GNUNET_SYSERR; 2031 } 2032 } 2033 if (NULL != challenge_feedback) 2034 { 2035 const char *uuid_str; 2036 json_t *val; 2037 unsigned int off = 0; 2038 2039 rr->have_challenge_feedback = true; 2040 rr->challenge_feedback_len 2041 = (unsigned int) json_object_size (challenge_feedback); 2042 rr->challenge_feedback 2043 = GNUNET_new_array (rr->challenge_feedback_len, 2044 struct ANASTASIS_ReduxFeedback); 2045 json_object_foreach ((json_t *) challenge_feedback, uuid_str, val) 2046 { 2047 struct ANASTASIS_ReduxFeedback *fb = &rr->challenge_feedback[off]; 2048 2049 if (GNUNET_OK != 2050 GNUNET_STRINGS_string_to_data (uuid_str, 2051 strlen (uuid_str), 2052 &fb->uuid, 2053 sizeof (fb->uuid))) 2054 { 2055 *detail = set_detail ("challenge_feedback", 2056 uuid_str); 2057 return GNUNET_SYSERR; 2058 } 2059 if (GNUNET_OK != 2060 parse_feedback_details (val, 2061 fb, 2062 detail)) 2063 return GNUNET_SYSERR; 2064 off++; 2065 } 2066 } 2067 return GNUNET_OK; 2068 } 2069 2070 2071 /** 2072 * Parse an `error` state. 2073 * 2074 * @param json the state 2075 * @param[out] e error state to fill in 2076 * @param[out] detail set to the offending field on failure 2077 * @return #GNUNET_OK on success 2078 */ 2079 static enum GNUNET_GenericReturnValue 2080 parse_error (const json_t *json, 2081 struct ANASTASIS_ReduxError *e, 2082 const char **detail) 2083 { 2084 static const char *const allowed[] = { 2085 "reducer_type", 2086 "code", 2087 "hint", 2088 "detail", 2089 NULL 2090 }; 2091 uint64_t code; 2092 const char *hint = NULL; 2093 const char *dtl = NULL; 2094 struct GNUNET_JSON_Specification spec[] = { 2095 GNUNET_JSON_spec_uint64 ("code", 2096 &code), 2097 GNUNET_JSON_spec_mark_optional ( 2098 GNUNET_JSON_spec_string ("hint", 2099 &hint), 2100 NULL), 2101 GNUNET_JSON_spec_mark_optional ( 2102 GNUNET_JSON_spec_string ("detail", 2103 &dtl), 2104 NULL), 2105 GNUNET_JSON_spec_end () 2106 }; 2107 2108 if ( (GNUNET_OK != 2109 check_fields (json, 2110 "state", 2111 allowed, 2112 detail)) || 2113 (GNUNET_OK != 2114 GNUNET_JSON_parse (json, 2115 spec, 2116 NULL, NULL)) ) 2117 { 2118 *detail = set_detail ("state", 2119 "code"); 2120 return GNUNET_SYSERR; 2121 } 2122 e->code = (enum TALER_ErrorCode) code; 2123 e->hint = dup_or_null (hint); 2124 e->detail = dup_or_null (dtl); 2125 return GNUNET_OK; 2126 } 2127 2128 2129 /** 2130 * Field names permitted at the top level of a backup state. 2131 */ 2132 static const char *const backup_allowed[] = { 2133 "reducer_type", 2134 "backup_state", 2135 "continents", 2136 "countries", 2137 "required_attributes", 2138 "authentication_providers", 2139 "identity_attributes", 2140 "currencies", 2141 "selected_continent", 2142 "selected_country", 2143 "preferred_currency", 2144 "authentication_methods", 2145 "policies", 2146 "policy_providers", 2147 "upload_fees", 2148 "payments", 2149 "policy_payment_requests", 2150 "success_details", 2151 "core_secret", 2152 "secret_name", 2153 "expiration", 2154 "pay_arguments", 2155 NULL 2156 }; 2157 2158 2159 /** 2160 * Field names permitted at the top level of a recovery state. 2161 */ 2162 static const char *const recovery_allowed[] = { 2163 "reducer_type", 2164 "recovery_state", 2165 "continents", 2166 "countries", 2167 "required_attributes", 2168 "authentication_providers", 2169 "identity_attributes", 2170 "currencies", 2171 "selected_continent", 2172 "selected_country", 2173 "preferred_currency", 2174 "recovery_information", 2175 "recovery_document", 2176 "challenge_feedback", 2177 "selected_challenge_uuid", 2178 "core_secret", 2179 NULL 2180 }; 2181 2182 2183 struct ANASTASIS_ReduxState * 2184 ANASTASIS_REDUX_state_parse_ (const json_t *json, 2185 enum TALER_ErrorCode *ec, 2186 const char **detail) 2187 { 2188 struct ANASTASIS_ReduxState *rs; 2189 const char *type; 2190 2191 *ec = TALER_EC_ANASTASIS_REDUCER_STATE_INVALID; 2192 *detail = NULL; 2193 if (! json_is_object (json)) 2194 { 2195 *detail = set_detail ("state", 2196 NULL); 2197 return NULL; 2198 } 2199 /* The reducer type is not always given explicitly: states written by 2200 older versions (and the initial states of the CLI tests) are 2201 identified by which of the two state fields is present. */ 2202 type = json_string_value (json_object_get (json, 2203 "reducer_type")); 2204 if (NULL == type) 2205 { 2206 if (NULL != json_object_get (json, 2207 "backup_state")) 2208 type = "backup"; 2209 else if (NULL != json_object_get (json, 2210 "recovery_state")) 2211 type = "recovery"; 2212 else 2213 { 2214 *detail = set_detail ("state", 2215 "reducer_type"); 2216 return NULL; 2217 } 2218 } 2219 rs = GNUNET_new (struct ANASTASIS_ReduxState); 2220 if (0 == strcmp (type, 2221 "backup")) 2222 { 2223 rs->type = ANASTASIS_RT_BACKUP; 2224 if ( (GNUNET_OK != 2225 check_fields (json, 2226 "state", 2227 backup_allowed, 2228 detail)) || 2229 (GNUNET_OK != 2230 parse_common (json, 2231 &rs->common, 2232 detail)) || 2233 (GNUNET_OK != 2234 parse_backup (json, 2235 &rs->details.backup, 2236 detail)) ) 2237 { 2238 ANASTASIS_REDUX_state_free_ (rs); 2239 return NULL; 2240 } 2241 return rs; 2242 } 2243 if (0 == strcmp (type, 2244 "recovery")) 2245 { 2246 rs->type = ANASTASIS_RT_RECOVERY; 2247 if ( (GNUNET_OK != 2248 check_fields (json, 2249 "state", 2250 recovery_allowed, 2251 detail)) || 2252 (GNUNET_OK != 2253 parse_common (json, 2254 &rs->common, 2255 detail)) || 2256 (GNUNET_OK != 2257 parse_recovery (json, 2258 &rs->details.recovery, 2259 detail)) ) 2260 { 2261 ANASTASIS_REDUX_state_free_ (rs); 2262 return NULL; 2263 } 2264 return rs; 2265 } 2266 if (0 == strcmp (type, 2267 "error")) 2268 { 2269 rs->type = ANASTASIS_RT_ERROR; 2270 if (GNUNET_OK != 2271 parse_error (json, 2272 &rs->details.error, 2273 detail)) 2274 { 2275 ANASTASIS_REDUX_state_free_ (rs); 2276 return NULL; 2277 } 2278 return rs; 2279 } 2280 *detail = set_detail ("state", 2281 "reducer_type"); 2282 ANASTASIS_REDUX_state_free_ (rs); 2283 return NULL; 2284 } 2285 2286 2287 enum GNUNET_GenericReturnValue 2288 ANASTASIS_REDUX_countries_set_ (struct ANASTASIS_ReduxCommon *common, 2289 const json_t *arr, 2290 const char **detail) 2291 { 2292 ANASTASIS_REDUX_countries_clear_ (common); 2293 if (GNUNET_OK != 2294 parse_countries (arr, 2295 common, 2296 detail)) 2297 { 2298 ANASTASIS_REDUX_countries_clear_ (common); 2299 return GNUNET_SYSERR; 2300 } 2301 return GNUNET_OK; 2302 } 2303 2304 2305 enum GNUNET_GenericReturnValue 2306 ANASTASIS_REDUX_required_attributes_set_ (struct ANASTASIS_ReduxCommon *common, 2307 const json_t *arr, 2308 const char **detail) 2309 { 2310 ANASTASIS_REDUX_required_attributes_clear_ (common); 2311 if (GNUNET_OK != 2312 parse_required_attributes (arr, 2313 common, 2314 detail)) 2315 { 2316 ANASTASIS_REDUX_required_attributes_clear_ (common); 2317 return GNUNET_SYSERR; 2318 } 2319 return GNUNET_OK; 2320 } 2321 2322 2323 enum GNUNET_GenericReturnValue 2324 ANASTASIS_REDUX_provider_set_ (struct ANASTASIS_ReduxCommon *common, 2325 const char *url, 2326 const json_t *val, 2327 const char **detail) 2328 { 2329 struct ANASTASIS_ReduxProvider *p; 2330 2331 p = ANASTASIS_REDUX_provider_get_ (common, 2332 url); 2333 if (p->have_config) 2334 ANASTASIS_REDUX_provider_config_clear_ (&p->config); 2335 p->have_config = false; 2336 p->status = ANASTASIS_RPS_NOT_CONTACTED; 2337 memset (&p->error, 2338 0, 2339 sizeof (p->error)); 2340 if (GNUNET_OK != 2341 parse_provider (url, 2342 val, 2343 p, 2344 detail)) 2345 { 2346 /* Leave a well-defined, if uninformative, entry behind: the caller 2347 reports the error, but the state must stay consistent. */ 2348 if (p->have_config) 2349 ANASTASIS_REDUX_provider_config_clear_ (&p->config); 2350 p->have_config = false; 2351 p->status = ANASTASIS_RPS_NOT_CONTACTED; 2352 return GNUNET_SYSERR; 2353 } 2354 return GNUNET_OK; 2355 } 2356 2357 2358 /* end of anastasis_api_redux_parse.c */