exchange

Base system with REST service to issue digital coins, run by the payment service provider
Log | Files | Refs | Submodules | README | LICENSE

util.c (11710B)


      1 /*
      2   This file is part of TALER
      3   Copyright (C) 2014-2023 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 util.c
     18  * @brief Common utility functions
     19  * @author Sree Harsha Totakura <sreeharsha@totakura.in>
     20  * @author Florian Dold
     21  * @author Benedikt Mueller
     22  * @author Christian Grothoff
     23  */
     24 #include "platform.h"
     25 #include "taler/taler_util.h"
     26 #include <gnunet/gnunet_json_lib.h>
     27 #include <unistr.h>
     28 
     29 
     30 int
     31 TALER_strcmp_ct (const char *a,
     32                  const char *b)
     33 {
     34   size_t alen = strlen (a);
     35 
     36   if (strlen (b) != alen)
     37     return 1;
     38   return GNUNET_memcmp_ct_ (a,
     39                             b,
     40                             alen);
     41 }
     42 
     43 
     44 const char *
     45 TALER_b2s (const void *buf,
     46            size_t buf_size)
     47 {
     48   static TALER_THREAD_LOCAL char ret[9];
     49   struct GNUNET_HashCode hc;
     50   char *tmp;
     51 
     52   GNUNET_CRYPTO_hash (buf,
     53                       buf_size,
     54                       &hc);
     55   tmp = GNUNET_STRINGS_data_to_string_alloc (&hc,
     56                                              sizeof (hc));
     57   GNUNET_memcpy (ret,
     58                  tmp,
     59                  8);
     60   GNUNET_free (tmp);
     61   ret[8] = '\0';
     62   return ret;
     63 }
     64 
     65 
     66 void
     67 TALER_denom_fee_set_hton (struct TALER_DenomFeeSetNBOP *nbo,
     68                           const struct TALER_DenomFeeSet *fees)
     69 {
     70   TALER_amount_hton (&nbo->withdraw,
     71                      &fees->withdraw);
     72   TALER_amount_hton (&nbo->deposit,
     73                      &fees->deposit);
     74   TALER_amount_hton (&nbo->refresh,
     75                      &fees->refresh);
     76   TALER_amount_hton (&nbo->refund,
     77                      &fees->refund);
     78 }
     79 
     80 
     81 void
     82 TALER_denom_fee_set_ntoh (struct TALER_DenomFeeSet *fees,
     83                           const struct TALER_DenomFeeSetNBOP *nbo)
     84 {
     85   TALER_amount_ntoh (&fees->withdraw,
     86                      &nbo->withdraw);
     87   TALER_amount_ntoh (&fees->deposit,
     88                      &nbo->deposit);
     89   TALER_amount_ntoh (&fees->refresh,
     90                      &nbo->refresh);
     91   TALER_amount_ntoh (&fees->refund,
     92                      &nbo->refund);
     93 }
     94 
     95 
     96 void
     97 TALER_global_fee_set_hton (struct TALER_GlobalFeeSetNBOP *nbo,
     98                            const struct TALER_GlobalFeeSet *fees)
     99 {
    100   TALER_amount_hton (&nbo->history,
    101                      &fees->history);
    102   TALER_amount_hton (&nbo->account,
    103                      &fees->account);
    104   TALER_amount_hton (&nbo->purse,
    105                      &fees->purse);
    106 }
    107 
    108 
    109 void
    110 TALER_global_fee_set_ntoh (struct TALER_GlobalFeeSet *fees,
    111                            const struct TALER_GlobalFeeSetNBOP *nbo)
    112 {
    113   TALER_amount_ntoh (&fees->history,
    114                      &nbo->history);
    115   TALER_amount_ntoh (&fees->account,
    116                      &nbo->account);
    117   TALER_amount_ntoh (&fees->purse,
    118                      &nbo->purse);
    119 }
    120 
    121 
    122 void
    123 TALER_wire_fee_set_hton (struct TALER_WireFeeSetNBOP *nbo,
    124                          const struct TALER_WireFeeSet *fees)
    125 {
    126   TALER_amount_hton (&nbo->wire,
    127                      &fees->wire);
    128   TALER_amount_hton (&nbo->closing,
    129                      &fees->closing);
    130 }
    131 
    132 
    133 void
    134 TALER_wire_fee_set_ntoh (struct TALER_WireFeeSet *fees,
    135                          const struct TALER_WireFeeSetNBOP *nbo)
    136 {
    137   TALER_amount_ntoh (&fees->wire,
    138                      &nbo->wire);
    139   TALER_amount_ntoh (&fees->closing,
    140                      &nbo->closing);
    141 }
    142 
    143 
    144 int
    145 TALER_global_fee_set_cmp (const struct TALER_GlobalFeeSet *f1,
    146                           const struct TALER_GlobalFeeSet *f2)
    147 {
    148   int ret;
    149 
    150   ret = TALER_amount_cmp (&f1->history,
    151                           &f2->history);
    152   if (0 != ret)
    153     return ret;
    154   ret = TALER_amount_cmp (&f1->account,
    155                           &f2->account);
    156   if (0 != ret)
    157     return ret;
    158   ret = TALER_amount_cmp (&f1->purse,
    159                           &f2->purse);
    160   if (0 != ret)
    161     return ret;
    162   return 0;
    163 }
    164 
    165 
    166 int
    167 TALER_wire_fee_set_cmp (const struct TALER_WireFeeSet *f1,
    168                         const struct TALER_WireFeeSet *f2)
    169 {
    170   int ret;
    171 
    172   ret = TALER_amount_cmp (&f1->wire,
    173                           &f2->wire);
    174   if (0 != ret)
    175     return ret;
    176   ret = TALER_amount_cmp (&f1->closing,
    177                           &f2->closing);
    178   if (0 != ret)
    179     return ret;
    180   return 0;
    181 }
    182 
    183 
    184 enum GNUNET_GenericReturnValue
    185 TALER_denom_fee_check_currency (
    186   const char *currency,
    187   const struct TALER_DenomFeeSet *fees)
    188 {
    189   if (GNUNET_YES !=
    190       TALER_amount_is_currency (&fees->withdraw,
    191                                 currency))
    192   {
    193     GNUNET_break (0);
    194     return GNUNET_NO;
    195   }
    196   if (GNUNET_YES !=
    197       TALER_amount_is_currency (&fees->deposit,
    198                                 currency))
    199   {
    200     GNUNET_break (0);
    201     return GNUNET_NO;
    202   }
    203   if (GNUNET_YES !=
    204       TALER_amount_is_currency (&fees->refresh,
    205                                 currency))
    206   {
    207     GNUNET_break (0);
    208     return GNUNET_NO;
    209   }
    210   if (GNUNET_YES !=
    211       TALER_amount_is_currency (&fees->refund,
    212                                 currency))
    213   {
    214     GNUNET_break (0);
    215     return GNUNET_NO;
    216   }
    217   return GNUNET_OK;
    218 }
    219 
    220 
    221 /**
    222  * Dump character in the low range into @a buf
    223  * following RFC 8785.
    224  *
    225  * @param[in,out] buf buffer to modify
    226  * @param val value to dump
    227  */
    228 static void
    229 lowdump (struct GNUNET_Buffer *buf,
    230          unsigned char val)
    231 {
    232   char scratch[7];
    233 
    234   switch (val)
    235   {
    236   case 0x8:
    237     GNUNET_buffer_write (buf,
    238                          "\\b",
    239                          2);
    240     break;
    241   case 0x9:
    242     GNUNET_buffer_write (buf,
    243                          "\\t",
    244                          2);
    245     break;
    246   case 0xA:
    247     GNUNET_buffer_write (buf,
    248                          "\\n",
    249                          2);
    250     break;
    251   case 0xC:
    252     GNUNET_buffer_write (buf,
    253                          "\\f",
    254                          2);
    255     break;
    256   case 0xD:
    257     GNUNET_buffer_write (buf,
    258                          "\\r",
    259                          2);
    260     break;
    261   default:
    262     GNUNET_snprintf (scratch,
    263                      sizeof (scratch),
    264                      "\\u%04x",
    265                      (unsigned int) val);
    266     GNUNET_buffer_write (buf,
    267                          scratch,
    268                          6);
    269     break;
    270   }
    271 }
    272 
    273 
    274 size_t
    275 TALER_rfc8785encode (char **inp)
    276 {
    277   struct GNUNET_Buffer buf = { 0 };
    278   size_t left = strlen (*inp) + 1;
    279   size_t olen;
    280   char *in = *inp;
    281   const char *pos = in;
    282 
    283   GNUNET_buffer_prealloc (&buf,
    284                           left + 40);
    285   buf.warn_grow = 0; /* disable, + 40 is just a wild guess */
    286   while (1)
    287   {
    288     int mbl = u8_mblen ((unsigned char *) pos,
    289                         left);
    290     unsigned char val;
    291 
    292     if (0 == mbl)
    293       break;
    294     val = (unsigned char) *pos;
    295     if ( (1 == mbl) &&
    296          (val <= 0x1F) )
    297     {
    298       /* Should not happen, as input is produced by
    299        * JSON stringification */
    300       GNUNET_break (0);
    301       lowdump (&buf,
    302                val);
    303     }
    304     else if ( (1 == mbl) && ('\\' == *pos) )
    305     {
    306       switch (*(pos + 1))
    307       {
    308       case '\\':
    309         mbl = 2;
    310         GNUNET_buffer_write (&buf,
    311                              pos,
    312                              mbl);
    313         break;
    314       case 'u':
    315         {
    316           unsigned int num;
    317           uint32_t n32;
    318           unsigned char res[8];
    319           size_t rlen;
    320 
    321           GNUNET_assert ( (1 ==
    322                            sscanf (pos + 2,
    323                                    "%4x",
    324                                    &num)) ||
    325                           (1 ==
    326                            sscanf (pos + 2,
    327                                    "%4X",
    328                                    &num)) );
    329           mbl = 6;
    330           n32 = (uint32_t) num;
    331           rlen = sizeof (res);
    332           u32_to_u8 (&n32,
    333                      1,
    334                      res,
    335                      &rlen);
    336           if ( (1 == rlen) &&
    337                (res[0] <= 0x1F) )
    338           {
    339             lowdump (&buf,
    340                      res[0]);
    341           }
    342           else
    343           {
    344             GNUNET_buffer_write (&buf,
    345                                  (const char *) res,
    346                                  rlen);
    347           }
    348         }
    349         break;
    350       default:
    351         mbl = 2;
    352         GNUNET_buffer_write (&buf,
    353                              pos,
    354                              mbl);
    355         break;
    356       }
    357     }
    358     else
    359     {
    360       GNUNET_buffer_write (&buf,
    361                            pos,
    362                            mbl);
    363     }
    364     left -= mbl;
    365     pos += mbl;
    366   }
    367 
    368   /* 0-terminate buffer */
    369   GNUNET_buffer_write (&buf,
    370                        "",
    371                        1);
    372   GNUNET_free (in);
    373   *inp = GNUNET_buffer_reap (&buf,
    374                              &olen);
    375   return olen;
    376 }
    377 
    378 
    379 /**
    380  * Hash normalized @a j JSON object or array and
    381  * store the result in @a hc.
    382  *
    383  * @param j JSON to hash
    384  * @param[out] hc where to write the hash
    385  */
    386 void
    387 TALER_json_hash (const json_t *j,
    388                  struct GNUNET_HashCode *hc)
    389 {
    390   char *cstr;
    391   size_t clen;
    392 
    393   cstr = json_dumps (j,
    394                      JSON_COMPACT | JSON_SORT_KEYS);
    395   GNUNET_assert (NULL != cstr);
    396   clen = TALER_rfc8785encode (&cstr);
    397   GNUNET_CRYPTO_hash (cstr,
    398                       clen,
    399                       hc);
    400   GNUNET_free (cstr);
    401 }
    402 
    403 
    404 char **
    405 TALER_words_split (const char *command,
    406                    const char **extra_args)
    407 {
    408   unsigned int i = 0;
    409   unsigned int j = 0;
    410   unsigned int n = 0;
    411   char **res = NULL;
    412 
    413   /* Result is always NULL-terminated */
    414   GNUNET_array_append (res, n, NULL);
    415 
    416   /* Split command into words */
    417   while (1)
    418   {
    419     char *c;
    420 
    421     /* Skip initial whitespace before word */
    422     while (' ' == command[i])
    423       i++;
    424 
    425     /* Start of new word */
    426     j = i;
    427 
    428     /* Scan to end of word */
    429     while ( (0 != command[j]) && (' ' != command[j]) )
    430       j++;
    431 
    432     /* No new word found */
    433     if (i == j)
    434       break;
    435 
    436     /* Append word to result */
    437     c = GNUNET_malloc (j - i + 1);
    438     memcpy (c, &command[i], j - i);
    439     c[j - i] = 0;
    440     res[n - 1] = c;
    441     GNUNET_array_append (res, n, NULL);
    442 
    443     /* Continue at end of word */
    444     i = j;
    445   }
    446 
    447   /* Append extra args */
    448   if (NULL != extra_args)
    449   {
    450     for (const char **m = extra_args; *m; m++)
    451     {
    452       res[n - 1] = GNUNET_strdup (*m);
    453       GNUNET_array_append (res,
    454                            n,
    455                            NULL);
    456     }
    457   }
    458 
    459   return res;
    460 }
    461 
    462 
    463 void
    464 TALER_words_destroy (char **args)
    465 {
    466   if (NULL == args)
    467     return;
    468   for (char **m = args; *m; m++)
    469   {
    470     GNUNET_free (*m);
    471     *m = NULL;
    472   }
    473   GNUNET_free (args);
    474 }
    475 
    476 
    477 bool
    478 TALER_is_slug (const char *slug)
    479 {
    480   const unsigned char *p;
    481 
    482   if ('\0' == slug[0])
    483     return false;
    484 
    485   /* Reject special path components */
    486   if (0 == strcmp (slug, ".") ||
    487       0 == strcmp (slug, ".."))
    488     return false;
    489 
    490   for (p = (const unsigned char *) slug; '\0' != *p; p++)
    491   {
    492     unsigned char c = *p;
    493 
    494     if (isalnum (c))
    495       continue;
    496 
    497     switch (c)
    498     {
    499     case '-':
    500     case '_':
    501     case '.':
    502     case ':':
    503       /* Note: could also allow '~' in principle, is on safe list! */
    504       continue;
    505     default:
    506       return false;
    507     }
    508   }
    509 
    510   return true;
    511 }
    512 
    513 
    514 #ifdef __APPLE__
    515 char *
    516 strchrnul (const char *s,
    517            int c)
    518 {
    519   char *value;
    520   value = strchr (s,
    521                   c);
    522   if (NULL == value)
    523     value = &s[strlen (s)];
    524   return value;
    525 }
    526 
    527 
    528 #endif
    529 
    530 
    531 /* end of util.c */