LCOV - code coverage report
Current view: top level - json - json.c (source / functions) Coverage Total Hit
Test: coverage.info Lines: 60.5 % 367 222
Test Date: 2025-12-26 23:00:34 Functions: 82.4 % 17 14

            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_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          178 :   free (wire_enc);
     126          178 :   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         1095 : forget (const json_t *in,
     141              :         json_t **out)
     142              : {
     143         1095 :   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         1095 :   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          122 :     ret = json_array ();
     157          122 :     if (NULL == ret)
     158              :     {
     159            0 :       GNUNET_break (0);
     160            0 :       return GNUNET_SYSERR;
     161              :     }
     162          244 :     json_array_foreach (in, index, value) {
     163              :       enum GNUNET_GenericReturnValue iret;
     164              :       json_t *t;
     165              : 
     166          122 :       iret = forget (value,
     167              :                      &t);
     168          122 :       if (GNUNET_OK != iret)
     169              :       {
     170            0 :         json_decref (ret);
     171            0 :         return iret;
     172              :       }
     173          122 :       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          122 :     *out = ret;
     182          122 :     return GNUNET_OK;
     183              :   }
     184          973 :   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          472 :     fg = json_object_get (in,
     193              :                           "$forgettable");
     194          472 :     rx = json_object_get (in,
     195              :                           "$forgotten");
     196          472 :     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          472 :     ret = json_object ();
     208          472 :     if (NULL == ret)
     209              :     {
     210            0 :       GNUNET_break (0);
     211            0 :       return GNUNET_SYSERR;
     212              :     }
     213         1294 :     json_object_foreach ((json_t*) in, key, value) {
     214              :       json_t *t;
     215              :       json_t *salt;
     216              :       enum GNUNET_GenericReturnValue iret;
     217              : 
     218          822 :       if (fg == value)
     219           15 :         continue; /* skip! */
     220          807 :       if (rx == value)
     221            0 :         continue; /* skip! */
     222          820 :       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          807 :       iret = forget (value,
     232              :                      &t);
     233          807 :       if (GNUNET_OK != iret)
     234              :       {
     235            0 :         json_decref (ret);
     236            0 :         json_decref (rx);
     237            0 :         return iret;
     238              :       }
     239          829 :       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          795 :         if (0 !=
     298          795 :             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          487 :     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          472 :     *out = ret;
     320          472 :     return GNUNET_OK;
     321              :   }
     322          501 :   *out = json_incref ((json_t *) in);
     323          501 :   return GNUNET_OK;
     324              : }
     325              : 
     326              : 
     327              : enum GNUNET_GenericReturnValue
     328          162 : 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          162 :   dc = json_deep_copy (json);
     336          162 :   ret = forget (dc,
     337              :                 &cjson);
     338          162 :   json_decref (dc);
     339          162 :   if (GNUNET_OK != ret)
     340            0 :     return ret;
     341          162 :   ret = dump_and_hash (cjson,
     342              :                        NULL,
     343              :                        &hc->hash);
     344          162 :   json_decref (cjson);
     345          162 :   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            4 : TALER_JSON_contract_seed_forgettable (const json_t *spec,
     583              :                                       json_t *contract)
     584              : {
     585            4 :   if (json_is_object (spec))
     586              :   {
     587              :     const char *key;
     588              :     json_t *val;
     589              : 
     590            6 :     json_object_foreach ((json_t *) spec,
     591              :                          key,
     592              :                          val)
     593              :     {
     594            4 :       json_t *cval = json_object_get (contract,
     595              :                                       key);
     596              : 
     597            4 :       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            3 :       if (NULL == cval)
     615            0 :         continue;
     616            3 :       if (GNUNET_OK !=
     617            3 :           TALER_JSON_contract_seed_forgettable (val,
     618              :                                                 cval))
     619            0 :         return GNUNET_SYSERR;
     620              :     }
     621              :   }
     622            4 :   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            4 :   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              : json_t *
     900          710 : TALER_JSON_currency_specs_to_json (
     901              :   const struct TALER_CurrencySpecification *cspec)
     902              : {
     903              :   json_t *ca;
     904              : 
     905          710 :   ca = json_array ();
     906          710 :   GNUNET_assert (NULL != ca);
     907         3550 :   for (unsigned int i = 0; i<cspec->num_common_amounts; i++)
     908         2840 :     GNUNET_assert (
     909              :       0 ==
     910              :       json_array_append_new (
     911              :         ca,
     912              :         TALER_JSON_from_amount (&cspec->common_amounts[i])));
     913          710 :   return GNUNET_JSON_PACK (
     914              :     GNUNET_JSON_pack_string ("name",
     915              :                              cspec->name),
     916              :     /* 'currency' is deprecated as of exchange v18 and merchant v6;
     917              :        remove this line once current-age > 6*/
     918              :     GNUNET_JSON_pack_string ("currency",
     919              :                              cspec->currency),
     920              :     GNUNET_JSON_pack_array_steal ("common_amounts",
     921              :                                   ca),
     922              :     GNUNET_JSON_pack_uint64 ("num_fractional_input_digits",
     923              :                              cspec->num_fractional_input_digits),
     924              :     GNUNET_JSON_pack_uint64 ("num_fractional_normal_digits",
     925              :                              cspec->num_fractional_normal_digits),
     926              :     GNUNET_JSON_pack_uint64 ("num_fractional_trailing_zero_digits",
     927              :                              cspec->num_fractional_trailing_zero_digits),
     928              :     GNUNET_JSON_pack_object_incref ("alt_unit_names",
     929              :                                     cspec->map_alt_unit_names));
     930              : }
     931              : 
     932              : 
     933              : /* End of json/json.c */
        

Generated by: LCOV version 2.0-1