README (6464B)
1 Paivana 2 ======= 3 4 Paivana is an HTTP reverse proxy that gates access to a target website 5 behind a GNU Taler payment. Unpaid visitors receive a paywall page 6 where they can pay using a GNU Taler wallet; once payment is confirmed 7 the request is forwarded transparently to the configured upstream 8 server. 9 10 The sole binary is `paivana-httpd`. 11 12 13 How it works 14 ------------ 15 16 0. `paivana-httpd` learns prices from the Paivana templates configured 17 in the taler-merchant-backend. Paivana templates include a regular 18 expression which determines the set of pages the template applies to. 19 1. An HTTP client accesses a page at `paivana-httpd`. 20 2. If the paywall is enabled for the respective URL and no valid access 21 cookie is present, `paivana-httpd` redirects the browser to 22 a static paywall HTML page (customizable Mustache template) 23 referencing the payment template. 24 The page includes a "Paivana" HTTP header to also facilitate agentic 25 payments. 26 3. The browser computes a unique payment identifier and 27 renders a dynamic payment request (taler:// QR code 28 or link) and long-polls the taler-merchant-backend awaiting 29 completion of the payment. 30 4. The user instructs their Taler wallet to complete the payment. 31 5. The browser notices that the payment is complete and calls back to 32 `POST /.well-known/paivana` (provided by `paivana-httpd`) 33 with a reference to the unique payment identifier. 34 6. `paivana-httpd` verifies the payment with the merchant, sets 35 an HMAC access cookie, and redirects the browser to the original URL. 36 7. Requests with a valid cookie are forwarded to the upstream server 37 via libcurl and the response is streamed back. 38 39 The cookie is an HMAC over `(expiration time, website, client address)` keyed by a 40 `paivana_secret` derived from the configured `SECRET`. If `SECRET` is absent, 41 a random nonce is used and cookies do not survive a restart of `paivana-httpd` 42 43 44 Dependencies 45 ------------ 46 47 - GNUnet (libgnunetutil, libgnunetcurl) 48 - libmicrohttpd 49 - libcurl >= 7.34.0 50 - libjansson 51 - libgcrypt >= 1.6.1 52 - zlib 53 - GNU Taler: libtalerutil, libtalermerchant, libtalerexchange, 54 libtalermhd, libtalertemplating 55 56 57 Build 58 ----- 59 60 The project uses Meson but supports a GNU build process. 61 62 ./bootstrap 63 ./configure --prefix=$TARGET 64 make 65 sudo make install 66 67 68 Configuration 69 ------------- 70 71 Paivana reads an INI-style `.conf` file. The only section used is 72 `[paivana]`. A minimal working configuration: 73 74 [paivana] 75 DESTINATION_BASE_URL = https://example.com/ 76 MERCHANT_BACKEND_URL = https://backend.demo.taler.net/instances/sandbox/ 77 MERCHANT_ACCESS_TOKEN = secret-token:sandbox 78 SERVE = tcp 79 PORT = 9967 80 81 ### Required keys 82 83 Key Description 84 ---------------------- ----------------------------------------------------- 85 DESTINATION_BASE_URL Upstream server to proxy to once payment is confirmed. 86 MERCHANT_BACKEND_URL Base URL of the Taler merchant backend. 87 MERCHANT_ACCESS_TOKEN Bearer token for all calls to the merchant backend. 88 89 ### Optional keys 90 91 Key Description 92 -------- --------------------------------------------------------------- 93 BASE_URL Public base URL of Paivana. Derived from request headers 94 (X-Forwarded-Host / Host / X-Forwarded-Port) if absent. 95 SECRET Stable secret for cookie MAC and Paivana ID derivation. 96 A random nonce is generated on every startup if absent. 97 SERVE `tcp` (default) or `unix` (Unix-domain socket) or `systemd` 98 (systemd socket activation). 99 PORT TCP port, used when SERVE = tcp. 100 BIND_TO IP address to bind to; dual-stack wildcard if absent. 101 UNIXPATH UNIX path do bind to, used when SERVE = unix. 102 103 104 Running 105 ------- 106 107 $ paivana-httpd -c /etc/paivana/paivana.conf 108 109 Pass `-n` / `--no-payment` to bypass the paywall entirely (pure reverse 110 proxy, useful for testing upstream plumbing). 111 112 The daemon does not serve requests until it has fetched paywall templates 113 from the merchant backend. If template loading fails, startup is aborted. 114 115 116 Deployment behind a reverse proxy 117 ---------------------------------- 118 119 The recommended production setup runs Paivana over a Unix socket and 120 places nginx or Apache in front for TLS termination. 121 122 nginx (`/etc/nginx/sites-available/paivana`): 123 124 server { 125 listen 443 ssl; 126 server_name example.com; 127 128 location / { 129 proxy_pass http://unix:/run/paivana/httpd/paivana-http.sock; 130 proxy_set_header Host $host; 131 } 132 } 133 134 Apache (requires mod_proxy and mod_proxy_http): 135 136 <Location "/"> 137 ProxyPass "unix:/var/lib/paivana/httpd/paivana.sock|http://example.com/" 138 </Location> 139 140 Set `BASE_URL` in the configuration file to the public HTTPS URL so 141 that redirects and cookie domains are correct. 142 143 144 Source layout 145 ------------- 146 147 src/backend/ Main binary and all subsystems 148 paivana-httpd.c Entry point, scheduler, global state, shutdown 149 paivana-httpd_reverse.c Request-proxying state machine (core) 150 paivana-httpd_pay.c POST /.well-known/paivana handler 151 paivana-httpd_cookie.c HMAC access-cookie logic 152 paivana-httpd_templates.c Paywall template loading and rendering 153 paivana-httpd_helper.c Client IP / base URL helpers 154 paivana-httpd_daemon.c MHD daemon startup 155 paivana_pd.c GNUnet project-data descriptor 156 src/include/platform.h GNUnet-style platform header (include first) 157 src/tests/ Automated reverse-proxy tests 158 contrib/paywall.en.must Default Mustache paywall template 159 doc/prebuilt/ Git submodule: taler-docs (man pages) 160 161 162 Architecture notes 163 ------------------ 164 165 Single-threaded event loop: GNUnet scheduler drives both inbound HTTP 166 (libmicrohttpd) and outbound requests (libgnunetcurl / libcurl multi). 167 Running multiple `paivana-httpd` processes on the same port is 168 supported as the main way to scale-up the system. 169 170 Requests and responses are currently not streamed in the reverse 171 proxy; as a result, uploads and downloads are currently hard-capped by 172 the implementation at 40 MiB. Lower limits for the upload may be 173 configured. 174 175 The MHD daemon is not started until paywall templates have been fetched 176 from the merchant backend asynchronously. 177 178 179 License 180 ------- 181 182 GNU Affero General Public License version 3 or later. 183 See COPYING for the full text. 184 185 186 Bug reports 187 ----------- 188 189 Please report bugs at https://bugs.taler.net/.