taler-merchant-httpd_post-private-fountains.c (6272B)
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_post-private-fountains.c 22 * @brief implementing POST /private/fountains request handling 23 * @author Bohdan Potuzhnyi 24 */ 25 #include "platform.h" 26 #include "taler-merchant-httpd_post-private-fountains.h" 27 #include "taler-merchant-httpd_helper.h" 28 #include "taler-merchant-httpd_fountains.h" 29 #include <taler/taler_json_lib.h> 30 #include "merchant-database/do_insert_fountain.h" 31 32 33 /** 34 * How often do we retry on a (astronomically unlikely) random 35 * collision of the fountain identifier or secret? 36 */ 37 #define MAX_RETRIES 3 38 39 40 enum MHD_Result 41 TMH_private_post_fountains (const struct TMH_RequestHandler *rh, 42 struct MHD_Connection *connection, 43 struct TMH_HandlerContext *hc) 44 { 45 struct TMH_MerchantInstance *mi = hc->instance; 46 const char *description; 47 struct GNUNET_TIME_Relative poll_freq; 48 const json_t *jgrants; 49 struct GNUNET_JSON_Specification spec[] = { 50 GNUNET_JSON_spec_string ("description", 51 &description), 52 GNUNET_JSON_spec_relative_time ("poll_freq", 53 &poll_freq), 54 GNUNET_JSON_spec_array_const ("grants", 55 &jgrants), 56 GNUNET_JSON_spec_end () 57 }; 58 unsigned int grants_len; 59 60 GNUNET_assert (NULL != mi); 61 { 62 enum GNUNET_GenericReturnValue res; 63 64 res = TALER_MHD_parse_json_data (connection, 65 hc->request_body, 66 spec); 67 if (GNUNET_OK != res) 68 { 69 GNUNET_break_op (0); 70 return (GNUNET_NO == res) 71 ? MHD_YES 72 : MHD_NO; 73 } 74 } 75 { 76 struct TALER_MERCHANTDB_FountainGrant grants[TMH_MAX_FOUNTAIN_GRANTS]; 77 enum GNUNET_GenericReturnValue res; 78 79 res = TMH_fountain_grants_parse (connection, 80 jgrants, 81 grants, 82 &grants_len); 83 if (GNUNET_OK != res) 84 { 85 GNUNET_JSON_parse_free (spec); 86 return (GNUNET_NO == res) 87 ? MHD_YES 88 : MHD_NO; 89 } 90 91 for (unsigned int attempt = 0; attempt < MAX_RETRIES; attempt++) 92 { 93 char secret[32]; 94 struct GNUNET_HashCode h_secret; 95 char *fountain_id; 96 char *fountain_secret; 97 char *unknown_slug; 98 bool conflict; 99 enum GNUNET_DB_QueryStatus qs; 100 101 GNUNET_CRYPTO_random_block (secret, 102 sizeof (secret)); 103 GNUNET_CRYPTO_hash (secret, 104 sizeof (secret), 105 &h_secret); 106 { 107 char rnd[16]; 108 109 GNUNET_CRYPTO_random_block (rnd, 110 sizeof (rnd)); 111 fountain_id = GNUNET_STRINGS_data_to_string_alloc (rnd, 112 sizeof (rnd)); 113 } 114 qs = TALER_MERCHANTDB_do_insert_fountain (TMH_db, 115 mi->settings.id, 116 fountain_id, 117 &h_secret, 118 description, 119 poll_freq, 120 grants_len, 121 grants, 122 &unknown_slug, 123 &conflict); 124 if (qs < 0) 125 { 126 GNUNET_break (0); 127 GNUNET_free (fountain_id); 128 GNUNET_JSON_parse_free (spec); 129 return TALER_MHD_reply_with_error (connection, 130 MHD_HTTP_INTERNAL_SERVER_ERROR, 131 TALER_EC_GENERIC_DB_STORE_FAILED, 132 "do_insert_fountain"); 133 } 134 if (NULL != unknown_slug) 135 { 136 enum MHD_Result mret; 137 138 GNUNET_free (fountain_id); 139 GNUNET_JSON_parse_free (spec); 140 mret = TALER_MHD_reply_with_error ( 141 connection, 142 MHD_HTTP_NOT_FOUND, 143 TALER_EC_MERCHANT_PRIVATE_POST_ORDERS_TOKEN_FAMILY_SLUG_UNKNOWN, 144 unknown_slug); 145 GNUNET_free (unknown_slug); 146 return mret; 147 } 148 if (conflict) 149 { 150 /* Random collision of fountain_id or secret hash; try again 151 with fresh randomness. */ 152 GNUNET_free (fountain_id); 153 continue; 154 } 155 fountain_secret = GNUNET_STRINGS_data_to_string_alloc (secret, 156 sizeof (secret)); 157 memset (secret, 158 0, 159 sizeof (secret)); 160 GNUNET_JSON_parse_free (spec); 161 { 162 enum MHD_Result mret; 163 164 mret = TALER_MHD_REPLY_JSON_PACK ( 165 connection, 166 MHD_HTTP_OK, 167 GNUNET_JSON_pack_string ("fountain_id", 168 fountain_id), 169 GNUNET_JSON_pack_string ("fountain_secret", 170 fountain_secret)); 171 GNUNET_free (fountain_id); 172 GNUNET_free (fountain_secret); 173 return mret; 174 } 175 } 176 } 177 GNUNET_break (0); 178 GNUNET_JSON_parse_free (spec); 179 return TALER_MHD_reply_with_error (connection, 180 MHD_HTTP_INTERNAL_SERVER_ERROR, 181 TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE, 182 "repeated fountain id collision"); 183 } 184 185 186 /* end of taler-merchant-httpd_post-private-fountains.c */