commit 93b195323d4bb3ce342fc716b654ef3f3cffeb9e
parent 35a9e030e0aabfc362918dc6c022e87bb3c1cb5d
Author: Christian Grothoff <grothoff@gnunet.org>
Date: Tue, 5 May 2026 13:34:10 +0200
add whitelisting, global cookie setting, but generally restrict payment per path
Diffstat:
6 files changed, 118 insertions(+), 6 deletions(-)
diff --git a/src/backend/paivana-httpd.c b/src/backend/paivana-httpd.c
@@ -61,6 +61,12 @@ unsigned long long PH_request_buffer_max = 1024 * 1024;
int PH_global_ret;
+int PH_global_cookie;
+
+regex_t PH_whitelist_ex;
+
+bool PH_have_whitelist_ex;
+
/**
* Our configuration.
*/
@@ -232,6 +238,33 @@ run (void *cls,
GNUNET_free (merchant_unix_path);
}
}
+ {
+ char *whitelist;
+
+ if (GNUNET_OK ==
+ GNUNET_CONFIGURATION_get_value_string (
+ c,
+ "paivana",
+ "WHITELIST",
+ &whitelist))
+ {
+ if (0 != regcomp (&PH_whitelist_ex,
+ whitelist,
+ REG_NOSUB | REG_EXTENDED))
+ {
+ GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
+ "paivana",
+ "WHITELIST",
+ "Invalid regular expression");
+ GNUNET_free (whitelist);
+ GNUNET_SCHEDULER_shutdown ();
+ return;
+ }
+ PH_have_whitelist_ex = true;
+ GNUNET_free (whitelist);
+ }
+ }
+
if (GNUNET_OK !=
GNUNET_CONFIGURATION_get_value_string (
c,
@@ -341,6 +374,12 @@ main (int argc,
"trust X-Forwarded-For for the client address (only safe behind a trusted reverse proxy)"),
&PH_respect_forwarded_headers),
GNUNET_GETOPT_option_flag (
+ 'g',
+ "global-payment",
+ gettext_noop (
+ "disables per-page payment, useful if a single payment should grant access to the entire site"),
+ &PH_global_cookie),
+ GNUNET_GETOPT_option_flag (
'n',
"no-payment",
gettext_noop (
diff --git a/src/backend/paivana-httpd.h b/src/backend/paivana-httpd.h
@@ -27,6 +27,9 @@
#ifndef PAIVANA_HTTPD_H
#define PAIVANA_HTTPD_H
+#include <regex.h>
+#include <stdbool.h>
+
#define PAIVANA_LOG_INFO(...) \
GNUNET_log (GNUNET_ERROR_TYPE_INFO, __VA_ARGS__)
#define PAIVANA_LOG_DEBUG(...) \
@@ -66,6 +69,23 @@ extern char *PH_base_url;
extern struct GNUNET_CURL_Context *PH_ctx;
/**
+ * Pre-compiled regular expression for sites that are whitelisted
+ * and never paywalled.
+ */
+extern regex_t PH_whitelist_ex;
+
+/**
+ * True if whitelist_ex was set.
+ */
+extern bool PH_have_whitelist_ex;
+
+/**
+ * Set to true if the cookie applies globally to all sites
+ * and not per-page.
+ */
+extern int PH_global_cookie;
+
+/**
* Disable paywall check.
*/
extern int PH_no_check;
diff --git a/src/backend/paivana-httpd_cookie.c b/src/backend/paivana-httpd_cookie.c
@@ -29,6 +29,7 @@
#include <gnunet/gnunet_util_lib.h>
#include <taler/taler_mhd_lib.h>
#include "paivana-httpd_cookie.h"
+#include "paivana-httpd.h"
/**
@@ -63,6 +64,8 @@ compute_cookie_hash (struct GNUNET_TIME_Timestamp cur_time,
TALER_b2s (ca,
ca_len));
e = GNUNET_TIME_absolute_hton (cur_time.abs_time);
+ if (PH_global_cookie)
+ website = "";
GNUNET_assert (GNUNET_YES ==
GNUNET_CRYPTO_hkdf_gnunet (
c, /* result */
@@ -71,6 +74,8 @@ compute_cookie_hash (struct GNUNET_TIME_Timestamp cur_time,
sizeof (e),
&paivana_secret, /* source key material */
sizeof (paivana_secret),
+ GNUNET_CRYPTO_kdf_arg (website,
+ strlen (website) + 1),
GNUNET_CRYPTO_kdf_arg (ca,
ca_len)));
}
@@ -148,7 +153,21 @@ PAIVANA_HTTPD_compute_cookie (struct GNUNET_TIME_Timestamp cur_time,
char *end;
char cstr[128];
char *res;
-
+ const char *url = "/";
+ bool use_https = strncasecmp (website,
+ "https://",
+ strlen ("https://"));
+ struct GNUNET_TIME_Relative duration
+ = GNUNET_TIME_absolute_get_remaining (cur_time.abs_time);
+
+ if (! PH_global_cookie)
+ {
+ const char *dslash = strstr (website,
+ "//");
+ if (NULL != dslash)
+ url = strchr (dslash + 2,
+ '/');
+ }
compute_cookie_hash (cur_time,
website,
ca_len,
@@ -161,9 +180,14 @@ PAIVANA_HTTPD_compute_cookie (struct GNUNET_TIME_Timestamp cur_time,
*end = '\0';
GNUNET_asprintf (
&res,
- "Paivana-Cookie=%llu-%s; Secure; Path=/;",
+ "Paivana-Cookie=%llu-%s; %sPath=%s; Max-Age=%llu;",
(unsigned long long) (cur_time.abs_time.abs_value_us / 1000LLU / 1000LLU),
- cstr);
+ cstr,
+ use_https
+ ? "Secure; "
+ : "",
+ url,
+ (unsigned long long) (duration.rel_value_us / 1000 / 1000));
return res;
}
diff --git a/src/backend/paivana-httpd_daemon.c b/src/backend/paivana-httpd_daemon.c
@@ -141,6 +141,14 @@ create_response (void *cls,
upload_data_size);
}
+ if (PH_have_whitelist_ex && (! rc->do_forward))
+ {
+ rc->do_forward = (0 ==
+ regcomp (&PH_whitelist_ex,
+ url,
+ REG_NOSUB | REG_EXTENDED));
+ }
+
if (rc->do_forward)
goto do_forward;
diff --git a/src/backend/paivana-httpd_pay.c b/src/backend/paivana-httpd_pay.c
@@ -93,7 +93,7 @@ struct PayRequest
struct PAIVANA_Nonce nonce;
/**
- *
+ * Expiration time of the cookie.
*/
struct GNUNET_TIME_Timestamp cur_time;
@@ -247,7 +247,7 @@ order_status_cb (struct PayRequest *ph,
&ca,
&ca_len));
cookie = PAIVANA_HTTPD_compute_cookie (ph->cur_time,
- ph->website,
+ ph->website,
ca_len,
ca);
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
diff --git a/src/backend/paivana-httpd_pay.h b/src/backend/paivana-httpd_pay.h
@@ -36,20 +36,41 @@
*/
struct PayRequest;
+/**
+ * The server is shutting down, clean up suspended requests.
+ */
void
PAIVANA_HTTPD_payment_shutdown (void);
+/**
+ * Create context for handling a request to check a payment.
+ *
+ * @param connection the request context
+ */
struct PayRequest *
PAIVANA_HTTPD_payment_create (struct MHD_Connection *connection);
+/**
+ * Make progress on handling the upload of the client.
+ *
+ * @param[in,out] pr payment request handle
+ * @param upload_data data uploaded by the client
+ * @param[in,out] upload_data_size number of bytes uploaded,
+ * set to the number of bytes of upload that were not handled
+ * @return MHD status code to return
+ */
enum MHD_Result
PAIVANA_HTTPD_payment_handle (struct PayRequest *pr,
const char *upload_data,
size_t *upload_data_size);
-
+/**
+ * Clean up payment request handle.
+ *
+ * @param[in] ph handle to clean up
+ */
void
PAIVANA_HTTPD_payment_destroy (struct PayRequest *ph);