@paywalls-net/filter 1.3.6 → 1.3.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/package.json +1 -1
  2. package/src/index.js +52 -7
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "description": "Client SDK for integrating paywalls.net bot filtering and authorization services into your server or CDN.",
4
4
  "author": "paywalls.net",
5
5
  "license": "MIT",
6
- "version": "1.3.6",
6
+ "version": "1.3.8",
7
7
  "publishConfig": {
8
8
  "access": "public"
9
9
  },
package/src/index.js CHANGED
@@ -78,9 +78,24 @@ function isVAIRequest(request, vaiPath = '/pw') {
78
78
  }
79
79
 
80
80
  /**
81
- * Proxy VAI requests to the cloud-api service.
82
- * Proxies the entire request path without endpoint-specific logic,
83
- * allowing new VAI endpoints to work automatically.
81
+ * Proxy VAI requests to the cloud-api service (Spec §7).
82
+ *
83
+ * Transparent passthrough: cloud-api is authoritative for CORS, domain auth,
84
+ * and security headers. This proxy must NOT inject or modify CORS headers.
85
+ *
86
+ * Header forwarding (§7.2):
87
+ * - X-Forwarded-Origin: browser Origin (Cloudflare Workers control the
88
+ * outbound Origin header, so we relay via a custom header)
89
+ * - X-Original-Host: publisher hostname for domain binding
90
+ * - Access-Control-Request-Method/Headers: for preflight evaluation
91
+ * - Cookie: for session/identity context
92
+ * - User-Agent, X-Forwarded-For: standard proxy headers
93
+ * - Authorization: publisher API key (§7.4)
94
+ *
95
+ * Response passthrough (§7.3):
96
+ * All response headers from cloud-api are returned unchanged — including
97
+ * Access-Control-*, Vary, Cache-Control. The proxy never injects or
98
+ * re-stamps CORS headers.
84
99
  *
85
100
  * @param {Object} cfg - Configuration object with paywallsAPIHost and paywallsAPIKey
86
101
  * @param {Request} request - The incoming request
@@ -96,26 +111,50 @@ async function proxyVAIRequest(cfg, request) {
96
111
  // Get all request headers
97
112
  const headers = getAllHeaders(request);
98
113
 
99
- // Build forwarding headers
114
+ // Build forwarding headers — include everything cloud-api needs
115
+ // for CORS evaluation, domain auth, and request context.
100
116
  const forwardHeaders = {
101
117
  'User-Agent': headers['user-agent'] || sdkUserAgent,
102
118
  'Authorization': `Bearer ${cfg.paywallsAPIKey}`
103
119
  };
104
120
 
105
- // Add forwarding headers if available
121
+ // Client IP forwarding
106
122
  if (headers['x-forwarded-for']) {
107
123
  forwardHeaders['X-Forwarded-For'] = headers['x-forwarded-for'];
108
124
  } else if (headers['cf-connecting-ip']) {
109
125
  forwardHeaders['X-Forwarded-For'] = headers['cf-connecting-ip'];
110
126
  }
111
127
 
128
+ // Publisher hostname for domain binding (§7.2, §4)
129
+ // Cloud-api gates reading this on the vai_forwarded_host feature flag.
112
130
  if (headers['host']) {
113
131
  forwardHeaders['X-Original-Host'] = headers['host'];
114
132
  }
115
133
 
134
+ // Forward browser Origin via custom header for CORS evaluation (§5, §7.2).
135
+ // Cloudflare Workers runtime controls the outbound Origin header on fetch(),
136
+ // so we relay the browser's Origin via X-Forwarded-Origin. Cloud-api's
137
+ // evaluateCORS() reads this to make the authoritative CORS decision.
138
+ if (headers['origin']) {
139
+ forwardHeaders['X-Forwarded-Origin'] = headers['origin'];
140
+ }
141
+
142
+ // Forward preflight headers so cloud-api can evaluate OPTIONS (§5.4, §7.2)
143
+ if (headers['access-control-request-method']) {
144
+ forwardHeaders['Access-Control-Request-Method'] = headers['access-control-request-method'];
145
+ }
146
+ if (headers['access-control-request-headers']) {
147
+ forwardHeaders['Access-Control-Request-Headers'] = headers['access-control-request-headers'];
148
+ }
149
+
150
+ // Forward cookies for session/identity context (§7.2)
151
+ if (headers['cookie']) {
152
+ forwardHeaders['Cookie'] = headers['cookie'];
153
+ }
154
+
116
155
  // Forward request to cloud-api
117
156
  const response = await fetch(`${cfg.paywallsAPIHost}${cloudApiPath}`, {
118
- method: 'GET',
157
+ method: request.method || 'GET',
119
158
  headers: forwardHeaders
120
159
  });
121
160
 
@@ -123,7 +162,13 @@ async function proxyVAIRequest(cfg, request) {
123
162
  console.error(`VAI proxy error: ${response.status} ${response.statusText}`);
124
163
  }
125
164
 
126
- return response;
165
+ // Transparent passthrough (§7.3): return cloud-api response unchanged.
166
+ // Cloud-api is authoritative for CORS headers — do not re-stamp or inject.
167
+ return new Response(response.body, {
168
+ status: response.status,
169
+ statusText: response.statusText,
170
+ headers: response.headers
171
+ });
127
172
  } catch (err) {
128
173
  console.error(`Error proxying VAI request: ${err.message}`);
129
174
  return new Response('Internal Server Error', { status: 500 });