merchant

Merchant backend to process payments, run by merchants
Log | Files | Refs | Submodules | README | LICENSE

util.c (6700B)


      1 /*
      2   This file is part of TALER
      3   (C) 2026 Taler Systems SA
      4 
      5   TALER is free software; you can redistribute it and/or modify it under the
      6   terms of the GNU Lesser 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 src/util/util.c
     18  * @brief small helpers
     19  * @author Christian Grothoff
     20  */
     21 #include "platform.h"
     22 #include <string.h>
     23 #include "taler/taler_merchant_util.h"
     24 #include <taler/taler_json_lib.h>
     25 #include <gnunet/gnunet_json_lib.h>
     26 
     27 
     28 bool
     29 TALER_MERCHANT_taxes_array_valid (const json_t *taxes)
     30 {
     31   json_t *tax;
     32   size_t idx;
     33 
     34   if (! json_is_array (taxes))
     35     return false;
     36   json_array_foreach (taxes, idx, tax)
     37   {
     38     struct TALER_Amount amount;
     39     const char *name;
     40     struct GNUNET_JSON_Specification spec[] = {
     41       GNUNET_JSON_spec_string ("name",
     42                                &name),
     43       TALER_JSON_spec_amount_any ("tax",
     44                                   &amount),
     45       GNUNET_JSON_spec_end ()
     46     };
     47     enum GNUNET_GenericReturnValue res;
     48     const char *ename;
     49     unsigned int eline;
     50 
     51     res = GNUNET_JSON_parse (tax,
     52                              spec,
     53                              &ename,
     54                              &eline);
     55     if (GNUNET_OK != res)
     56     {
     57       GNUNET_break_op (0);
     58       return false;
     59     }
     60   }
     61   return true;
     62 }
     63 
     64 
     65 bool
     66 TALER_MERCHANT_payment_method_valid (
     67   const char *method)
     68 {
     69   if ( (0 == strlen (method)) ||
     70        (0 == strcasecmp ("taler",
     71                          method)) )
     72   {
     73     GNUNET_break_op (0);
     74     return false;
     75   }
     76   for (const char *c = method; '\0' != *c; c++)
     77     if ( (! isalnum ((unsigned char) *c)) &&
     78          ('-' != *c) )
     79     {
     80       GNUNET_break_op (0);
     81       return false;
     82     }
     83   return true;
     84 }
     85 
     86 
     87 bool
     88 TALER_MERCHANT_amount_external_valid (
     89   const json_t *amount_external)
     90 {
     91   struct TALER_Amount first;
     92   bool have_first = false;
     93   json_t *entry;
     94   size_t idx;
     95 
     96   if (! json_is_array (amount_external))
     97     return false;
     98   json_array_foreach (amount_external, idx, entry)
     99   {
    100     const char *method;
    101     const char *id;
    102     struct TALER_Amount ext_amount;
    103     struct GNUNET_JSON_Specification spec[] = {
    104       GNUNET_JSON_spec_string ("method",
    105                                &method),
    106       GNUNET_JSON_spec_string ("id",
    107                                &id),
    108       TALER_JSON_spec_amount_any ("amount",
    109                                   &ext_amount),
    110       GNUNET_JSON_spec_end ()
    111     };
    112 
    113     if (GNUNET_OK !=
    114         GNUNET_JSON_parse (entry,
    115                            spec,
    116                            NULL,
    117                            NULL))
    118     {
    119       GNUNET_break_op (0);
    120       return false;
    121     }
    122     if (! TALER_MERCHANT_payment_method_valid (method))
    123       return false;
    124     if (0 == strlen (id))
    125     {
    126       GNUNET_break_op (0);
    127       return false;
    128     }
    129     if (! have_first)
    130     {
    131       first = ext_amount;
    132       have_first = true;
    133     }
    134     else if (GNUNET_OK !=
    135              TALER_amount_cmp_currency (&ext_amount,
    136                                         &first))
    137     {
    138       /* the entries have to agree on a currency among themselves */
    139       GNUNET_break_op (0);
    140       return false;
    141     }
    142     for (size_t j = 0; j < idx; j++)
    143     {
    144       const char *other_id
    145         = json_string_value (
    146             json_object_get (json_array_get (amount_external,
    147                                              j),
    148                              "id"));
    149 
    150       if ( (NULL != other_id) &&
    151            (0 == strcmp (id,
    152                          other_id)) )
    153       {
    154         GNUNET_break_op (0);
    155         return false;
    156       }
    157     }
    158     {
    159       const char *key;
    160       json_t *value;
    161 
    162       json_object_foreach (entry, key, value)
    163       {
    164         if ( (json_is_object (value)) ||
    165              (json_is_array (value)) ||
    166              (json_is_real (value)) )
    167         {
    168           GNUNET_break_op (0);
    169           return false;
    170         }
    171       }
    172     }
    173   }
    174   return true;
    175 }
    176 
    177 
    178 bool
    179 TALER_MERCHANT_amount_external_currency_valid (
    180   const json_t *amount_external,
    181   const struct TALER_Amount *amount)
    182 {
    183   struct TALER_Amount ext_amount;
    184   struct GNUNET_JSON_Specification spec[] = {
    185     TALER_JSON_spec_amount_any ("amount",
    186                                 &ext_amount),
    187     GNUNET_JSON_spec_end ()
    188   };
    189 
    190   if (0 == json_array_size (amount_external))
    191     return true; /* no external payment to agree with */
    192   if (GNUNET_OK !=
    193       GNUNET_JSON_parse (json_array_get (amount_external,
    194                                          0),
    195                          spec,
    196                          NULL,
    197                          NULL))
    198   {
    199     GNUNET_break_op (0);
    200     return false;
    201   }
    202   return (GNUNET_OK ==
    203           TALER_amount_cmp_currency (&ext_amount,
    204                                      amount));
    205 }
    206 
    207 
    208 bool
    209 TALER_MERCHANT_amount_external_total_valid (
    210   const json_t *amount_external,
    211   const struct TALER_Amount *amount)
    212 {
    213   struct TALER_Amount total = *amount;
    214   json_t *entry;
    215   size_t idx;
    216 
    217   json_array_foreach ((json_t *) amount_external, idx, entry)
    218   {
    219     struct TALER_Amount ext_amount;
    220     struct GNUNET_JSON_Specification spec[] = {
    221       TALER_JSON_spec_amount_any ("amount",
    222                                   &ext_amount),
    223       GNUNET_JSON_spec_end ()
    224     };
    225 
    226     if (GNUNET_OK !=
    227         GNUNET_JSON_parse (entry,
    228                            spec,
    229                            NULL,
    230                            NULL))
    231     {
    232       GNUNET_break_op (0);
    233       return false;
    234     }
    235     if (0 >
    236         TALER_amount_add (&total,
    237                           &total,
    238                           &ext_amount))
    239     {
    240       /* The order total would not be representable; refusing here
    241          keeps us from storing an order whose total can never be
    242          computed again. */
    243       GNUNET_break_op (0);
    244       return false;
    245     }
    246   }
    247   return true;
    248 }
    249 
    250 
    251 enum TALER_MERCHANT_ContractTokenKind
    252 TALER_MERCHANT_contract_token_kind_from_string (const char *str)
    253 {
    254   if (NULL == str)
    255   {
    256     GNUNET_break (0);
    257     return TALER_MERCHANT_CONTRACT_TOKEN_KIND_INVALID;
    258   }
    259   if (0 == strcmp ("subscription",
    260                    str))
    261     return TALER_MERCHANT_CONTRACT_TOKEN_KIND_SUBSCRIPTION;
    262   if (0 == strcmp ("discount",
    263                    str))
    264     return TALER_MERCHANT_CONTRACT_TOKEN_KIND_DISCOUNT;
    265   return TALER_MERCHANT_CONTRACT_TOKEN_KIND_INVALID;
    266 }