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