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 }