paivana

HTTP paywall reverse proxy
Log | Files | Refs | Submodules | README | LICENSE

commit f81de57d9b83cf5705672b4dae247ce3eb44d183
parent 9048cd9bfb20a60910b4f8a2bde80dda51a42a98
Author: Christian Grothoff <christian@grothoff.org>
Date:   Thu,  6 Aug 2026 16:45:22 +0200

split curl context between reverse proxy and merchant to avoid leaking merchant authorization secret to target host

Diffstat:
Msrc/backend/paivana-httpd.c | 56++++++++++++++++++++++++++++++++++++++++++--------------
Msrc/backend/paivana-httpd.h | 16++++++++++++++--
Msrc/backend/paivana-httpd_pay.c | 2+-
Msrc/backend/paivana-httpd_reverse.c | 2+-
Msrc/backend/paivana-httpd_templates.c | 4++--
5 files changed, 60 insertions(+), 20 deletions(-)

diff --git a/src/backend/paivana-httpd.c b/src/backend/paivana-httpd.c @@ -51,7 +51,9 @@ char *PH_merchant_base_url; char *PH_base_url; -struct GNUNET_CURL_Context *PH_ctx; +struct GNUNET_CURL_Context *PH_merchant_ctx; + +struct GNUNET_CURL_Context *PH_proxy_ctx; int PH_no_check; @@ -80,9 +82,16 @@ const struct GNUNET_CONFIGURATION_Handle *PH_cfg; /** - * Closure for #GNUNET_CURL_gnunet_scheduler_reschedule(). + * Closure for #GNUNET_CURL_gnunet_scheduler_reschedule() of + * #PH_merchant_ctx. + */ +static struct GNUNET_CURL_RescheduleContext *merchant_ctx_rc; + +/** + * Closure for #GNUNET_CURL_gnunet_scheduler_reschedule() of + * #PH_proxy_ctx. */ -static struct GNUNET_CURL_RescheduleContext *ctx_rc; +static struct GNUNET_CURL_RescheduleContext *proxy_ctx_rc; /* *************** General / main code *************** */ @@ -193,15 +202,25 @@ do_shutdown (void *cls) regfree (&PH_whitelist_ex); PH_have_whitelist_ex = false; } - if (NULL != PH_ctx) + if (NULL != PH_merchant_ctx) + { + GNUNET_CURL_fini (PH_merchant_ctx); + PH_merchant_ctx = NULL; + } + if (NULL != merchant_ctx_rc) + { + GNUNET_CURL_gnunet_rc_destroy (merchant_ctx_rc); + merchant_ctx_rc = NULL; + } + if (NULL != PH_proxy_ctx) { - GNUNET_CURL_fini (PH_ctx); - PH_ctx = NULL; + GNUNET_CURL_fini (PH_proxy_ctx); + PH_proxy_ctx = NULL; } - if (NULL != ctx_rc) + if (NULL != proxy_ctx_rc) { - GNUNET_CURL_gnunet_rc_destroy (ctx_rc); - ctx_rc = NULL; + GNUNET_CURL_gnunet_rc_destroy (proxy_ctx_rc); + proxy_ctx_rc = NULL; } } @@ -494,9 +513,10 @@ run (void *cls, &paivana_secret); GNUNET_free (secret); } - PH_ctx = GNUNET_CURL_init (&GNUNET_CURL_gnunet_scheduler_reschedule, - &ctx_rc); - GNUNET_assert (NULL != PH_ctx); + PH_proxy_ctx = GNUNET_CURL_init (&GNUNET_CURL_gnunet_scheduler_reschedule, + &proxy_ctx_rc); + GNUNET_assert (NULL != PH_proxy_ctx); + proxy_ctx_rc = GNUNET_CURL_gnunet_rc_create (PH_proxy_ctx); if (! PH_no_check) { char *merchant_access_token; @@ -516,17 +536,25 @@ run (void *cls, GNUNET_SCHEDULER_shutdown (); return; } + /* A second context, because the credential below is appended to + *every* request the context makes: on a shared context we would + hand our merchant bearer token to the origin server (and to + whoever it redirects to) on each forwarded request. */ + PH_merchant_ctx + = GNUNET_CURL_init (&GNUNET_CURL_gnunet_scheduler_reschedule, + &merchant_ctx_rc); + GNUNET_assert (NULL != PH_merchant_ctx); + merchant_ctx_rc = GNUNET_CURL_gnunet_rc_create (PH_merchant_ctx); GNUNET_asprintf (&auth_header, "%s: Bearer %s", MHD_HTTP_HEADER_AUTHORIZATION, merchant_access_token); GNUNET_free (merchant_access_token); GNUNET_assert (GNUNET_OK == - GNUNET_CURL_append_header (PH_ctx, + GNUNET_CURL_append_header (PH_merchant_ctx, auth_header)); GNUNET_free (auth_header); } - ctx_rc = GNUNET_CURL_gnunet_rc_create (PH_ctx); /* Once templates are done loading, this will start the daemon as well. In -n (no-payment) mode we skip the merchant round-trip entirely. */ diff --git a/src/backend/paivana-httpd.h b/src/backend/paivana-httpd.h @@ -90,9 +90,21 @@ extern char *PH_merchant_base_url; extern char *PH_base_url; /** - * Curl context for making HTTP requests. + * Curl context for talking to the merchant backend. Carries the + * `Authorization: Bearer $MERCHANT_ACCESS_TOKEN` header on every + * request, so it must never be used for anything but the backend. + * NULL in `-n` (no payment) mode, where there is no backend. */ -extern struct GNUNET_CURL_Context *PH_ctx; +extern struct GNUNET_CURL_Context *PH_merchant_ctx; + +/** + * Curl context for forwarding client requests to the origin server. + * Deliberately separate from #PH_merchant_ctx: headers appended to a + * context apply to every request made through it, and our credentials + * for the merchant backend have no business being sent to the site we + * proxy for. + */ +extern struct GNUNET_CURL_Context *PH_proxy_ctx; /** * Pre-compiled regular expression for sites that are whitelisted diff --git a/src/backend/paivana-httpd_pay.c b/src/backend/paivana-httpd_pay.c @@ -479,7 +479,7 @@ PAIVANA_HTTPD_payment_handle (struct PayRequest *ph, } } GNUNET_assert (NULL == ph->co); - ph->co = TALER_MERCHANT_get_private_order_create (PH_ctx, + ph->co = TALER_MERCHANT_get_private_order_create (PH_merchant_ctx, PH_merchant_base_url, ph->order_id); if (NULL == ph->co) diff --git a/src/backend/paivana-httpd_reverse.c b/src/backend/paivana-httpd_reverse.c @@ -1930,7 +1930,7 @@ start_curl_request (struct HttpRequest *hr, append_forwarded_headers (hr, con, ver); - hr->job = GNUNET_CURL_job_add_raw (PH_ctx, + hr->job = GNUNET_CURL_job_add_raw (PH_proxy_ctx, hr->curl, hr->headers, &curl_download_cb, diff --git a/src/backend/paivana-httpd_templates.c b/src/backend/paivana-httpd_templates.c @@ -618,7 +618,7 @@ check_templates ( t = GNUNET_new (struct Template); t->template_id = GNUNET_strdup (te->template_id); t->max_pickup_delay = GNUNET_TIME_UNIT_FOREVER_REL; - t->gt = TALER_MERCHANT_get_private_template_create (PH_ctx, + t->gt = TALER_MERCHANT_get_private_template_create (PH_merchant_ctx, PH_merchant_base_url, t->template_id); GNUNET_CONTAINER_DLL_insert (t_head, @@ -636,7 +636,7 @@ check_templates ( void PAIVANA_HTTPD_load_templates () { - gpt = TALER_MERCHANT_get_private_templates_create (PH_ctx, + gpt = TALER_MERCHANT_get_private_templates_create (PH_merchant_ctx, PH_merchant_base_url); GNUNET_assert (NULL != gpt); GNUNET_assert (