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

Generated by: LCOV version 1.14