merchant

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

taler-merchant-httpd_fountains.c (5348B)


      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
      6   it under the terms of the GNU Affero General Public License as
      7   published by the Free Software Foundation; either version 3,
      8   or (at your option) any later version.
      9 
     10   TALER is distributed in the hope that it will be useful, but
     11   WITHOUT ANY WARRANTY; without even the implied warranty of
     12   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     13   GNU General Public License for more details.
     14 
     15   You should have received a copy of the GNU General Public
     16   License along with TALER; see the file COPYING.  If not,
     17   see <http://www.gnu.org/licenses/>
     18 */
     19 
     20 /**
     21  * @file src/backend/taler-merchant-httpd_fountains.c
     22  * @brief shared validation of private fountain grants
     23  */
     24 #include "platform.h"
     25 #include "taler-merchant-httpd_fountains.h"
     26 #include "taler-merchant-httpd_token-keys.h"
     27 #include <taler/taler_json_lib.h>
     28 
     29 
     30 /**
     31  * Parse one fountain grant from @a jgrant.
     32  *
     33  * @param connection connection to report errors on
     34  * @param jgrant JSON object to parse
     35  * @param[out] grant set to the parsed grant
     36  * @return #GNUNET_OK on success, #GNUNET_NO if an error was
     37  *         already reported, #GNUNET_SYSERR on hard failure
     38  */
     39 static enum GNUNET_GenericReturnValue
     40 parse_fountain_grant (struct MHD_Connection *connection,
     41                       const json_t *jgrant,
     42                       struct TALER_MERCHANTDB_FountainGrant *grant)
     43 {
     44   struct GNUNET_JSON_Specification spec[] = {
     45     GNUNET_JSON_spec_string ("token_family_slug",
     46                              &grant->token_family_slug),
     47     GNUNET_JSON_spec_uint64 ("tokens_per_period_limit",
     48                              &grant->tokens_per_period_limit),
     49     GNUNET_JSON_spec_uint64 ("tokens_per_period_stash",
     50                              &grant->tokens_per_period_stash),
     51     GNUNET_JSON_spec_uint32 ("key_window_size",
     52                              &grant->key_window_size),
     53     GNUNET_JSON_spec_end ()
     54   };
     55   enum GNUNET_GenericReturnValue res;
     56 
     57   res = TALER_MHD_parse_json_data (connection,
     58                                    jgrant,
     59                                    spec);
     60   if (GNUNET_OK != res)
     61     return res;
     62   /* spec_uint64 also accepts negative JSON integers by unsigned conversion.
     63      PostgreSQL INT8 cannot represent these or other values above INT64_MAX. */
     64   if ( (grant->tokens_per_period_limit > INT64_MAX) ||
     65        (grant->tokens_per_period_stash > INT64_MAX) )
     66     return (MHD_YES ==
     67             TALER_MHD_reply_with_error (connection,
     68                                         MHD_HTTP_BAD_REQUEST,
     69                                         TALER_EC_GENERIC_PARAMETER_MALFORMED,
     70                                         "quotas must be between 0 and INT64_MAX"))
     71       ? GNUNET_NO
     72       : GNUNET_SYSERR;
     73   if (grant->tokens_per_period_stash > grant->tokens_per_period_limit)
     74   {
     75     GNUNET_break_op (0);
     76     return (MHD_YES ==
     77             TALER_MHD_reply_with_error (connection,
     78                                         MHD_HTTP_BAD_REQUEST,
     79                                         TALER_EC_GENERIC_PARAMETER_MALFORMED,
     80                                         "tokens_per_period_stash exceeds tokens_per_period_limit"))
     81       ? GNUNET_NO
     82       : GNUNET_SYSERR;
     83   }
     84   if (grant->key_window_size > TMH_MAX_FOUNTAIN_KEY_WINDOW)
     85   {
     86     GNUNET_break_op (0);
     87     return (MHD_YES ==
     88             TALER_MHD_reply_with_error (connection,
     89                                         MHD_HTTP_BAD_REQUEST,
     90                                         TALER_EC_GENERIC_PARAMETER_MALFORMED,
     91                                         "key_window_size too large"))
     92       ? GNUNET_NO
     93       : GNUNET_SYSERR;
     94   }
     95   return GNUNET_OK;
     96 }
     97 
     98 
     99 enum GNUNET_GenericReturnValue
    100 TMH_fountain_grants_parse (
    101   struct MHD_Connection *connection,
    102   const json_t *jgrants,
    103   struct TALER_MERCHANTDB_FountainGrant *grants,
    104   unsigned int *grants_len)
    105 {
    106   size_t len = json_array_size (jgrants);
    107   size_t idx;
    108   json_t *jgrant;
    109 
    110   *grants_len = 0;
    111   GNUNET_assert (json_is_array (jgrants));
    112   if (len > TMH_MAX_FOUNTAIN_GRANTS)
    113   {
    114     GNUNET_break_op (0);
    115     return (MHD_YES ==
    116             TALER_MHD_reply_with_error (connection,
    117                                         MHD_HTTP_BAD_REQUEST,
    118                                         TALER_EC_GENERIC_PARAMETER_MALFORMED,
    119                                         "too many grants"))
    120       ? GNUNET_NO
    121       : GNUNET_SYSERR;
    122   }
    123   json_array_foreach ((json_t *) jgrants, idx, jgrant)
    124   {
    125     enum GNUNET_GenericReturnValue res;
    126 
    127     res = parse_fountain_grant (connection,
    128                                 jgrant,
    129                                 &grants[idx]);
    130     if (GNUNET_OK != res)
    131       return res;
    132     for (size_t j = 0; j < idx; j++)
    133     {
    134       if (0 == strcmp (grants[j].token_family_slug,
    135                        grants[idx].token_family_slug))
    136       {
    137         GNUNET_break_op (0);
    138         return (MHD_YES ==
    139                 TALER_MHD_reply_with_error (connection,
    140                                             MHD_HTTP_BAD_REQUEST,
    141                                             TALER_EC_GENERIC_PARAMETER_MALFORMED,
    142                                             "duplicate token_family_slug in grants"))
    143           ? GNUNET_NO
    144           : GNUNET_SYSERR;
    145       }
    146     }
    147   }
    148   *grants_len = (unsigned int) len;
    149   return GNUNET_OK;
    150 }