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-03 22:53:11 Functions: 82.4 % 17 14

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

Generated by: LCOV version 2.0-1