LCOV - code coverage report
Current view: top level - json - json.c (source / functions) Hit Total Coverage
Test: GNU Taler exchange coverage report Lines: 204 335 60.9 %
Date: 2021-08-30 06:43:37 Functions: 12 13 92.3 %
Legend: Lines: hit not hit

          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             : 
      27             : 
      28             : /**
      29             :  * Check if @a json contains a 'real' value anywhere.
      30             :  *
      31             :  * @param json json to check
      32             :  * @return true if a real is in it somewhere
      33             :  */
      34             : static bool
      35         489 : contains_real (const json_t *json)
      36             : {
      37         489 :   if (json_is_real (json))
      38           0 :     return true;
      39         489 :   if (json_is_object (json))
      40             :   {
      41             :     json_t *member;
      42             :     const char *name;
      43             : 
      44         569 :     json_object_foreach ((json_t *) json, name, member)
      45         353 :     if (contains_real (member))
      46           0 :       return true;
      47         216 :     return false;
      48             :   }
      49         273 :   if (json_is_array (json))
      50             :   {
      51             :     json_t *member;
      52             :     size_t index;
      53             : 
      54         112 :     json_array_foreach ((json_t *) json, index, member)
      55          56 :     if (contains_real (member))
      56           0 :       return true;
      57          56 :     return false;
      58             :   }
      59         217 :   return false;
      60             : }
      61             : 
      62             : 
      63             : /**
      64             :  * Dump the @a json to a string and hash it.
      65             :  *
      66             :  * @param json value to hash
      67             :  * @param salt salt value to include when using HKDF,
      68             :  *        NULL to not use any salt and to use SHA512
      69             :  * @param[out] hc where to store the hash
      70             :  * @return #GNUNET_OK on success,
      71             :  *         #GNUNET_NO if @a json was not hash-able
      72             :  *         #GNUNET_SYSERR on failure
      73             :  */
      74             : static enum GNUNET_GenericReturnValue
      75          80 : dump_and_hash (const json_t *json,
      76             :                const char *salt,
      77             :                struct GNUNET_HashCode *hc)
      78             : {
      79             :   char *wire_enc;
      80             :   size_t len;
      81             : 
      82          80 :   if (NULL == json)
      83             :   {
      84           0 :     GNUNET_break_op (0);
      85           0 :     return GNUNET_NO;
      86             :   }
      87          80 :   if (contains_real (json))
      88             :   {
      89           0 :     GNUNET_break_op (0);
      90           0 :     return GNUNET_NO;
      91             :   }
      92          80 :   if (NULL == (wire_enc = json_dumps (json,
      93             :                                       JSON_ENCODE_ANY
      94             :                                       | JSON_COMPACT
      95             :                                       | JSON_SORT_KEYS)))
      96             :   {
      97           0 :     GNUNET_break (0);
      98           0 :     return GNUNET_SYSERR;
      99             :   }
     100          80 :   len = strlen (wire_enc) + 1;
     101          80 :   if (NULL == salt)
     102             :   {
     103          64 :     GNUNET_CRYPTO_hash (wire_enc,
     104             :                         len,
     105             :                         hc);
     106             :   }
     107             :   else
     108             :   {
     109          16 :     if (GNUNET_YES !=
     110          16 :         GNUNET_CRYPTO_kdf (hc,
     111             :                            sizeof (*hc),
     112             :                            salt,
     113          16 :                            strlen (salt) + 1,
     114             :                            wire_enc,
     115             :                            len,
     116             :                            NULL,
     117             :                            0))
     118             :     {
     119           0 :       GNUNET_break (0);
     120           0 :       free (wire_enc);
     121           0 :       return GNUNET_SYSERR;
     122             :     }
     123             :   }
     124          80 :   free (wire_enc);
     125          80 :   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         468 : forget (const json_t *in,
     140             :         json_t **out)
     141             : {
     142         468 :   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         468 :   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          56 :     ret = json_array ();
     156          56 :     if (NULL == ret)
     157             :     {
     158           0 :       GNUNET_break (0);
     159           0 :       return GNUNET_SYSERR;
     160             :     }
     161         112 :     json_array_foreach (in, index, value) {
     162             :       enum GNUNET_GenericReturnValue iret;
     163             :       json_t *t;
     164             : 
     165          56 :       iret = forget (value,
     166             :                      &t);
     167          56 :       if (GNUNET_OK != iret)
     168             :       {
     169           0 :         json_decref (ret);
     170           0 :         return iret;
     171             :       }
     172          56 :       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          56 :     *out = ret;
     181          56 :     return GNUNET_OK;
     182             :   }
     183         412 :   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         207 :     fg = json_object_get (in,
     192             :                           "$forgettable");
     193         207 :     rx = json_object_get (in,
     194             :                           "$forgotten");
     195         207 :     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         207 :     ret = json_object ();
     207         207 :     if (NULL == ret)
     208             :     {
     209           0 :       GNUNET_break (0);
     210           0 :       return GNUNET_SYSERR;
     211             :     }
     212         566 :     json_object_foreach ((json_t*) in, key, value) {
     213             :       json_t *t;
     214             :       json_t *salt;
     215             :       enum GNUNET_GenericReturnValue iret;
     216             : 
     217         359 :       if (fg == value)
     218          15 :         continue; /* skip! */
     219         344 :       if (rx == value)
     220           0 :         continue; /* skip! */
     221         357 :       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         344 :       iret = forget (value,
     231             :                      &t);
     232         344 :       if (GNUNET_OK != iret)
     233             :       {
     234           0 :         json_decref (ret);
     235           0 :         json_decref (rx);
     236           0 :         return iret;
     237             :       }
     238         366 :       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         332 :         if (0 !=
     297         332 :             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         222 :     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         207 :     *out = ret;
     319         207 :     return GNUNET_OK;
     320             :   }
     321         205 :   *out = json_incref ((json_t *) in);
     322         205 :   return GNUNET_OK;
     323             : }
     324             : 
     325             : 
     326             : enum GNUNET_GenericReturnValue
     327          64 : TALER_JSON_contract_hash (const json_t *json,
     328             :                           struct GNUNET_HashCode *hc)
     329             : {
     330             :   enum GNUNET_GenericReturnValue ret;
     331             :   json_t *cjson;
     332             :   json_t *dc;
     333             : 
     334          64 :   dc = json_deep_copy (json);
     335          64 :   ret = forget (dc,
     336             :                 &cjson);
     337          64 :   json_decref (dc);
     338          64 :   if (GNUNET_OK != ret)
     339           0 :     return ret;
     340          64 :   ret = dump_and_hash (cjson,
     341             :                        NULL,
     342             :                        hc);
     343          64 :   json_decref (cjson);
     344          64 :   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             :  * Look 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             :     {
     556             :       struct GNUNET_ShortHashCode sh;
     557             : 
     558           1 :       GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
     559             :                                   &sh,
     560             :                                   sizeof (sh));
     561           1 :       json_object_set_new (f,
     562             :                            key,
     563             :                            GNUNET_JSON_from_data_auto (&sh));
     564           1 :       continue;
     565             :     }
     566           0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     567             :                 "Forgettable field `%s' has invalid value\n",
     568             :                 key);
     569           0 :     return GNUNET_SYSERR;
     570             :   }
     571           1 :   return GNUNET_OK;
     572             : }
     573             : 
     574             : 
     575             : /**
     576             :  * Take a given contract with "forgettable" fields marked
     577             :  * but with 'True' instead of a real salt. Replaces all
     578             :  * 'True' values with proper random salts.  Fails if any
     579             :  * forgettable markers are neither 'True' nor valid salts.
     580             :  *
     581             :  * @param[in,out] json JSON to transform
     582             :  * @return #GNUNET_OK on success
     583             :  */
     584             : enum GNUNET_GenericReturnValue
     585           4 : TALER_JSON_contract_seed_forgettable (json_t *json)
     586             : {
     587           4 :   if (json_is_object (json))
     588             :   {
     589             :     const char *key;
     590             :     json_t *val;
     591             : 
     592           6 :     json_object_foreach (json,
     593             :                          key,
     594             :                          val)
     595             :     {
     596           4 :       if (0 == strcmp ("$forgettable",
     597             :                        key))
     598             :       {
     599           1 :         if (GNUNET_OK !=
     600           1 :             seed_forgettable (val))
     601           0 :           return GNUNET_SYSERR;
     602           1 :         continue;
     603             :       }
     604           3 :       if (GNUNET_OK !=
     605           3 :           TALER_JSON_contract_seed_forgettable (val))
     606           0 :         return GNUNET_SYSERR;
     607             :     }
     608             :   }
     609           4 :   if (json_is_array (json))
     610             :   {
     611             :     size_t index;
     612             :     json_t *val;
     613             : 
     614           0 :     json_array_foreach (json,
     615             :                         index,
     616             :                         val)
     617             :     {
     618           0 :       if (GNUNET_OK !=
     619           0 :           TALER_JSON_contract_seed_forgettable (val))
     620           0 :         return GNUNET_SYSERR;
     621             :     }
     622             :   }
     623           4 :   return GNUNET_OK;
     624             : }
     625             : 
     626             : 
     627             : /**
     628             :  * Parse a json path.
     629             :  *
     630             :  * @param obj the object that the path is relative to.
     631             :  * @param prev the parent of @e obj.
     632             :  * @param path the path to parse.
     633             :  * @param cb the callback to call, if we get to the end of @e path.
     634             :  * @param cb_cls the closure for the callback.
     635             :  * @return #GNUNET_OK on success, #GNUNET_SYSERR if @e path is malformed.
     636             :  */
     637             : static enum GNUNET_GenericReturnValue
     638          16 : parse_path (json_t *obj,
     639             :             json_t *prev,
     640             :             const char *path,
     641             :             TALER_JSON_ExpandPathCallback cb,
     642             :             void *cb_cls)
     643             : {
     644          16 :   char *id = GNUNET_strdup (path);
     645          16 :   char *next_id = strchr (id,
     646             :                           '.');
     647             :   char *next_path;
     648             :   char *bracket;
     649          16 :   json_t *next_obj = NULL;
     650             :   char *next_dot;
     651             : 
     652          16 :   if (NULL == next_id)
     653             :   {
     654           5 :     cb (cb_cls,
     655             :         id,
     656             :         prev);
     657           5 :     GNUNET_free (id);
     658           5 :     return GNUNET_OK;
     659             :   }
     660          11 :   bracket = strchr (next_id,
     661             :                     '[');
     662          11 :   *next_id = '\0';
     663          11 :   next_id++;
     664          11 :   next_path = GNUNET_strdup (next_id);
     665          11 :   next_dot = strchr (next_id,
     666             :                      '.');
     667          11 :   if (NULL != next_dot)
     668           3 :     *next_dot = '\0';
     669             :   /* If this is the first time this is called, make sure id is "$" */
     670          11 :   if ( (NULL == prev) &&
     671           6 :        (0 != strcmp (id,
     672             :                      "$")))
     673             :   {
     674           1 :     GNUNET_free (id);
     675           1 :     GNUNET_free (next_path);
     676           1 :     return GNUNET_SYSERR;
     677             :   }
     678             : 
     679             :   /* Check for bracketed indices */
     680          10 :   if (NULL != bracket)
     681             :   {
     682           3 :     char *end_bracket = strchr (bracket,
     683             :                                 ']');
     684           3 :     if (NULL == end_bracket)
     685             :     {
     686           0 :       GNUNET_free (id);
     687           0 :       GNUNET_free (next_path);
     688           0 :       return GNUNET_SYSERR;
     689             :     }
     690           3 :     *end_bracket = '\0';
     691             : 
     692           3 :     *bracket = '\0';
     693           3 :     bracket++;
     694             : 
     695           3 :     json_t *array = json_object_get (obj,
     696             :                                      next_id);
     697           3 :     if (0 == strcmp (bracket,
     698             :                      "*"))
     699             :     {
     700             :       size_t index;
     701             :       json_t *value;
     702           1 :       int ret = GNUNET_OK;
     703             : 
     704           4 :       json_array_foreach (array, index, value) {
     705           3 :         ret = parse_path (value,
     706             :                           obj,
     707             :                           next_path,
     708             :                           cb,
     709             :                           cb_cls);
     710           3 :         if (GNUNET_OK != ret)
     711             :         {
     712           0 :           GNUNET_free (id);
     713           0 :           GNUNET_free (next_path);
     714           0 :           return ret;
     715             :         }
     716             :       }
     717             :     }
     718             :     else
     719             :     {
     720             :       unsigned int index;
     721             :       char dummy;
     722             : 
     723           2 :       if (1 != sscanf (bracket,
     724             :                        "%u%c",
     725             :                        &index,
     726             :                        &dummy))
     727             :       {
     728           1 :         GNUNET_free (id);
     729           1 :         GNUNET_free (next_path);
     730           1 :         return GNUNET_SYSERR;
     731             :       }
     732           1 :       next_obj = json_array_get (array,
     733             :                                  index);
     734             :     }
     735             :   }
     736             :   else
     737             :   {
     738             :     /* No brackets, so just fetch the object by name */
     739           7 :     next_obj = json_object_get (obj,
     740             :                                 next_id);
     741             :   }
     742             : 
     743           9 :   if (NULL != next_obj)
     744             :   {
     745           7 :     int ret = parse_path (next_obj,
     746             :                           obj,
     747             :                           next_path,
     748             :                           cb,
     749             :                           cb_cls);
     750           7 :     GNUNET_free (id);
     751           7 :     GNUNET_free (next_path);
     752           7 :     return ret;
     753             :   }
     754           2 :   GNUNET_free (id);
     755           2 :   GNUNET_free (next_path);
     756           2 :   return GNUNET_OK;
     757             : }
     758             : 
     759             : 
     760             : enum GNUNET_GenericReturnValue
     761           6 : TALER_JSON_expand_path (json_t *json,
     762             :                         const char *path,
     763             :                         TALER_JSON_ExpandPathCallback cb,
     764             :                         void *cb_cls)
     765             : {
     766           6 :   return parse_path (json,
     767             :                      NULL,
     768             :                      path,
     769             :                      cb,
     770             :                      cb_cls);
     771             : }
     772             : 
     773             : 
     774             : enum TALER_ErrorCode
     775          51 : TALER_JSON_get_error_code (const json_t *json)
     776             : {
     777             :   const json_t *jc;
     778             : 
     779          51 :   if (NULL == json)
     780           0 :     return TALER_EC_GENERIC_INVALID_RESPONSE;
     781          51 :   jc = json_object_get (json, "code");
     782             :   /* The caller already knows that the JSON represents an error,
     783             :      so we are dealing with a missing error code here.  */
     784          51 :   if (NULL == jc)
     785             :   {
     786           0 :     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
     787             :                 "Expected Taler error code `code' in JSON, but field does not exist!\n");
     788           0 :     return TALER_EC_INVALID;
     789             :   }
     790          51 :   if (json_is_integer (jc))
     791          51 :     return (enum TALER_ErrorCode) json_integer_value (jc);
     792           0 :   GNUNET_break_op (0);
     793           0 :   return TALER_EC_INVALID;
     794             : }
     795             : 
     796             : 
     797             : const char *
     798          34 : TALER_JSON_get_error_hint (const json_t *json)
     799             : {
     800             :   const json_t *jc;
     801             : 
     802          34 :   if (NULL == json)
     803           0 :     return NULL;
     804          34 :   jc = json_object_get (json,
     805             :                         "hint");
     806          34 :   if (NULL == jc)
     807           0 :     return NULL; /* no hint, is allowed */
     808          34 :   if (! json_is_string (jc))
     809             :   {
     810             :     /* Hints must be strings */
     811           0 :     GNUNET_break_op (0);
     812           0 :     return NULL;
     813             :   }
     814          34 :   return json_string_value (jc);
     815             : }
     816             : 
     817             : 
     818             : enum TALER_ErrorCode
     819           0 : TALER_JSON_get_error_code2 (const void *data,
     820             :                             size_t data_size)
     821             : {
     822             :   json_t *json;
     823             :   enum TALER_ErrorCode ec;
     824             :   json_error_t err;
     825             : 
     826           0 :   json = json_loadb (data,
     827             :                      data_size,
     828             :                      JSON_REJECT_DUPLICATES,
     829             :                      &err);
     830           0 :   if (NULL == json)
     831           0 :     return TALER_EC_INVALID;
     832           0 :   ec = TALER_JSON_get_error_code (json);
     833           0 :   json_decref (json);
     834           0 :   if (ec == TALER_EC_NONE)
     835           0 :     return TALER_EC_INVALID;
     836           0 :   return ec;
     837             : }
     838             : 
     839             : 
     840             : /* End of json/json.c */

Generated by: LCOV version 1.14