paivana-httpd.c (9035B)
1 /* 2 This file is part of GNU Taler 3 Copyright (C) 2012-2014 GNUnet e.V. 4 Copyright (C) 2018, 2025, 2026 Taler Systems SA 5 6 GNU Taler is free software; you can redistribute it and/or 7 modify it under the terms of the GNU General Public License 8 as published by the Free Software Foundation; either version 9 3, or (at your option) any later version. 10 11 GNU Taler is distributed in the hope that it will be useful, but 12 WITHOUT ANY WARRANTY; without even the implied warranty of 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 GNU General Public License for more details. 15 16 You should have received a copy of the GNU General Public 17 License along with GNU Taler; see the file COPYING. If not, 18 write to the Free Software Foundation, Inc., 51 Franklin 19 Street, Fifth Floor, Boston, MA 02110-1301, USA. 20 */ 21 22 /** 23 * @author Martin Schanzenbach 24 * @author Christian Grothoff 25 * @author Marcello Stanisci 26 * @file src/backend/paivana-httpd.c 27 * @brief HTTP proxy that acts as a GNU Taler paywall 28 */ 29 #include "platform.h" 30 #include <curl/curl.h> 31 #include <gnunet/gnunet_util_lib.h> 32 #include <gnunet/gnunet_curl_lib.h> 33 #include <taler/taler_mhd_lib.h> 34 #include <taler/taler_templating_lib.h> 35 #include "paivana-httpd.h" 36 #include "paivana-httpd_cookie.h" 37 #include "paivana-httpd_daemon.h" 38 #include "paivana-httpd_helper.h" 39 #include "paivana-httpd_pay.h" 40 #include "paivana-httpd_reverse.h" 41 #include "paivana-httpd_templates.h" 42 #include "paivana_pd.h" 43 44 45 char *PH_target_server_base_url; 46 47 char *PH_merchant_base_url; 48 49 char *PH_base_url; 50 51 struct GNUNET_CURL_Context *PH_ctx; 52 53 int PH_no_check; 54 55 unsigned long long PH_request_buffer_max = 1024 * 1024; 56 57 int PH_global_ret; 58 59 /** 60 * Our configuration. 61 */ 62 const struct GNUNET_CONFIGURATION_Handle *PH_cfg; 63 64 65 /** 66 * Closure for #GNUNET_CURL_gnunet_scheduler_reschedule(). 67 */ 68 static struct GNUNET_CURL_RescheduleContext *ctx_rc; 69 70 71 /* *************** General / main code *************** */ 72 73 74 /** 75 * Task run on shutdown 76 * 77 * @param cls closure 78 */ 79 static void 80 do_shutdown (void *cls) 81 { 82 (void) cls; 83 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 84 "Shutting down...\n"); 85 TALER_MHD_daemons_halt (); 86 PAIVANA_HTTPD_payment_shutdown (); 87 PAIVANA_HTTPD_reverse_shutdown (); 88 TALER_MHD_daemons_destroy (); 89 PAIVANA_HTTPD_unload_templates (); 90 TALER_TEMPLATING_done (); 91 GNUNET_free (PH_target_server_base_url); 92 GNUNET_free (PH_merchant_base_url); 93 GNUNET_free (PH_base_url); 94 if (NULL != PH_ctx) 95 { 96 GNUNET_CURL_fini (PH_ctx); 97 PH_ctx = NULL; 98 } 99 if (NULL != ctx_rc) 100 { 101 GNUNET_CURL_gnunet_rc_destroy (ctx_rc); 102 ctx_rc = NULL; 103 } 104 } 105 106 107 /** 108 * Main function that will be run. Main tasks are (1) init. the 109 * curl infrastructure (curl_global_init() / curl_multi_init()), 110 * then fetch the HTTP port where its Web service should listen at, 111 * and finally start MHD on that port. 112 * 113 * @param cls closure 114 * @param args remaining command-line arguments 115 * @param cfgfile name of the configuration file used (for saving, can be NULL!) 116 * @param c configuration 117 */ 118 static void 119 run (void *cls, 120 char *const *args, 121 const char *cfgfile, 122 const struct GNUNET_CONFIGURATION_Handle *c) 123 { 124 char *secret; 125 126 (void) cls; 127 (void) args; 128 (void) cfgfile; 129 PH_cfg = c; 130 131 if (! PH_no_check) 132 { 133 if (GNUNET_OK != 134 TALER_TEMPLATING_init (PAIVANA_project_data ())) 135 { 136 GNUNET_break (0); 137 GNUNET_SCHEDULER_shutdown (); 138 return; 139 } 140 } 141 if (! PAIVANA_HTTPD_reverse_init ()) 142 { 143 GNUNET_break (0); 144 GNUNET_SCHEDULER_shutdown (); 145 return; 146 } 147 148 /* No need to check return value. If given, we take, 149 * otherwise it stays zero. */ 150 if (GNUNET_OK != 151 GNUNET_CONFIGURATION_get_value_string ( 152 c, 153 "paivana", 154 "DESTINATION_BASE_URL", 155 &PH_target_server_base_url)) 156 { 157 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, 158 "paivana", 159 "DESTINATION_BASE_URL"); 160 GNUNET_SCHEDULER_shutdown (); 161 return; 162 } 163 if (! TALER_is_web_url (PH_target_server_base_url)) 164 { 165 GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR, 166 "paivana", 167 "DESTINATION_BASE_URL", 168 "not a web url"); 169 GNUNET_SCHEDULER_shutdown (); 170 return; 171 } 172 { 173 size_t tlen = strlen (PH_target_server_base_url); 174 175 if ( (tlen > 0) && 176 ('/' == PH_target_server_base_url[tlen - 1]) ) 177 PH_target_server_base_url[tlen - 1] = '\0'; 178 } 179 if (! PH_no_check) 180 { 181 if (GNUNET_OK != 182 GNUNET_CONFIGURATION_get_value_string ( 183 c, 184 "paivana", 185 "MERCHANT_BACKEND_URL", 186 &PH_merchant_base_url)) 187 { 188 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, 189 "paivana", 190 "MERCHANT_BACKEND_URL"); 191 GNUNET_SCHEDULER_shutdown (); 192 return; 193 } 194 if (! TALER_is_web_url (PH_merchant_base_url)) 195 { 196 GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR, 197 "paivana", 198 "MERCHANT_BACKEND_URL", 199 "not a web url"); 200 GNUNET_SCHEDULER_shutdown (); 201 return; 202 } 203 } 204 if (GNUNET_OK != 205 GNUNET_CONFIGURATION_get_value_string ( 206 c, 207 "paivana", 208 "BASE_URL", 209 &PH_base_url)) 210 { 211 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_INFO, 212 "paivana", 213 "BASE_URL"); 214 } 215 if (NULL != PH_base_url) 216 { 217 if (! TALER_is_web_url (PH_base_url)) 218 { 219 GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR, 220 "paivana", 221 "BASE_URL", 222 "not a web url"); 223 GNUNET_SCHEDULER_shutdown (); 224 return; 225 } 226 if ('/' == PH_base_url[strlen (PH_base_url) - 1]) 227 PH_base_url[strlen (PH_base_url) - 1] = '\0'; 228 } 229 230 if (GNUNET_OK != 231 GNUNET_CONFIGURATION_get_value_string ( 232 c, 233 "paivana", 234 "SECRET", 235 &secret)) 236 { 237 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_WARNING, 238 "paivana", 239 "SECRET"); 240 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE, 241 &paivana_secret, 242 sizeof (paivana_secret)); 243 } 244 else 245 { 246 GNUNET_CRYPTO_hash (secret, 247 strlen (secret), 248 &paivana_secret); 249 GNUNET_free (secret); 250 } 251 GNUNET_SCHEDULER_add_shutdown (&do_shutdown, 252 NULL); 253 PH_ctx = GNUNET_CURL_init (&GNUNET_CURL_gnunet_scheduler_reschedule, 254 &ctx_rc); 255 if (! PH_no_check) 256 { 257 char *merchant_access_token; 258 char *auth_header; 259 260 if (GNUNET_OK != 261 GNUNET_CONFIGURATION_get_value_string ( 262 c, 263 "paivana", 264 "MERCHANT_ACCESS_TOKEN", 265 &merchant_access_token)) 266 { 267 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, 268 "paivana", 269 "MERCHANT_ACCESS_TOKEN"); 270 GNUNET_SCHEDULER_shutdown (); 271 return; 272 } 273 GNUNET_asprintf (&auth_header, 274 "%s: Bearer %s", 275 MHD_HTTP_HEADER_AUTHORIZATION, 276 merchant_access_token); 277 GNUNET_free (merchant_access_token); 278 GNUNET_assert (GNUNET_OK == 279 GNUNET_CURL_append_header (PH_ctx, 280 auth_header)); 281 GNUNET_free (auth_header); 282 } 283 ctx_rc = GNUNET_CURL_gnunet_rc_create (PH_ctx); 284 /* Once templates are done loading, this will 285 start the daemon as well. In -n (no-payment) mode we skip 286 the merchant round-trip entirely. */ 287 if (PH_no_check) 288 { 289 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 290 "Paywall disabled (-n), skipping template load\n"); 291 PAIVANA_HTTPD_serve_requests (); 292 return; 293 } 294 PAIVANA_HTTPD_load_templates (); 295 } 296 297 298 /** 299 * Main function. 300 */ 301 int 302 main (int argc, 303 char *const *argv) 304 { 305 struct GNUNET_GETOPT_CommandLineOption options[] = { 306 GNUNET_GETOPT_option_flag ( 307 'n', 308 "no-payment", 309 gettext_noop ( 310 "disables payment, useful for testing reverse-proxy only"), 311 &PH_no_check), 312 GNUNET_GETOPT_option_ulong ( 313 'u', 314 "max-upload", 315 "BYTES", 316 gettext_noop ( 317 "maximum request body size to buffer before forwarding (default: 1048576)"), 318 &PH_request_buffer_max), 319 GNUNET_GETOPT_OPTION_END 320 }; 321 enum GNUNET_GenericReturnValue ret; 322 323 ret = GNUNET_PROGRAM_run ( 324 PAIVANA_project_data (), 325 argc, 326 argv, 327 "paivana-httpd", 328 "reverse proxy requesting Taler payment", 329 options, 330 &run, NULL); 331 if (GNUNET_SYSERR == ret) 332 return EXIT_INVALIDARGUMENT; 333 if (GNUNET_NO == ret) 334 return EXIT_SUCCESS; 335 return PH_global_ret; 336 } 337 338 339 /* end of paivana-httpd.c */