LCOV - code coverage report
Current view: top level - json - json.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 216 361 59.8 %
Date: 2025-06-05 21:03:14 Functions: 13 16 81.2 %

          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 */

Generated by: LCOV version 1.16