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