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