@paywalls-net/filter 1.2.4 → 1.3.1
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.
- package/package.json +1 -1
- package/src/index.js +130 -9
package/package.json
CHANGED
package/src/index.js
CHANGED
|
@@ -34,10 +34,7 @@ let runtime = detectRuntime();
|
|
|
34
34
|
let fetchVersion = detectFetchVersion();
|
|
35
35
|
const sdkUserAgent = `pw-filter-sdk/${sdk_version} (${runtime}; fetch/${fetchVersion})`;
|
|
36
36
|
|
|
37
|
-
|
|
38
|
-
// Separate html from the status in the access object.
|
|
39
|
-
const { response, ...status } = access;
|
|
40
|
-
|
|
37
|
+
function getAllHeaders(request) {
|
|
41
38
|
// Get all headers as a plain object (name-value pairs)
|
|
42
39
|
let headers = {};
|
|
43
40
|
if (typeof request.headers.entries === "function") {
|
|
@@ -51,6 +48,80 @@ async function logAccess(cfg, request, access) {
|
|
|
51
48
|
headers[key] = request.headers[key][0]?.value || "";
|
|
52
49
|
}
|
|
53
50
|
}
|
|
51
|
+
return headers;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Check if the request is for a VAI endpoint (vai.json or vai.js)
|
|
56
|
+
* @param {Request} request - The incoming request
|
|
57
|
+
* @param {string} vaiPath - The path prefix for VAI endpoints (default: '/pw')
|
|
58
|
+
* @returns {boolean} - True if this is a VAI endpoint request
|
|
59
|
+
*/
|
|
60
|
+
function isVAIRequest(request, vaiPath = '/pw') {
|
|
61
|
+
try {
|
|
62
|
+
const url = new URL(request.url || `http://host${request.uri || ''}`);
|
|
63
|
+
const pathname = url.pathname;
|
|
64
|
+
return pathname === `${vaiPath}/vai.json` || pathname === `${vaiPath}/vai.js`;
|
|
65
|
+
} catch (err) {
|
|
66
|
+
return false;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Proxy VAI requests to the cloud-api service
|
|
72
|
+
* @param {Object} cfg - Configuration object with paywallsAPIHost and paywallsAPIKey
|
|
73
|
+
* @param {Request} request - The incoming request
|
|
74
|
+
* @returns {Promise<Response>} - The proxied response from cloud-api
|
|
75
|
+
*/
|
|
76
|
+
async function proxyVAIRequest(cfg, request) {
|
|
77
|
+
try {
|
|
78
|
+
const url = new URL(request.url || `http://host${request.uri || ''}`);
|
|
79
|
+
const isJson = url.pathname.endsWith('/vai.json');
|
|
80
|
+
const cloudApiPath = isJson ? '/pw/vai.json' : '/pw/vai.js';
|
|
81
|
+
|
|
82
|
+
// Get all request headers
|
|
83
|
+
const headers = getAllHeaders(request);
|
|
84
|
+
|
|
85
|
+
// Build forwarding headers
|
|
86
|
+
const forwardHeaders = {
|
|
87
|
+
'User-Agent': headers['user-agent'] || sdkUserAgent,
|
|
88
|
+
'Authorization': `Bearer ${cfg.paywallsAPIKey}`
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
// Add forwarding headers if available
|
|
92
|
+
if (headers['x-forwarded-for']) {
|
|
93
|
+
forwardHeaders['X-Forwarded-For'] = headers['x-forwarded-for'];
|
|
94
|
+
} else if (headers['cf-connecting-ip']) {
|
|
95
|
+
forwardHeaders['X-Forwarded-For'] = headers['cf-connecting-ip'];
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
if (headers['host']) {
|
|
99
|
+
forwardHeaders['X-Original-Host'] = headers['host'];
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// Forward request to cloud-api
|
|
103
|
+
const response = await fetch(`${cfg.paywallsAPIHost}${cloudApiPath}`, {
|
|
104
|
+
method: 'GET',
|
|
105
|
+
headers: forwardHeaders
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
if (!response.ok) {
|
|
109
|
+
console.error(`VAI proxy error: ${response.status} ${response.statusText}`);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
return response;
|
|
113
|
+
} catch (err) {
|
|
114
|
+
console.error(`Error proxying VAI request: ${err.message}`);
|
|
115
|
+
return new Response('Internal Server Error', { status: 500 });
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
async function logAccess(cfg, request, access) {
|
|
120
|
+
// Separate html from the status in the access object.
|
|
121
|
+
const { response, ...status } = access;
|
|
122
|
+
|
|
123
|
+
// Get all headers as a plain object (name-value pairs)
|
|
124
|
+
let headers = getAllHeaders(request);
|
|
54
125
|
|
|
55
126
|
const url = new URL(request.url);
|
|
56
127
|
let body = {
|
|
@@ -107,14 +178,15 @@ async function checkAgentStatus(cfg, request) {
|
|
|
107
178
|
response: { code: 401, html: "Unauthorized access." }
|
|
108
179
|
};
|
|
109
180
|
}
|
|
110
|
-
|
|
181
|
+
let headers = getAllHeaders(request);
|
|
111
182
|
const agentInfo = await classifyUserAgent(cfg, userAgent);
|
|
112
183
|
|
|
113
184
|
const body = JSON.stringify({
|
|
114
185
|
account_id: cfg.paywallsPublisherId,
|
|
115
186
|
operator: agentInfo.operator,
|
|
116
187
|
agent: agentInfo.agent,
|
|
117
|
-
token: token
|
|
188
|
+
token: token,
|
|
189
|
+
headers: headers
|
|
118
190
|
});
|
|
119
191
|
|
|
120
192
|
const response = await fetch(`${cfg.paywallsAPIHost}/api/filter/agents/auth`, {
|
|
@@ -256,8 +328,15 @@ async function cloudflare(config = null) {
|
|
|
256
328
|
const paywallsConfig = {
|
|
257
329
|
paywallsAPIHost: env.PAYWALLS_CLOUD_API_HOST || PAYWALLS_CLOUD_API_HOST,
|
|
258
330
|
paywallsAPIKey: env.PAYWALLS_CLOUD_API_KEY,
|
|
259
|
-
paywallsPublisherId: env.PAYWALLS_PUBLISHER_ID
|
|
331
|
+
paywallsPublisherId: env.PAYWALLS_PUBLISHER_ID,
|
|
332
|
+
vaiPath: env.PAYWALLS_VAI_PATH || '/pw'
|
|
260
333
|
};
|
|
334
|
+
|
|
335
|
+
// Check if this is a VAI endpoint request and proxy it
|
|
336
|
+
if (isVAIRequest(request, paywallsConfig.vaiPath)) {
|
|
337
|
+
return await proxyVAIRequest(paywallsConfig, request);
|
|
338
|
+
}
|
|
339
|
+
|
|
261
340
|
await loadAgentPatterns(paywallsConfig);
|
|
262
341
|
|
|
263
342
|
if (await isRecognizedBot(paywallsConfig, request)) {
|
|
@@ -281,8 +360,14 @@ async function fastly() {
|
|
|
281
360
|
const paywallsConfig = {
|
|
282
361
|
paywallsAPIHost: config.get('PAYWALLS_CLOUD_API_HOST') || PAYWALLS_CLOUD_API_HOST,
|
|
283
362
|
paywallsAPIKey: config.get('PAYWALLS_API_KEY'),
|
|
284
|
-
paywallsPublisherId: config.get('PAYWALLS_PUBLISHER_ID')
|
|
363
|
+
paywallsPublisherId: config.get('PAYWALLS_PUBLISHER_ID'),
|
|
364
|
+
vaiPath: config.get('PAYWALLS_VAI_PATH') || '/pw'
|
|
285
365
|
};
|
|
366
|
+
|
|
367
|
+
// Check if this is a VAI endpoint request and proxy it
|
|
368
|
+
if (isVAIRequest(request, paywallsConfig.vaiPath)) {
|
|
369
|
+
return await proxyVAIRequest(paywallsConfig, request);
|
|
370
|
+
}
|
|
286
371
|
|
|
287
372
|
await loadAgentPatterns(paywallsConfig);
|
|
288
373
|
|
|
@@ -297,6 +382,34 @@ async function fastly() {
|
|
|
297
382
|
}
|
|
298
383
|
};
|
|
299
384
|
}
|
|
385
|
+
/**
|
|
386
|
+
* Convert a standard Response to CloudFront format
|
|
387
|
+
* @param {Response} response - Standard fetch Response object
|
|
388
|
+
* @returns {Promise<Object>} - CloudFront-formatted response
|
|
389
|
+
*/
|
|
390
|
+
async function responseToCloudFront(response) {
|
|
391
|
+
const headers = {};
|
|
392
|
+
|
|
393
|
+
// Convert response headers to CloudFront format
|
|
394
|
+
for (const [key, value] of response.headers.entries()) {
|
|
395
|
+
headers[key.toLowerCase()] = [
|
|
396
|
+
{
|
|
397
|
+
key: key,
|
|
398
|
+
value: value
|
|
399
|
+
}
|
|
400
|
+
];
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
const body = await response.text();
|
|
404
|
+
|
|
405
|
+
return {
|
|
406
|
+
status: response.status,
|
|
407
|
+
statusDescription: response.statusText || 'OK',
|
|
408
|
+
headers: headers,
|
|
409
|
+
body: body
|
|
410
|
+
};
|
|
411
|
+
}
|
|
412
|
+
|
|
300
413
|
/**
|
|
301
414
|
* Adapt to CloudFront format
|
|
302
415
|
* Lambda@Edge events see https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/lambda-event-structure.html#lambda-event-structure-request
|
|
@@ -329,13 +442,21 @@ async function cloudfront(config) {
|
|
|
329
442
|
const paywallsConfig = {
|
|
330
443
|
paywallsAPIHost: config.PAYWALLS_CLOUD_API_HOST || PAYWALLS_CLOUD_API_HOST,
|
|
331
444
|
paywallsAPIKey: config.PAYWALLS_API_KEY,
|
|
332
|
-
paywallsPublisherId: config.PAYWALLS_PUBLISHER_ID
|
|
445
|
+
paywallsPublisherId: config.PAYWALLS_PUBLISHER_ID,
|
|
446
|
+
vaiPath: config.PAYWALLS_VAI_PATH || '/pw'
|
|
333
447
|
};
|
|
334
448
|
await loadAgentPatterns(paywallsConfig);
|
|
335
449
|
|
|
336
450
|
return async function handle(event, ctx) {
|
|
337
451
|
let request = event.Records[0].cf.request;
|
|
338
452
|
request = requestShim(request);
|
|
453
|
+
|
|
454
|
+
// Check if this is a VAI endpoint request and proxy it
|
|
455
|
+
if (isVAIRequest(request, paywallsConfig.vaiPath)) {
|
|
456
|
+
const response = await proxyVAIRequest(paywallsConfig, request);
|
|
457
|
+
return await responseToCloudFront(response);
|
|
458
|
+
}
|
|
459
|
+
|
|
339
460
|
if (await isRecognizedBot(paywallsConfig, request)) {
|
|
340
461
|
const authz = await checkAgentStatus(paywallsConfig, request);
|
|
341
462
|
|