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

Generated by: LCOV version 2.0-1