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 1082 : forget (const json_t *in,
139 : json_t **out)
140 : {
141 1082 : 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 1082 : 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 960 : if (json_is_object (in))
183 : {
184 : json_t *ret;
185 : const char *key;
186 : json_t *value;
187 : json_t *fg;
188 466 : json_t *rx = NULL;
189 : json_t *rx_orig;
190 :
191 466 : fg = json_object_get (in,
192 : "$forgettable");
193 466 : rx_orig = json_object_get (in,
194 : "$forgotten");
195 466 : if (NULL != rx_orig)
196 : {
197 6 : rx = json_deep_copy (rx_orig); /* should be shallow
198 : by structure, but
199 : deep copy is safer */
200 6 : if (NULL == rx)
201 : {
202 0 : GNUNET_break (0);
203 0 : return GNUNET_SYSERR;
204 : }
205 : }
206 466 : ret = json_object ();
207 466 : if (NULL == ret)
208 : {
209 0 : GNUNET_break (0);
210 0 : return GNUNET_SYSERR;
211 : }
212 1281 : json_object_foreach ((json_t*) in, key, value) {
213 : json_t *t;
214 : json_t *salt;
215 : enum GNUNET_GenericReturnValue iret;
216 :
217 815 : if (fg == value)
218 21 : continue; /* skip! */
219 800 : if (rx_orig == value)
220 6 : continue; /* skip! */
221 801 : if ( (NULL != rx) &&
222 : (NULL !=
223 7 : json_object_get (rx,
224 : key)) )
225 : {
226 0 : (void) json_object_del (ret,
227 : key);
228 0 : continue; /* already forgotten earlier */
229 : }
230 794 : iret = forget (value,
231 : &t);
232 794 : if (GNUNET_OK != iret)
233 : {
234 0 : json_decref (ret);
235 0 : json_decref (rx);
236 0 : return iret;
237 : }
238 810 : if ( (NULL != fg) &&
239 16 : (NULL != (salt = json_object_get (fg,
240 : key))) )
241 12 : {
242 : /* 't' is to be forgotten! */
243 : struct GNUNET_HashCode hc;
244 :
245 12 : if (! json_is_string (salt))
246 : {
247 0 : GNUNET_break_op (0);
248 0 : json_decref (ret);
249 0 : json_decref (rx);
250 0 : json_decref (t);
251 0 : return GNUNET_NO;
252 : }
253 12 : iret = dump_and_hash (t,
254 : json_string_value (salt),
255 : &hc);
256 12 : if (GNUNET_OK != iret)
257 : {
258 0 : json_decref (ret);
259 0 : json_decref (rx);
260 0 : json_decref (t);
261 0 : return iret;
262 : }
263 12 : json_decref (t);
264 : /* scrub salt */
265 12 : if (0 !=
266 12 : json_object_del (fg,
267 : key))
268 : {
269 0 : GNUNET_break_op (0);
270 0 : json_decref (ret);
271 0 : json_decref (rx);
272 0 : return GNUNET_NO;
273 : }
274 12 : if (NULL == rx)
275 9 : rx = json_object ();
276 12 : if (NULL == rx)
277 : {
278 0 : GNUNET_break (0);
279 0 : json_decref (ret);
280 0 : return GNUNET_SYSERR;
281 : }
282 12 : if (0 !=
283 12 : json_object_set_new (rx,
284 : key,
285 : GNUNET_JSON_from_data_auto (&hc)))
286 : {
287 0 : GNUNET_break (0);
288 0 : json_decref (ret);
289 0 : json_decref (rx);
290 0 : return GNUNET_SYSERR;
291 : }
292 : }
293 : else
294 : {
295 : /* 't' to be used without 'forgetting' */
296 782 : if (0 !=
297 782 : json_object_set_new (ret,
298 : key,
299 : t))
300 : {
301 0 : GNUNET_break (0);
302 0 : json_decref (ret);
303 0 : json_decref (rx);
304 0 : return GNUNET_SYSERR;
305 : }
306 : }
307 : } /* json_object_foreach */
308 481 : if ( (NULL != rx) &&
309 : (0 !=
310 15 : json_object_set_new (ret,
311 : "$forgotten",
312 : rx)) )
313 : {
314 0 : GNUNET_break (0);
315 0 : json_decref (ret);
316 0 : return GNUNET_SYSERR;
317 : }
318 466 : *out = ret;
319 466 : return GNUNET_OK;
320 : }
321 494 : *out = json_incref ((json_t *) in);
322 494 : return GNUNET_OK;
323 : }
324 :
325 :
326 : enum GNUNET_GenericReturnValue
327 162 : TALER_JSON_contract_hash (const json_t *json,
328 : struct TALER_PrivateContractHashP *hc)
329 : {
330 : enum GNUNET_GenericReturnValue ret;
331 : json_t *cjson;
332 : json_t *dc;
333 :
334 162 : dc = json_deep_copy (json);
335 162 : ret = forget (dc,
336 : &cjson);
337 162 : json_decref (dc);
338 162 : if (GNUNET_OK != ret)
339 0 : return ret;
340 162 : ret = dump_and_hash (cjson,
341 : NULL,
342 : &hc->hash);
343 162 : json_decref (cjson);
344 162 : return ret;
345 : }
346 :
347 :
348 : enum GNUNET_GenericReturnValue
349 4 : TALER_JSON_contract_mark_forgettable (json_t *json,
350 : const char *field)
351 : {
352 : json_t *fg;
353 : struct GNUNET_ShortHashCode salt;
354 :
355 4 : if (! json_is_object (json))
356 : {
357 0 : GNUNET_break (0);
358 0 : return GNUNET_SYSERR;
359 : }
360 : /* check field name is legal for forgettable field */
361 12 : for (const char *f = field; '\0' != *f; f++)
362 : {
363 8 : char c = *f;
364 :
365 8 : if ( (c >= 'a') && (c <= 'z') )
366 4 : continue;
367 4 : if ( (c >= 'A') && (c <= 'Z') )
368 0 : continue;
369 4 : if ( (c >= '0') && (c <= '9') )
370 4 : continue;
371 0 : if ('_' == c)
372 0 : continue;
373 0 : GNUNET_break (0);
374 0 : return GNUNET_SYSERR;
375 : }
376 4 : if (NULL == json_object_get (json,
377 : field))
378 : {
379 : /* field must exist */
380 0 : GNUNET_break (0);
381 0 : return GNUNET_SYSERR;
382 : }
383 4 : fg = json_object_get (json,
384 : "$forgettable");
385 4 : if (NULL == fg)
386 : {
387 3 : fg = json_object ();
388 3 : if (0 !=
389 3 : json_object_set_new (json,
390 : "$forgettable",
391 : fg))
392 : {
393 0 : GNUNET_break (0);
394 0 : return GNUNET_SYSERR;
395 : }
396 : }
397 :
398 4 : GNUNET_CRYPTO_random_block (&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 : GNUNET_break (0);
508 0 : return GNUNET_SYSERR;
509 : }
510 :
511 : /* remember field as 'forgotten' */
512 4 : if (0 !=
513 4 : json_object_set_new (rx,
514 : field,
515 : GNUNET_JSON_from_data_auto (&hc)))
516 : {
517 0 : GNUNET_break (0);
518 0 : return GNUNET_SYSERR;
519 : }
520 : /* finally, set 'forgotten' field to null */
521 4 : if (0 !=
522 4 : json_object_del (json,
523 : field))
524 : {
525 0 : GNUNET_break (0);
526 0 : return GNUNET_SYSERR;
527 : }
528 4 : return GNUNET_OK;
529 : }
530 :
531 :
532 : /**
533 : * Loop over all of the values of a '$forgettable' object. Replace 'True'
534 : * values with proper random salts. Fails if any forgettable values are
535 : * neither 'True' nor valid salts (strings).
536 : *
537 : * @param[in,out] f JSON to transform
538 : * @return #GNUNET_OK on success
539 : */
540 : static enum GNUNET_GenericReturnValue
541 1 : seed_forgettable (json_t *f)
542 : {
543 : const char *key;
544 : json_t *val;
545 :
546 2 : json_object_foreach (f,
547 : key,
548 : val)
549 : {
550 1 : if (json_is_string (val))
551 0 : continue;
552 1 : if (json_is_true (val))
553 1 : {
554 : struct GNUNET_ShortHashCode sh;
555 :
556 1 : GNUNET_CRYPTO_random_block (&sh,
557 : sizeof (sh));
558 1 : if (0 !=
559 1 : json_object_set_new (f,
560 : key,
561 : GNUNET_JSON_from_data_auto (&sh)))
562 : {
563 0 : GNUNET_break (0);
564 0 : return GNUNET_SYSERR;
565 : }
566 1 : continue;
567 : }
568 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
569 : "Forgettable field `%s' has invalid value\n",
570 : key);
571 0 : return GNUNET_SYSERR;
572 : }
573 1 : return GNUNET_OK;
574 : }
575 :
576 :
577 : enum GNUNET_GenericReturnValue
578 4 : TALER_JSON_contract_seed_forgettable (const json_t *spec,
579 : json_t *contract)
580 : {
581 4 : if (json_is_object (spec))
582 : {
583 : const char *key;
584 : json_t *val;
585 :
586 6 : json_object_foreach ((json_t *) spec,
587 : key,
588 : val)
589 : {
590 4 : json_t *cval = json_object_get (contract,
591 : key);
592 :
593 4 : if (0 == strcmp ("$forgettable",
594 : key))
595 1 : {
596 1 : json_t *xval = json_deep_copy (val);
597 :
598 1 : if (GNUNET_OK !=
599 1 : seed_forgettable (xval))
600 : {
601 0 : json_decref (xval);
602 0 : return GNUNET_SYSERR;
603 : }
604 1 : GNUNET_assert (0 ==
605 : json_object_set_new (contract,
606 : "$forgettable",
607 : xval));
608 1 : continue;
609 : }
610 3 : if (NULL == cval)
611 0 : continue;
612 3 : if (GNUNET_OK !=
613 3 : TALER_JSON_contract_seed_forgettable (val,
614 : cval))
615 0 : return GNUNET_SYSERR;
616 : }
617 : }
618 4 : if (json_is_array (spec))
619 : {
620 : size_t index;
621 : json_t *val;
622 :
623 0 : json_array_foreach ((json_t *) spec,
624 : index,
625 : val)
626 : {
627 0 : json_t *ival = json_array_get (contract,
628 : index);
629 :
630 0 : if (NULL == ival)
631 0 : continue;
632 0 : if (GNUNET_OK !=
633 0 : TALER_JSON_contract_seed_forgettable (val,
634 : ival))
635 0 : return GNUNET_SYSERR;
636 : }
637 : }
638 4 : return GNUNET_OK;
639 : }
640 :
641 :
642 : /**
643 : * Parse a json path.
644 : *
645 : * @param obj the object that the path is relative to.
646 : * @param prev the parent of @e obj.
647 : * @param path the path to parse.
648 : * @param cb the callback to call, if we get to the end of @e path.
649 : * @param cb_cls the closure for the callback.
650 : * @return #GNUNET_OK on success, #GNUNET_SYSERR if @e path is malformed.
651 : */
652 : static enum GNUNET_GenericReturnValue
653 16 : parse_path (json_t *obj,
654 : json_t *prev,
655 : const char *path,
656 : TALER_JSON_ExpandPathCallback cb,
657 : void *cb_cls)
658 : {
659 16 : char *id = GNUNET_strdup (path);
660 16 : char *next_id = strchr (id,
661 : '.');
662 : char *next_path;
663 : char *bracket;
664 16 : json_t *next_obj = NULL;
665 : char *next_dot;
666 :
667 16 : GNUNET_assert (NULL != id); /* make stupid compiler happy */
668 16 : if (NULL == next_id)
669 : {
670 5 : cb (cb_cls,
671 : id,
672 : prev);
673 5 : GNUNET_free (id);
674 5 : return GNUNET_OK;
675 : }
676 11 : bracket = strchr (next_id,
677 : '[');
678 11 : *next_id = '\0';
679 11 : next_id++;
680 11 : next_path = GNUNET_strdup (next_id);
681 11 : next_dot = strchr (next_id,
682 : '.');
683 11 : if (NULL != next_dot)
684 3 : *next_dot = '\0';
685 : /* If this is the first time this is called, make sure id is "$" */
686 11 : if ( (NULL == prev) &&
687 6 : (0 != strcmp (id,
688 : "$")))
689 : {
690 1 : GNUNET_free (id);
691 1 : GNUNET_free (next_path);
692 1 : return GNUNET_SYSERR;
693 : }
694 :
695 : /* Check for bracketed indices */
696 10 : if (NULL != bracket)
697 : {
698 3 : char *end_bracket = strchr (bracket,
699 : ']');
700 : json_t *array;
701 :
702 3 : if (NULL == end_bracket)
703 : {
704 0 : GNUNET_free (id);
705 0 : GNUNET_free (next_path);
706 0 : return GNUNET_SYSERR;
707 : }
708 3 : *end_bracket = '\0';
709 3 : *bracket = '\0';
710 3 : bracket++;
711 3 : array = json_object_get (obj,
712 : next_id);
713 3 : if (0 == strcmp (bracket,
714 : "*"))
715 : {
716 : size_t index;
717 : json_t *value;
718 1 : int ret = GNUNET_OK;
719 :
720 4 : json_array_foreach (array, index, value) {
721 3 : ret = parse_path (value,
722 : obj,
723 : next_path,
724 : cb,
725 : cb_cls);
726 3 : if (GNUNET_OK != ret)
727 : {
728 0 : GNUNET_free (id);
729 0 : GNUNET_free (next_path);
730 0 : return ret;
731 : }
732 : }
733 : }
734 : else
735 : {
736 : unsigned int index;
737 : char dummy;
738 :
739 2 : if (1 != sscanf (bracket,
740 : "%u%c",
741 : &index,
742 : &dummy))
743 : {
744 1 : GNUNET_free (id);
745 1 : GNUNET_free (next_path);
746 1 : return GNUNET_SYSERR;
747 : }
748 1 : next_obj = json_array_get (array,
749 : index);
750 : }
751 : }
752 : else
753 : {
754 : /* No brackets, so just fetch the object by name */
755 7 : next_obj = json_object_get (obj,
756 : next_id);
757 : }
758 :
759 9 : if (NULL != next_obj)
760 : {
761 7 : int ret = parse_path (next_obj,
762 : obj,
763 : next_path,
764 : cb,
765 : cb_cls);
766 7 : GNUNET_free (id);
767 7 : GNUNET_free (next_path);
768 7 : return ret;
769 : }
770 2 : GNUNET_free (id);
771 2 : GNUNET_free (next_path);
772 2 : return GNUNET_OK;
773 : }
774 :
775 :
776 : enum GNUNET_GenericReturnValue
777 6 : TALER_JSON_expand_path (json_t *json,
778 : const char *path,
779 : TALER_JSON_ExpandPathCallback cb,
780 : void *cb_cls)
781 : {
782 6 : return parse_path (json,
783 : NULL,
784 : path,
785 : cb,
786 : cb_cls);
787 : }
788 :
789 :
790 : enum TALER_ErrorCode
791 92 : TALER_JSON_get_error_code (const json_t *json)
792 : {
793 : const json_t *jc;
794 :
795 92 : if (NULL == json)
796 0 : return TALER_EC_GENERIC_INVALID_RESPONSE;
797 92 : jc = json_object_get (json, "code");
798 : /* The caller already knows that the JSON represents an error,
799 : so we are dealing with a missing error code here. */
800 92 : if (NULL == jc)
801 : {
802 0 : GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
803 : "Expected Taler error code `code' in JSON, but field does not exist!\n");
804 0 : return TALER_EC_INVALID;
805 : }
806 92 : if (json_is_integer (jc))
807 92 : return (enum TALER_ErrorCode) (int) json_integer_value (jc);
808 0 : GNUNET_break_op (0);
809 0 : return TALER_EC_INVALID;
810 : }
811 :
812 :
813 : const char *
814 82 : TALER_JSON_get_error_hint (const json_t *json)
815 : {
816 : const json_t *jc;
817 :
818 82 : if (NULL == json)
819 0 : return NULL;
820 82 : jc = json_object_get (json,
821 : "hint");
822 82 : if (NULL == jc)
823 0 : return NULL; /* no hint, is allowed */
824 82 : if (! json_is_string (jc))
825 : {
826 : /* Hints must be strings */
827 0 : GNUNET_break_op (0);
828 0 : return NULL;
829 : }
830 82 : return json_string_value (jc);
831 : }
832 :
833 :
834 : enum TALER_ErrorCode
835 0 : TALER_JSON_get_error_code2 (const void *data,
836 : size_t data_size)
837 : {
838 : json_t *json;
839 : enum TALER_ErrorCode ec;
840 : json_error_t err;
841 :
842 0 : json = json_loadb (data,
843 : data_size,
844 : JSON_REJECT_DUPLICATES,
845 : &err);
846 0 : if (NULL == json)
847 0 : return TALER_EC_INVALID;
848 0 : ec = TALER_JSON_get_error_code (json);
849 0 : json_decref (json);
850 0 : if (ec == TALER_EC_NONE)
851 0 : return TALER_EC_INVALID;
852 0 : return ec;
853 : }
854 :
855 :
856 : void
857 0 : TALER_deposit_policy_hash (const json_t *policy,
858 : struct TALER_ExtensionPolicyHashP *ech)
859 : {
860 0 : GNUNET_assert (GNUNET_OK ==
861 : dump_and_hash (policy,
862 : "taler-extensions-policy",
863 : &ech->hash));
864 0 : }
865 :
866 :
867 : char *
868 3 : TALER_JSON_canonicalize (const json_t *input)
869 : {
870 : char *wire_enc;
871 :
872 3 : if (NULL == (wire_enc = json_dumps (input,
873 : JSON_ENCODE_ANY
874 : | JSON_COMPACT
875 : | JSON_SORT_KEYS)))
876 : {
877 0 : GNUNET_break (0);
878 0 : return NULL;
879 : }
880 3 : TALER_rfc8785encode (&wire_enc);
881 3 : return wire_enc;
882 : }
883 :
884 :
885 : json_t *
886 140 : TALER_JSON_currency_specs_to_json (
887 : const struct TALER_CurrencySpecification *cspec)
888 : {
889 : json_t *ca;
890 :
891 140 : ca = json_array ();
892 140 : GNUNET_assert (NULL != ca);
893 700 : for (unsigned int i = 0; i<cspec->num_common_amounts; i++)
894 560 : GNUNET_assert (
895 : 0 ==
896 : json_array_append_new (
897 : ca,
898 : TALER_JSON_from_amount (&cspec->common_amounts[i])));
899 140 : return GNUNET_JSON_PACK (
900 : GNUNET_JSON_pack_string ("name",
901 : cspec->name),
902 : /* 'currency' is deprecated as of exchange v18 and merchant v6;
903 : remove this line once current-age > 6*/
904 : GNUNET_JSON_pack_string ("currency",
905 : cspec->currency),
906 : GNUNET_JSON_pack_array_steal ("common_amounts",
907 : ca),
908 : GNUNET_JSON_pack_uint64 ("num_fractional_input_digits",
909 : cspec->num_fractional_input_digits),
910 : GNUNET_JSON_pack_uint64 ("num_fractional_normal_digits",
911 : cspec->num_fractional_normal_digits),
912 : GNUNET_JSON_pack_uint64 ("num_fractional_trailing_zero_digits",
913 : cspec->num_fractional_trailing_zero_digits),
914 : GNUNET_JSON_pack_object_incref ("alt_unit_names",
915 : cspec->map_alt_unit_names));
916 : }
917 :
918 :
919 : /* End of json/json.c */
|