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 "taler/platform.h"
23 : #include <gnunet/gnunet_util_lib.h>
24 : #include "taler/taler_util.h"
25 : #include "taler/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 1116 : contains_real (const json_t *json)
37 : {
38 1116 : if (json_is_real (json))
39 0 : return true;
40 1116 : if (json_is_object (json))
41 : {
42 : json_t *member;
43 : const char *name;
44 :
45 1297 : json_object_foreach ((json_t *) json, name, member)
46 816 : if (contains_real (member))
47 0 : return true;
48 481 : return false;
49 : }
50 635 : if (json_is_array (json))
51 : {
52 : json_t *member;
53 : size_t index;
54 :
55 244 : json_array_foreach ((json_t *) json, index, member)
56 122 : if (contains_real (member))
57 0 : return true;
58 122 : return false;
59 : }
60 513 : 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 178 : 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 178 : if (NULL == json)
84 : {
85 0 : GNUNET_break_op (0);
86 0 : return GNUNET_NO;
87 : }
88 178 : if (contains_real (json))
89 : {
90 0 : GNUNET_break_op (0);
91 0 : return GNUNET_NO;
92 : }
93 178 : 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 178 : len = TALER_rfc8785encode (&wire_enc);
102 178 : if (NULL == salt)
103 : {
104 162 : GNUNET_CRYPTO_hash (wire_enc,
105 : len,
106 : hc);
107 : }
108 : else
109 : {
110 16 : if (GNUNET_YES !=
111 16 : GNUNET_CRYPTO_hkdf_gnunet (
112 : hc,
113 : sizeof (*hc),
114 : salt,
115 : strlen (salt) + 1,
116 : wire_enc,
117 : len))
118 : {
119 0 : GNUNET_break (0);
120 0 : free (wire_enc);
121 0 : return GNUNET_SYSERR;
122 : }
123 : }
124 178 : free (wire_enc);
125 178 : return GNUNET_OK;
126 : }
127 :
128 :
129 : /**
130 : * Replace "forgettable" parts of a JSON object with their salted hash.
131 : *
132 : * @param[in] in some JSON value
133 : * @param[out] out resulting JSON value
134 : * @return #GNUNET_OK on success,
135 : * #GNUNET_NO if @a json was not hash-able
136 : * #GNUNET_SYSERR on failure
137 : */
138 : static enum GNUNET_GenericReturnValue
139 1095 : forget (const json_t *in,
140 : json_t **out)
141 : {
142 1095 : if (json_is_real (in))
143 : {
144 : /* floating point is not allowed! */
145 0 : GNUNET_break_op (0);
146 0 : return GNUNET_NO;
147 : }
148 1095 : if (json_is_array (in))
149 : {
150 : /* array is a JSON array */
151 : size_t index;
152 : json_t *value;
153 : json_t *ret;
154 :
155 122 : ret = json_array ();
156 122 : if (NULL == ret)
157 : {
158 0 : GNUNET_break (0);
159 0 : return GNUNET_SYSERR;
160 : }
161 244 : json_array_foreach (in, index, value) {
162 : enum GNUNET_GenericReturnValue iret;
163 : json_t *t;
164 :
165 122 : iret = forget (value,
166 : &t);
167 122 : if (GNUNET_OK != iret)
168 : {
169 0 : json_decref (ret);
170 0 : return iret;
171 : }
172 122 : if (0 != json_array_append_new (ret,
173 : t))
174 : {
175 0 : GNUNET_break (0);
176 0 : json_decref (ret);
177 0 : return GNUNET_SYSERR;
178 : }
179 : }
180 122 : *out = ret;
181 122 : return GNUNET_OK;
182 : }
183 973 : if (json_is_object (in))
184 : {
185 : json_t *ret;
186 : const char *key;
187 : json_t *value;
188 : json_t *fg;
189 : json_t *rx;
190 :
191 472 : fg = json_object_get (in,
192 : "$forgettable");
193 472 : rx = json_object_get (in,
194 : "$forgotten");
195 472 : if (NULL != rx)
196 : {
197 6 : rx = json_deep_copy (rx); /* 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 472 : ret = json_object ();
207 472 : if (NULL == ret)
208 : {
209 0 : GNUNET_break (0);
210 0 : return GNUNET_SYSERR;
211 : }
212 1294 : json_object_foreach ((json_t*) in, key, value) {
213 : json_t *t;
214 : json_t *salt;
215 : enum GNUNET_GenericReturnValue iret;
216 :
217 822 : if (fg == value)
218 15 : continue; /* skip! */
219 807 : if (rx == value)
220 0 : continue; /* skip! */
221 820 : if ( (NULL != rx) &&
222 : (NULL !=
223 13 : json_object_get (rx,
224 : key)) )
225 : {
226 0 : (void) json_object_del (ret,
227 : key);
228 0 : continue; /* already forgotten earlier */
229 : }
230 807 : iret = forget (value,
231 : &t);
232 807 : if (GNUNET_OK != iret)
233 : {
234 0 : json_decref (ret);
235 0 : json_decref (rx);
236 0 : return iret;
237 : }
238 829 : if ( (NULL != fg) &&
239 22 : (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 795 : if (0 !=
297 795 : 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 487 : 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 472 : *out = ret;
319 472 : return GNUNET_OK;
320 : }
321 501 : *out = json_incref ((json_t *) in);
322 501 : 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 (GNUNET_CRYPTO_QUALITY_NONCE,
399 : &salt,
400 : sizeof (salt));
401 4 : if (0 !=
402 4 : json_object_set_new (fg,
403 : field,
404 : GNUNET_JSON_from_data_auto (&salt)))
405 : {
406 0 : GNUNET_break (0);
407 0 : return GNUNET_SYSERR;
408 : }
409 4 : return GNUNET_OK;
410 : }
411 :
412 :
413 : enum GNUNET_GenericReturnValue
414 4 : TALER_JSON_contract_part_forget (json_t *json,
415 : const char *field)
416 : {
417 : json_t *fg;
418 : const json_t *part;
419 : json_t *fp;
420 : json_t *rx;
421 : struct GNUNET_HashCode hc;
422 : const char *salt;
423 : enum GNUNET_GenericReturnValue ret;
424 :
425 4 : if (! json_is_object (json))
426 : {
427 0 : GNUNET_break (0);
428 0 : return GNUNET_SYSERR;
429 : }
430 4 : if (NULL == (part = json_object_get (json,
431 : field)))
432 : {
433 0 : GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
434 : "Did not find field `%s' we were asked to forget\n",
435 : field);
436 0 : return GNUNET_SYSERR;
437 : }
438 4 : fg = json_object_get (json,
439 : "$forgettable");
440 4 : if (NULL == fg)
441 : {
442 0 : GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
443 : "Did not find '$forgettable' attribute trying to forget field `%s'\n",
444 : field);
445 0 : return GNUNET_SYSERR;
446 : }
447 4 : rx = json_object_get (json,
448 : "$forgotten");
449 4 : if (NULL == rx)
450 : {
451 3 : rx = json_object ();
452 3 : if (0 !=
453 3 : json_object_set_new (json,
454 : "$forgotten",
455 : rx))
456 : {
457 0 : GNUNET_break (0);
458 0 : return GNUNET_SYSERR;
459 : }
460 : }
461 4 : if (NULL !=
462 4 : json_object_get (rx,
463 : field))
464 : {
465 0 : if (! json_is_null (json_object_get (json,
466 : field)))
467 : {
468 0 : GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
469 : "Field `%s' market as forgotten, but still exists!\n",
470 : field);
471 0 : return GNUNET_SYSERR;
472 : }
473 0 : GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
474 : "Already forgot field `%s'\n",
475 : field);
476 0 : return GNUNET_NO;
477 : }
478 4 : salt = json_string_value (json_object_get (fg,
479 : field));
480 4 : if (NULL == salt)
481 : {
482 0 : GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
483 : "Did not find required salt to forget field `%s'\n",
484 : field);
485 0 : return GNUNET_SYSERR;
486 : }
487 :
488 : /* need to recursively forget to compute 'hc' */
489 4 : ret = forget (part,
490 : &fp);
491 4 : if (GNUNET_OK != ret)
492 0 : return ret;
493 4 : if (GNUNET_OK !=
494 4 : dump_and_hash (fp,
495 : salt,
496 : &hc))
497 : {
498 0 : json_decref (fp);
499 0 : GNUNET_break (0);
500 0 : return GNUNET_SYSERR;
501 : }
502 4 : json_decref (fp);
503 : /* drop salt */
504 4 : if (0 !=
505 4 : json_object_del (fg,
506 : field))
507 : {
508 0 : json_decref (fp);
509 0 : GNUNET_break (0);
510 0 : return GNUNET_SYSERR;
511 : }
512 :
513 : /* remember field as 'forgotten' */
514 4 : if (0 !=
515 4 : json_object_set_new (rx,
516 : field,
517 : GNUNET_JSON_from_data_auto (&hc)))
518 : {
519 0 : GNUNET_break (0);
520 0 : return GNUNET_SYSERR;
521 : }
522 : /* finally, set 'forgotten' field to null */
523 4 : if (0 !=
524 4 : json_object_del (json,
525 : field))
526 : {
527 0 : GNUNET_break (0);
528 0 : return GNUNET_SYSERR;
529 : }
530 4 : return GNUNET_OK;
531 : }
532 :
533 :
534 : /**
535 : * Loop over all of the values of a '$forgettable' object. Replace 'True'
536 : * values with proper random salts. Fails if any forgettable values are
537 : * neither 'True' nor valid salts (strings).
538 : *
539 : * @param[in,out] f JSON to transform
540 : * @return #GNUNET_OK on success
541 : */
542 : static enum GNUNET_GenericReturnValue
543 1 : seed_forgettable (json_t *f)
544 : {
545 : const char *key;
546 : json_t *val;
547 :
548 2 : json_object_foreach (f,
549 : key,
550 : val)
551 : {
552 1 : if (json_is_string (val))
553 0 : continue;
554 1 : if (json_is_true (val))
555 1 : {
556 : struct GNUNET_ShortHashCode sh;
557 :
558 1 : GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
559 : &sh,
560 : sizeof (sh));
561 1 : if (0 !=
562 1 : json_object_set_new (f,
563 : key,
564 : GNUNET_JSON_from_data_auto (&sh)))
565 : {
566 0 : GNUNET_break (0);
567 0 : return GNUNET_SYSERR;
568 : }
569 1 : continue;
570 : }
571 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
572 : "Forgettable field `%s' has invalid value\n",
573 : key);
574 0 : return GNUNET_SYSERR;
575 : }
576 1 : return GNUNET_OK;
577 : }
578 :
579 :
580 : enum GNUNET_GenericReturnValue
581 4 : TALER_JSON_contract_seed_forgettable (const json_t *spec,
582 : json_t *contract)
583 : {
584 4 : if (json_is_object (spec))
585 : {
586 : const char *key;
587 : json_t *val;
588 :
589 6 : json_object_foreach ((json_t *) spec,
590 : key,
591 : val)
592 : {
593 4 : json_t *cval = json_object_get (contract,
594 : key);
595 :
596 4 : if (0 == strcmp ("$forgettable",
597 : key))
598 1 : {
599 1 : json_t *xval = json_deep_copy (val);
600 :
601 1 : if (GNUNET_OK !=
602 1 : seed_forgettable (xval))
603 : {
604 0 : json_decref (xval);
605 0 : return GNUNET_SYSERR;
606 : }
607 1 : GNUNET_assert (0 ==
608 : json_object_set_new (contract,
609 : "$forgettable",
610 : xval));
611 1 : continue;
612 : }
613 3 : if (NULL == cval)
614 0 : continue;
615 3 : if (GNUNET_OK !=
616 3 : TALER_JSON_contract_seed_forgettable (val,
617 : cval))
618 0 : return GNUNET_SYSERR;
619 : }
620 : }
621 4 : if (json_is_array (spec))
622 : {
623 : size_t index;
624 : json_t *val;
625 :
626 0 : json_array_foreach ((json_t *) spec,
627 : index,
628 : val)
629 : {
630 0 : json_t *ival = json_array_get (contract,
631 : index);
632 :
633 0 : if (NULL == ival)
634 0 : continue;
635 0 : if (GNUNET_OK !=
636 0 : TALER_JSON_contract_seed_forgettable (val,
637 : ival))
638 0 : return GNUNET_SYSERR;
639 : }
640 : }
641 4 : return GNUNET_OK;
642 : }
643 :
644 :
645 : /**
646 : * Parse a json path.
647 : *
648 : * @param obj the object that the path is relative to.
649 : * @param prev the parent of @e obj.
650 : * @param path the path to parse.
651 : * @param cb the callback to call, if we get to the end of @e path.
652 : * @param cb_cls the closure for the callback.
653 : * @return #GNUNET_OK on success, #GNUNET_SYSERR if @e path is malformed.
654 : */
655 : static enum GNUNET_GenericReturnValue
656 16 : parse_path (json_t *obj,
657 : json_t *prev,
658 : const char *path,
659 : TALER_JSON_ExpandPathCallback cb,
660 : void *cb_cls)
661 : {
662 16 : char *id = GNUNET_strdup (path);
663 16 : char *next_id = strchr (id,
664 : '.');
665 : char *next_path;
666 : char *bracket;
667 16 : json_t *next_obj = NULL;
668 : char *next_dot;
669 :
670 16 : GNUNET_assert (NULL != id); /* make stupid compiler happy */
671 16 : if (NULL == next_id)
672 : {
673 5 : cb (cb_cls,
674 : id,
675 : prev);
676 5 : GNUNET_free (id);
677 5 : return GNUNET_OK;
678 : }
679 11 : bracket = strchr (next_id,
680 : '[');
681 11 : *next_id = '\0';
682 11 : next_id++;
683 11 : next_path = GNUNET_strdup (next_id);
684 11 : next_dot = strchr (next_id,
685 : '.');
686 11 : if (NULL != next_dot)
687 3 : *next_dot = '\0';
688 : /* If this is the first time this is called, make sure id is "$" */
689 11 : if ( (NULL == prev) &&
690 6 : (0 != strcmp (id,
691 : "$")))
692 : {
693 1 : GNUNET_free (id);
694 1 : GNUNET_free (next_path);
695 1 : return GNUNET_SYSERR;
696 : }
697 :
698 : /* Check for bracketed indices */
699 10 : if (NULL != bracket)
700 : {
701 3 : char *end_bracket = strchr (bracket,
702 : ']');
703 : json_t *array;
704 :
705 3 : if (NULL == end_bracket)
706 : {
707 0 : GNUNET_free (id);
708 0 : GNUNET_free (next_path);
709 0 : return GNUNET_SYSERR;
710 : }
711 3 : *end_bracket = '\0';
712 3 : *bracket = '\0';
713 3 : bracket++;
714 3 : array = json_object_get (obj,
715 : next_id);
716 3 : if (0 == strcmp (bracket,
717 : "*"))
718 : {
719 : size_t index;
720 : json_t *value;
721 1 : int ret = GNUNET_OK;
722 :
723 4 : json_array_foreach (array, index, value) {
724 3 : ret = parse_path (value,
725 : obj,
726 : next_path,
727 : cb,
728 : cb_cls);
729 3 : if (GNUNET_OK != ret)
730 : {
731 0 : GNUNET_free (id);
732 0 : GNUNET_free (next_path);
733 0 : return ret;
734 : }
735 : }
736 : }
737 : else
738 : {
739 : unsigned int index;
740 : char dummy;
741 :
742 2 : if (1 != sscanf (bracket,
743 : "%u%c",
744 : &index,
745 : &dummy))
746 : {
747 1 : GNUNET_free (id);
748 1 : GNUNET_free (next_path);
749 1 : return GNUNET_SYSERR;
750 : }
751 1 : next_obj = json_array_get (array,
752 : index);
753 : }
754 : }
755 : else
756 : {
757 : /* No brackets, so just fetch the object by name */
758 7 : next_obj = json_object_get (obj,
759 : next_id);
760 : }
761 :
762 9 : if (NULL != next_obj)
763 : {
764 7 : int ret = parse_path (next_obj,
765 : obj,
766 : next_path,
767 : cb,
768 : cb_cls);
769 7 : GNUNET_free (id);
770 7 : GNUNET_free (next_path);
771 7 : return ret;
772 : }
773 2 : GNUNET_free (id);
774 2 : GNUNET_free (next_path);
775 2 : return GNUNET_OK;
776 : }
777 :
778 :
779 : enum GNUNET_GenericReturnValue
780 6 : TALER_JSON_expand_path (json_t *json,
781 : const char *path,
782 : TALER_JSON_ExpandPathCallback cb,
783 : void *cb_cls)
784 : {
785 6 : return parse_path (json,
786 : NULL,
787 : path,
788 : cb,
789 : cb_cls);
790 : }
791 :
792 :
793 : enum TALER_ErrorCode
794 77 : TALER_JSON_get_error_code (const json_t *json)
795 : {
796 : const json_t *jc;
797 :
798 77 : if (NULL == json)
799 0 : return TALER_EC_GENERIC_INVALID_RESPONSE;
800 77 : jc = json_object_get (json, "code");
801 : /* The caller already knows that the JSON represents an error,
802 : so we are dealing with a missing error code here. */
803 77 : if (NULL == jc)
804 : {
805 0 : GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
806 : "Expected Taler error code `code' in JSON, but field does not exist!\n");
807 0 : return TALER_EC_INVALID;
808 : }
809 77 : if (json_is_integer (jc))
810 77 : return (enum TALER_ErrorCode) (int) json_integer_value (jc);
811 0 : GNUNET_break_op (0);
812 0 : return TALER_EC_INVALID;
813 : }
814 :
815 :
816 : const char *
817 63 : TALER_JSON_get_error_hint (const json_t *json)
818 : {
819 : const json_t *jc;
820 :
821 63 : if (NULL == json)
822 0 : return NULL;
823 63 : jc = json_object_get (json,
824 : "hint");
825 63 : if (NULL == jc)
826 0 : return NULL; /* no hint, is allowed */
827 63 : if (! json_is_string (jc))
828 : {
829 : /* Hints must be strings */
830 0 : GNUNET_break_op (0);
831 0 : return NULL;
832 : }
833 63 : return json_string_value (jc);
834 : }
835 :
836 :
837 : enum TALER_ErrorCode
838 0 : TALER_JSON_get_error_code2 (const void *data,
839 : size_t data_size)
840 : {
841 : json_t *json;
842 : enum TALER_ErrorCode ec;
843 : json_error_t err;
844 :
845 0 : json = json_loadb (data,
846 : data_size,
847 : JSON_REJECT_DUPLICATES,
848 : &err);
849 0 : if (NULL == json)
850 0 : return TALER_EC_INVALID;
851 0 : ec = TALER_JSON_get_error_code (json);
852 0 : json_decref (json);
853 0 : if (ec == TALER_EC_NONE)
854 0 : return TALER_EC_INVALID;
855 0 : return ec;
856 : }
857 :
858 :
859 : void
860 0 : TALER_deposit_policy_hash (const json_t *policy,
861 : struct TALER_ExtensionPolicyHashP *ech)
862 : {
863 0 : GNUNET_assert (GNUNET_OK ==
864 : dump_and_hash (policy,
865 : "taler-extensions-policy",
866 : &ech->hash));
867 0 : }
868 :
869 :
870 : char *
871 3 : TALER_JSON_canonicalize (const json_t *input)
872 : {
873 : char *wire_enc;
874 :
875 3 : if (NULL == (wire_enc = json_dumps (input,
876 : JSON_ENCODE_ANY
877 : | JSON_COMPACT
878 : | JSON_SORT_KEYS)))
879 : {
880 0 : GNUNET_break (0);
881 0 : return NULL;
882 : }
883 3 : TALER_rfc8785encode (&wire_enc);
884 3 : return wire_enc;
885 : }
886 :
887 :
888 : enum GNUNET_GenericReturnValue
889 0 : TALER_JSON_extensions_manifests_hash (const json_t *manifests,
890 : struct TALER_ExtensionManifestsHashP *ech)
891 : {
892 0 : return dump_and_hash (manifests,
893 : "taler-extensions-manifests",
894 : &ech->hash);
895 : }
896 :
897 :
898 : json_t *
899 95 : TALER_JSON_currency_specs_to_json (
900 : const struct TALER_CurrencySpecification *cspec)
901 : {
902 : json_t *ca;
903 :
904 95 : ca = json_array ();
905 95 : GNUNET_assert (NULL != ca);
906 475 : for (unsigned int i = 0; i<cspec->num_common_amounts; i++)
907 380 : GNUNET_assert (
908 : 0 ==
909 : json_array_append_new (
910 : ca,
911 : TALER_JSON_from_amount (&cspec->common_amounts[i])));
912 95 : return GNUNET_JSON_PACK (
913 : GNUNET_JSON_pack_string ("name",
914 : cspec->name),
915 : /* 'currency' is deprecated as of exchange v18 and merchant v6;
916 : remove this line once current-age > 6*/
917 : GNUNET_JSON_pack_string ("currency",
918 : cspec->currency),
919 : GNUNET_JSON_pack_array_steal ("common_amounts",
920 : ca),
921 : GNUNET_JSON_pack_uint64 ("num_fractional_input_digits",
922 : cspec->num_fractional_input_digits),
923 : GNUNET_JSON_pack_uint64 ("num_fractional_normal_digits",
924 : cspec->num_fractional_normal_digits),
925 : GNUNET_JSON_pack_uint64 ("num_fractional_trailing_zero_digits",
926 : cspec->num_fractional_trailing_zero_digits),
927 : GNUNET_JSON_pack_object_incref ("alt_unit_names",
928 : cspec->map_alt_unit_names));
929 : }
930 :
931 :
932 : /* End of json/json.c */
|