Line data Source code
1 : /*
2 : This file is part of TALER
3 : Copyright (C) 2014, 2015, 2016, 2020, 2021 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.c
18 : * @brief helper functions for JSON processing using libjansson
19 : * @author Sree Harsha Totakura <sreeharsha@totakura.in>
20 : * @author Christian Grothoff
21 : */
22 : #include <gnunet/gnunet_util_lib.h>
23 : #include "taler/taler_util.h"
24 : #include "taler/taler_json_lib.h"
25 : #include <unistr.h>
26 :
27 :
28 : /**
29 : * Check if @a json contains a 'real' value anywhere.
30 : *
31 : * @param json json to check
32 : * @return true if a real is in it somewhere
33 : */
34 : static bool
35 1116 : contains_real (const json_t *json)
36 : {
37 1116 : if (json_is_real (json))
38 0 : return true;
39 1116 : if (json_is_object (json))
40 : {
41 : json_t *member;
42 : const char *name;
43 :
44 1297 : json_object_foreach ((json_t *) json, name, member)
45 816 : if (contains_real (member))
46 0 : return true;
47 481 : return false;
48 : }
49 635 : if (json_is_array (json))
50 : {
51 : json_t *member;
52 : size_t index;
53 :
54 244 : json_array_foreach ((json_t *) json, index, member)
55 122 : if (contains_real (member))
56 0 : return true;
57 122 : return false;
58 : }
59 513 : return false;
60 : }
61 :
62 :
63 : /**
64 : * Dump the @a json to a string and hash it.
65 : *
66 : * @param json value to hash
67 : * @param salt salt value to include when using HKDF,
68 : * NULL to not use any salt and to use SHA512
69 : * @param[out] hc where to store the hash
70 : * @return #GNUNET_OK on success,
71 : * #GNUNET_NO if @a json was not hash-able
72 : * #GNUNET_SYSERR on failure
73 : */
74 : static enum GNUNET_GenericReturnValue
75 178 : dump_and_hash (const json_t *json,
76 : const char *salt,
77 : struct GNUNET_HashCode *hc)
78 : {
79 : char *wire_enc;
80 : size_t len;
81 :
82 178 : if (NULL == json)
83 : {
84 0 : GNUNET_break_op (0);
85 0 : return GNUNET_NO;
86 : }
87 178 : if (contains_real (json))
88 : {
89 0 : GNUNET_break_op (0);
90 0 : return GNUNET_NO;
91 : }
92 178 : if (NULL == (wire_enc = json_dumps (json,
93 : JSON_ENCODE_ANY
94 : | JSON_COMPACT
95 : | JSON_SORT_KEYS)))
96 : {
97 0 : GNUNET_break (0);
98 0 : return GNUNET_SYSERR;
99 : }
100 178 : len = TALER_rfc8785encode (&wire_enc);
101 178 : if (NULL == salt)
102 : {
103 162 : GNUNET_CRYPTO_hash (wire_enc,
104 : len,
105 : hc);
106 : }
107 : else
108 : {
109 16 : if (GNUNET_YES !=
110 16 : GNUNET_CRYPTO_hkdf_gnunet (
111 : hc,
112 : sizeof (*hc),
113 : salt,
114 : strlen (salt) + 1,
115 : wire_enc,
116 : len))
117 : {
118 0 : GNUNET_break (0);
119 0 : free (wire_enc);
120 0 : return GNUNET_SYSERR;
121 : }
122 : }
123 178 : free (wire_enc);
124 178 : return GNUNET_OK;
125 : }
126 :
127 :
128 : /**
129 : * Replace "forgettable" parts of a JSON object with their salted hash.
130 : *
131 : * @param[in] in some JSON value
132 : * @param[out] out resulting JSON value
133 : * @return #GNUNET_OK on success,
134 : * #GNUNET_NO if @a json was not hash-able
135 : * #GNUNET_SYSERR on failure
136 : */
137 : static enum GNUNET_GenericReturnValue
138 1095 : forget (const json_t *in,
139 : json_t **out)
140 : {
141 1095 : if (json_is_real (in))
142 : {
143 : /* floating point is not allowed! */
144 0 : GNUNET_break_op (0);
145 0 : return GNUNET_NO;
146 : }
147 1095 : if (json_is_array (in))
148 : {
149 : /* array is a JSON array */
150 : size_t index;
151 : json_t *value;
152 : json_t *ret;
153 :
154 122 : ret = json_array ();
155 122 : if (NULL == ret)
156 : {
157 0 : GNUNET_break (0);
158 0 : return GNUNET_SYSERR;
159 : }
160 244 : json_array_foreach (in, index, value) {
161 : enum GNUNET_GenericReturnValue iret;
162 : json_t *t;
163 :
164 122 : iret = forget (value,
165 : &t);
166 122 : if (GNUNET_OK != iret)
167 : {
168 0 : json_decref (ret);
169 0 : return iret;
170 : }
171 122 : if (0 != json_array_append_new (ret,
172 : t))
173 : {
174 0 : GNUNET_break (0);
175 0 : json_decref (ret);
176 0 : return GNUNET_SYSERR;
177 : }
178 : }
179 122 : *out = ret;
180 122 : return GNUNET_OK;
181 : }
182 973 : if (json_is_object (in))
183 : {
184 : json_t *ret;
185 : const char *key;
186 : json_t *value;
187 : json_t *fg;
188 : json_t *rx;
189 :
190 472 : fg = json_object_get (in,
191 : "$forgettable");
192 472 : rx = json_object_get (in,
193 : "$forgotten");
194 472 : if (NULL != rx)
195 : {
196 6 : rx = json_deep_copy (rx); /* should be shallow
197 : by structure, but
198 : deep copy is safer */
199 6 : if (NULL == rx)
200 : {
201 0 : GNUNET_break (0);
202 0 : return GNUNET_SYSERR;
203 : }
204 : }
205 472 : ret = json_object ();
206 472 : if (NULL == ret)
207 : {
208 0 : GNUNET_break (0);
209 0 : return GNUNET_SYSERR;
210 : }
211 1294 : json_object_foreach ((json_t*) in, key, value) {
212 : json_t *t;
213 : json_t *salt;
214 : enum GNUNET_GenericReturnValue iret;
215 :
216 822 : if (fg == value)
217 15 : continue; /* skip! */
218 807 : if (rx == value)
219 0 : continue; /* skip! */
220 820 : if ( (NULL != rx) &&
221 : (NULL !=
222 13 : json_object_get (rx,
223 : key)) )
224 : {
225 0 : (void) json_object_del (ret,
226 : key);
227 0 : continue; /* already forgotten earlier */
228 : }
229 807 : iret = forget (value,
230 : &t);
231 807 : if (GNUNET_OK != iret)
232 : {
233 0 : json_decref (ret);
234 0 : json_decref (rx);
235 0 : return iret;
236 : }
237 829 : if ( (NULL != fg) &&
238 22 : (NULL != (salt = json_object_get (fg,
239 : key))) )
240 12 : {
241 : /* 't' is to be forgotten! */
242 : struct GNUNET_HashCode hc;
243 :
244 12 : if (! json_is_string (salt))
245 : {
246 0 : GNUNET_break_op (0);
247 0 : json_decref (ret);
248 0 : json_decref (rx);
249 0 : json_decref (t);
250 0 : return GNUNET_NO;
251 : }
252 12 : iret = dump_and_hash (t,
253 : json_string_value (salt),
254 : &hc);
255 12 : if (GNUNET_OK != iret)
256 : {
257 0 : json_decref (ret);
258 0 : json_decref (rx);
259 0 : json_decref (t);
260 0 : return iret;
261 : }
262 12 : json_decref (t);
263 : /* scrub salt */
264 12 : if (0 !=
265 12 : json_object_del (fg,
266 : key))
267 : {
268 0 : GNUNET_break_op (0);
269 0 : json_decref (ret);
270 0 : json_decref (rx);
271 0 : return GNUNET_NO;
272 : }
273 12 : if (NULL == rx)
274 9 : rx = json_object ();
275 12 : if (NULL == rx)
276 : {
277 0 : GNUNET_break (0);
278 0 : json_decref (ret);
279 0 : return GNUNET_SYSERR;
280 : }
281 12 : if (0 !=
282 12 : json_object_set_new (rx,
283 : key,
284 : GNUNET_JSON_from_data_auto (&hc)))
285 : {
286 0 : GNUNET_break (0);
287 0 : json_decref (ret);
288 0 : json_decref (rx);
289 0 : return GNUNET_SYSERR;
290 : }
291 : }
292 : else
293 : {
294 : /* 't' to be used without 'forgetting' */
295 795 : if (0 !=
296 795 : json_object_set_new (ret,
297 : key,
298 : t))
299 : {
300 0 : GNUNET_break (0);
301 0 : json_decref (ret);
302 0 : json_decref (rx);
303 0 : return GNUNET_SYSERR;
304 : }
305 : }
306 : } /* json_object_foreach */
307 487 : if ( (NULL != rx) &&
308 : (0 !=
309 15 : json_object_set_new (ret,
310 : "$forgotten",
311 : rx)) )
312 : {
313 0 : GNUNET_break (0);
314 0 : json_decref (ret);
315 0 : return GNUNET_SYSERR;
316 : }
317 472 : *out = ret;
318 472 : return GNUNET_OK;
319 : }
320 501 : *out = json_incref ((json_t *) in);
321 501 : return GNUNET_OK;
322 : }
323 :
324 :
325 : enum GNUNET_GenericReturnValue
326 162 : TALER_JSON_contract_hash (const json_t *json,
327 : struct TALER_PrivateContractHashP *hc)
328 : {
329 : enum GNUNET_GenericReturnValue ret;
330 : json_t *cjson;
331 : json_t *dc;
332 :
333 162 : dc = json_deep_copy (json);
334 162 : ret = forget (dc,
335 : &cjson);
336 162 : json_decref (dc);
337 162 : if (GNUNET_OK != ret)
338 0 : return ret;
339 162 : ret = dump_and_hash (cjson,
340 : NULL,
341 : &hc->hash);
342 162 : json_decref (cjson);
343 162 : return ret;
344 : }
345 :
346 :
347 : enum GNUNET_GenericReturnValue
348 4 : TALER_JSON_contract_mark_forgettable (json_t *json,
349 : const char *field)
350 : {
351 : json_t *fg;
352 : struct GNUNET_ShortHashCode salt;
353 :
354 4 : if (! json_is_object (json))
355 : {
356 0 : GNUNET_break (0);
357 0 : return GNUNET_SYSERR;
358 : }
359 : /* check field name is legal for forgettable field */
360 12 : for (const char *f = field; '\0' != *f; f++)
361 : {
362 8 : char c = *f;
363 :
364 8 : if ( (c >= 'a') && (c <= 'z') )
365 4 : continue;
366 4 : if ( (c >= 'A') && (c <= 'Z') )
367 0 : continue;
368 4 : if ( (c >= '0') && (c <= '9') )
369 4 : continue;
370 0 : if ('_' == c)
371 0 : continue;
372 0 : GNUNET_break (0);
373 0 : return GNUNET_SYSERR;
374 : }
375 4 : if (NULL == json_object_get (json,
376 : field))
377 : {
378 : /* field must exist */
379 0 : GNUNET_break (0);
380 0 : return GNUNET_SYSERR;
381 : }
382 4 : fg = json_object_get (json,
383 : "$forgettable");
384 4 : if (NULL == fg)
385 : {
386 3 : fg = json_object ();
387 3 : if (0 !=
388 3 : json_object_set_new (json,
389 : "$forgettable",
390 : fg))
391 : {
392 0 : GNUNET_break (0);
393 0 : return GNUNET_SYSERR;
394 : }
395 : }
396 :
397 4 : GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
398 : &salt,
399 : sizeof (salt));
400 4 : if (0 !=
401 4 : json_object_set_new (fg,
402 : field,
403 : GNUNET_JSON_from_data_auto (&salt)))
404 : {
405 0 : GNUNET_break (0);
406 0 : return GNUNET_SYSERR;
407 : }
408 4 : return GNUNET_OK;
409 : }
410 :
411 :
412 : enum GNUNET_GenericReturnValue
413 4 : TALER_JSON_contract_part_forget (json_t *json,
414 : const char *field)
415 : {
416 : json_t *fg;
417 : const json_t *part;
418 : json_t *fp;
419 : json_t *rx;
420 : struct GNUNET_HashCode hc;
421 : const char *salt;
422 : enum GNUNET_GenericReturnValue ret;
423 :
424 4 : if (! json_is_object (json))
425 : {
426 0 : GNUNET_break (0);
427 0 : return GNUNET_SYSERR;
428 : }
429 4 : if (NULL == (part = json_object_get (json,
430 : field)))
431 : {
432 0 : GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
433 : "Did not find field `%s' we were asked to forget\n",
434 : field);
435 0 : return GNUNET_SYSERR;
436 : }
437 4 : fg = json_object_get (json,
438 : "$forgettable");
439 4 : if (NULL == fg)
440 : {
441 0 : GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
442 : "Did not find '$forgettable' attribute trying to forget field `%s'\n",
443 : field);
444 0 : return GNUNET_SYSERR;
445 : }
446 4 : rx = json_object_get (json,
447 : "$forgotten");
448 4 : if (NULL == rx)
449 : {
450 3 : rx = json_object ();
451 3 : if (0 !=
452 3 : json_object_set_new (json,
453 : "$forgotten",
454 : rx))
455 : {
456 0 : GNUNET_break (0);
457 0 : return GNUNET_SYSERR;
458 : }
459 : }
460 4 : if (NULL !=
461 4 : json_object_get (rx,
462 : field))
463 : {
464 0 : if (! json_is_null (json_object_get (json,
465 : field)))
466 : {
467 0 : GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
468 : "Field `%s' market as forgotten, but still exists!\n",
469 : field);
470 0 : return GNUNET_SYSERR;
471 : }
472 0 : GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
473 : "Already forgot field `%s'\n",
474 : field);
475 0 : return GNUNET_NO;
476 : }
477 4 : salt = json_string_value (json_object_get (fg,
478 : field));
479 4 : if (NULL == salt)
480 : {
481 0 : GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
482 : "Did not find required salt to forget field `%s'\n",
483 : field);
484 0 : return GNUNET_SYSERR;
485 : }
486 :
487 : /* need to recursively forget to compute 'hc' */
488 4 : ret = forget (part,
489 : &fp);
490 4 : if (GNUNET_OK != ret)
491 0 : return ret;
492 4 : if (GNUNET_OK !=
493 4 : dump_and_hash (fp,
494 : salt,
495 : &hc))
496 : {
497 0 : json_decref (fp);
498 0 : GNUNET_break (0);
499 0 : return GNUNET_SYSERR;
500 : }
501 4 : json_decref (fp);
502 : /* drop salt */
503 4 : if (0 !=
504 4 : json_object_del (fg,
505 : field))
506 : {
507 0 : json_decref (fp);
508 0 : GNUNET_break (0);
509 0 : return GNUNET_SYSERR;
510 : }
511 :
512 : /* remember field as 'forgotten' */
513 4 : if (0 !=
514 4 : json_object_set_new (rx,
515 : field,
516 : GNUNET_JSON_from_data_auto (&hc)))
517 : {
518 0 : GNUNET_break (0);
519 0 : return GNUNET_SYSERR;
520 : }
521 : /* finally, set 'forgotten' field to null */
522 4 : if (0 !=
523 4 : json_object_del (json,
524 : field))
525 : {
526 0 : GNUNET_break (0);
527 0 : return GNUNET_SYSERR;
528 : }
529 4 : return GNUNET_OK;
530 : }
531 :
532 :
533 : /**
534 : * Loop over all of the values of a '$forgettable' object. Replace 'True'
535 : * values with proper random salts. Fails if any forgettable values are
536 : * neither 'True' nor valid salts (strings).
537 : *
538 : * @param[in,out] f JSON to transform
539 : * @return #GNUNET_OK on success
540 : */
541 : static enum GNUNET_GenericReturnValue
542 1 : seed_forgettable (json_t *f)
543 : {
544 : const char *key;
545 : json_t *val;
546 :
547 2 : json_object_foreach (f,
548 : key,
549 : val)
550 : {
551 1 : if (json_is_string (val))
552 0 : continue;
553 1 : if (json_is_true (val))
554 1 : {
555 : struct GNUNET_ShortHashCode sh;
556 :
557 1 : GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
558 : &sh,
559 : sizeof (sh));
560 1 : if (0 !=
561 1 : json_object_set_new (f,
562 : key,
563 : GNUNET_JSON_from_data_auto (&sh)))
564 : {
565 0 : GNUNET_break (0);
566 0 : return GNUNET_SYSERR;
567 : }
568 1 : continue;
569 : }
570 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
571 : "Forgettable field `%s' has invalid value\n",
572 : key);
573 0 : return GNUNET_SYSERR;
574 : }
575 1 : return GNUNET_OK;
576 : }
577 :
578 :
579 : enum GNUNET_GenericReturnValue
580 4 : TALER_JSON_contract_seed_forgettable (const json_t *spec,
581 : json_t *contract)
582 : {
583 4 : if (json_is_object (spec))
584 : {
585 : const char *key;
586 : json_t *val;
587 :
588 6 : json_object_foreach ((json_t *) spec,
589 : key,
590 : val)
591 : {
592 4 : json_t *cval = json_object_get (contract,
593 : key);
594 :
595 4 : if (0 == strcmp ("$forgettable",
596 : key))
597 1 : {
598 1 : json_t *xval = json_deep_copy (val);
599 :
600 1 : if (GNUNET_OK !=
601 1 : seed_forgettable (xval))
602 : {
603 0 : json_decref (xval);
604 0 : return GNUNET_SYSERR;
605 : }
606 1 : GNUNET_assert (0 ==
607 : json_object_set_new (contract,
608 : "$forgettable",
609 : xval));
610 1 : continue;
611 : }
612 3 : if (NULL == cval)
613 0 : continue;
614 3 : if (GNUNET_OK !=
615 3 : TALER_JSON_contract_seed_forgettable (val,
616 : cval))
617 0 : return GNUNET_SYSERR;
618 : }
619 : }
620 4 : if (json_is_array (spec))
621 : {
622 : size_t index;
623 : json_t *val;
624 :
625 0 : json_array_foreach ((json_t *) spec,
626 : index,
627 : val)
628 : {
629 0 : json_t *ival = json_array_get (contract,
630 : index);
631 :
632 0 : if (NULL == ival)
633 0 : continue;
634 0 : if (GNUNET_OK !=
635 0 : TALER_JSON_contract_seed_forgettable (val,
636 : ival))
637 0 : return GNUNET_SYSERR;
638 : }
639 : }
640 4 : return GNUNET_OK;
641 : }
642 :
643 :
644 : /**
645 : * Parse a json path.
646 : *
647 : * @param obj the object that the path is relative to.
648 : * @param prev the parent of @e obj.
649 : * @param path the path to parse.
650 : * @param cb the callback to call, if we get to the end of @e path.
651 : * @param cb_cls the closure for the callback.
652 : * @return #GNUNET_OK on success, #GNUNET_SYSERR if @e path is malformed.
653 : */
654 : static enum GNUNET_GenericReturnValue
655 16 : parse_path (json_t *obj,
656 : json_t *prev,
657 : const char *path,
658 : TALER_JSON_ExpandPathCallback cb,
659 : void *cb_cls)
660 : {
661 16 : char *id = GNUNET_strdup (path);
662 16 : char *next_id = strchr (id,
663 : '.');
664 : char *next_path;
665 : char *bracket;
666 16 : json_t *next_obj = NULL;
667 : char *next_dot;
668 :
669 16 : GNUNET_assert (NULL != id); /* make stupid compiler happy */
670 16 : if (NULL == next_id)
671 : {
672 5 : cb (cb_cls,
673 : id,
674 : prev);
675 5 : GNUNET_free (id);
676 5 : return GNUNET_OK;
677 : }
678 11 : bracket = strchr (next_id,
679 : '[');
680 11 : *next_id = '\0';
681 11 : next_id++;
682 11 : next_path = GNUNET_strdup (next_id);
683 11 : next_dot = strchr (next_id,
684 : '.');
685 11 : if (NULL != next_dot)
686 3 : *next_dot = '\0';
687 : /* If this is the first time this is called, make sure id is "$" */
688 11 : if ( (NULL == prev) &&
689 6 : (0 != strcmp (id,
690 : "$")))
691 : {
692 1 : GNUNET_free (id);
693 1 : GNUNET_free (next_path);
694 1 : return GNUNET_SYSERR;
695 : }
696 :
697 : /* Check for bracketed indices */
698 10 : if (NULL != bracket)
699 : {
700 3 : char *end_bracket = strchr (bracket,
701 : ']');
702 : json_t *array;
703 :
704 3 : if (NULL == end_bracket)
705 : {
706 0 : GNUNET_free (id);
707 0 : GNUNET_free (next_path);
708 0 : return GNUNET_SYSERR;
709 : }
710 3 : *end_bracket = '\0';
711 3 : *bracket = '\0';
712 3 : bracket++;
713 3 : array = json_object_get (obj,
714 : next_id);
715 3 : if (0 == strcmp (bracket,
716 : "*"))
717 : {
718 : size_t index;
719 : json_t *value;
720 1 : int ret = GNUNET_OK;
721 :
722 4 : json_array_foreach (array, index, value) {
723 3 : ret = parse_path (value,
724 : obj,
725 : next_path,
726 : cb,
727 : cb_cls);
728 3 : if (GNUNET_OK != ret)
729 : {
730 0 : GNUNET_free (id);
731 0 : GNUNET_free (next_path);
732 0 : return ret;
733 : }
734 : }
735 : }
736 : else
737 : {
738 : unsigned int index;
739 : char dummy;
740 :
741 2 : if (1 != sscanf (bracket,
742 : "%u%c",
743 : &index,
744 : &dummy))
745 : {
746 1 : GNUNET_free (id);
747 1 : GNUNET_free (next_path);
748 1 : return GNUNET_SYSERR;
749 : }
750 1 : next_obj = json_array_get (array,
751 : index);
752 : }
753 : }
754 : else
755 : {
756 : /* No brackets, so just fetch the object by name */
757 7 : next_obj = json_object_get (obj,
758 : next_id);
759 : }
760 :
761 9 : if (NULL != next_obj)
762 : {
763 7 : int ret = parse_path (next_obj,
764 : obj,
765 : next_path,
766 : cb,
767 : cb_cls);
768 7 : GNUNET_free (id);
769 7 : GNUNET_free (next_path);
770 7 : return ret;
771 : }
772 2 : GNUNET_free (id);
773 2 : GNUNET_free (next_path);
774 2 : return GNUNET_OK;
775 : }
776 :
777 :
778 : enum GNUNET_GenericReturnValue
779 6 : TALER_JSON_expand_path (json_t *json,
780 : const char *path,
781 : TALER_JSON_ExpandPathCallback cb,
782 : void *cb_cls)
783 : {
784 6 : return parse_path (json,
785 : NULL,
786 : path,
787 : cb,
788 : cb_cls);
789 : }
790 :
791 :
792 : enum TALER_ErrorCode
793 91 : TALER_JSON_get_error_code (const json_t *json)
794 : {
795 : const json_t *jc;
796 :
797 91 : if (NULL == json)
798 0 : return TALER_EC_GENERIC_INVALID_RESPONSE;
799 91 : jc = json_object_get (json, "code");
800 : /* The caller already knows that the JSON represents an error,
801 : so we are dealing with a missing error code here. */
802 91 : if (NULL == jc)
803 : {
804 0 : GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
805 : "Expected Taler error code `code' in JSON, but field does not exist!\n");
806 0 : return TALER_EC_INVALID;
807 : }
808 91 : if (json_is_integer (jc))
809 91 : return (enum TALER_ErrorCode) (int) json_integer_value (jc);
810 0 : GNUNET_break_op (0);
811 0 : return TALER_EC_INVALID;
812 : }
813 :
814 :
815 : const char *
816 81 : TALER_JSON_get_error_hint (const json_t *json)
817 : {
818 : const json_t *jc;
819 :
820 81 : if (NULL == json)
821 0 : return NULL;
822 81 : jc = json_object_get (json,
823 : "hint");
824 81 : if (NULL == jc)
825 0 : return NULL; /* no hint, is allowed */
826 81 : if (! json_is_string (jc))
827 : {
828 : /* Hints must be strings */
829 0 : GNUNET_break_op (0);
830 0 : return NULL;
831 : }
832 81 : return json_string_value (jc);
833 : }
834 :
835 :
836 : enum TALER_ErrorCode
837 0 : TALER_JSON_get_error_code2 (const void *data,
838 : size_t data_size)
839 : {
840 : json_t *json;
841 : enum TALER_ErrorCode ec;
842 : json_error_t err;
843 :
844 0 : json = json_loadb (data,
845 : data_size,
846 : JSON_REJECT_DUPLICATES,
847 : &err);
848 0 : if (NULL == json)
849 0 : return TALER_EC_INVALID;
850 0 : ec = TALER_JSON_get_error_code (json);
851 0 : json_decref (json);
852 0 : if (ec == TALER_EC_NONE)
853 0 : return TALER_EC_INVALID;
854 0 : return ec;
855 : }
856 :
857 :
858 : void
859 0 : TALER_deposit_policy_hash (const json_t *policy,
860 : struct TALER_ExtensionPolicyHashP *ech)
861 : {
862 0 : GNUNET_assert (GNUNET_OK ==
863 : dump_and_hash (policy,
864 : "taler-extensions-policy",
865 : &ech->hash));
866 0 : }
867 :
868 :
869 : char *
870 3 : TALER_JSON_canonicalize (const json_t *input)
871 : {
872 : char *wire_enc;
873 :
874 3 : if (NULL == (wire_enc = json_dumps (input,
875 : JSON_ENCODE_ANY
876 : | JSON_COMPACT
877 : | JSON_SORT_KEYS)))
878 : {
879 0 : GNUNET_break (0);
880 0 : return NULL;
881 : }
882 3 : TALER_rfc8785encode (&wire_enc);
883 3 : return wire_enc;
884 : }
885 :
886 :
887 : enum GNUNET_GenericReturnValue
888 0 : TALER_JSON_extensions_manifests_hash (const json_t *manifests,
889 : struct TALER_ExtensionManifestsHashP *ech)
890 : {
891 0 : return dump_and_hash (manifests,
892 : "taler-extensions-manifests",
893 : &ech->hash);
894 : }
895 :
896 :
897 : json_t *
898 116 : TALER_JSON_currency_specs_to_json (
899 : const struct TALER_CurrencySpecification *cspec)
900 : {
901 : json_t *ca;
902 :
903 116 : ca = json_array ();
904 116 : GNUNET_assert (NULL != ca);
905 580 : for (unsigned int i = 0; i<cspec->num_common_amounts; i++)
906 464 : GNUNET_assert (
907 : 0 ==
908 : json_array_append_new (
909 : ca,
910 : TALER_JSON_from_amount (&cspec->common_amounts[i])));
911 116 : return GNUNET_JSON_PACK (
912 : GNUNET_JSON_pack_string ("name",
913 : cspec->name),
914 : /* 'currency' is deprecated as of exchange v18 and merchant v6;
915 : remove this line once current-age > 6*/
916 : GNUNET_JSON_pack_string ("currency",
917 : cspec->currency),
918 : GNUNET_JSON_pack_array_steal ("common_amounts",
919 : ca),
920 : GNUNET_JSON_pack_uint64 ("num_fractional_input_digits",
921 : cspec->num_fractional_input_digits),
922 : GNUNET_JSON_pack_uint64 ("num_fractional_normal_digits",
923 : cspec->num_fractional_normal_digits),
924 : GNUNET_JSON_pack_uint64 ("num_fractional_trailing_zero_digits",
925 : cspec->num_fractional_trailing_zero_digits),
926 : GNUNET_JSON_pack_object_incref ("alt_unit_names",
927 : cspec->map_alt_unit_names));
928 : }
929 :
930 :
931 : /* End of json/json.c */
|