@profullstack/x402-gateway 0.2.0 → 0.2.2
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/edge.js +28 -7
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@profullstack/x402-gateway",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.2",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Sell crawl access to AI training crawlers by the day over x402, settled by CoinPay. One middleware: 402 with an offer, a sales page with CLI instructions, signed passes, and a robots.txt that keeps search crawlers welcome.",
|
|
6
6
|
"keywords": [
|
package/src/edge.js
CHANGED
|
@@ -59,22 +59,42 @@ export function inCidrs(ip, compiled) {
|
|
|
59
59
|
/**
|
|
60
60
|
* The caller's address, as the edge reported it.
|
|
61
61
|
*
|
|
62
|
-
* `x-forwarded-for` is a list the client can seed
|
|
63
|
-
*
|
|
64
|
-
*
|
|
65
|
-
*
|
|
66
|
-
* nginx spelling of the same
|
|
62
|
+
* `x-forwarded-for` is a list the client can seed, and a denylist read from
|
|
63
|
+
* its first entry is a denylist any client can step around by sending one.
|
|
64
|
+
* The entry our own edge appends is the LAST, on every platform in front of
|
|
65
|
+
* these sites (Railway's proxy, nginx with `$proxy_add_x_forwarded_for`), so
|
|
66
|
+
* last is what is used. `x-real-ip` is nginx's spelling of the same hop and
|
|
67
|
+
* is preferred when present, because nginx sets it from the socket and
|
|
68
|
+
* nothing a client sends survives into it.
|
|
69
|
+
*
|
|
70
|
+
* A CDN in front of the edge would make the last hop the CDN's; put its
|
|
71
|
+
* ranges nowhere near `denyCidrs` and this still fails safe: nothing is
|
|
72
|
+
* refused, nothing is charged, by this check.
|
|
67
73
|
*/
|
|
68
74
|
export function clientIp(request) {
|
|
75
|
+
const real = request.headers.get('x-real-ip')?.trim();
|
|
76
|
+
if (real) return real;
|
|
69
77
|
const xff = request.headers.get('x-forwarded-for');
|
|
70
|
-
if (xff) return
|
|
71
|
-
|
|
78
|
+
if (!xff) return '';
|
|
79
|
+
const hops = xff.split(',').map((h) => h.trim()).filter(Boolean);
|
|
80
|
+
return hops[hops.length - 1] ?? '';
|
|
72
81
|
}
|
|
73
82
|
|
|
74
83
|
/* -------------------------------------------------------------- spoofing -- */
|
|
75
84
|
|
|
76
85
|
const CLAIMS_CHROMIUM = /\bChrome\/\d+/;
|
|
77
86
|
|
|
87
|
+
/**
|
|
88
|
+
* A crawler that says so. Googlebot's evergreen string is
|
|
89
|
+
* "Mozilla/5.0 AppleWebKit/537.36 (KHTML, like Gecko; compatible;
|
|
90
|
+
* Googlebot/2.1; +http://www.google.com/bot.html) Chrome/W.X.Y.Z Safari/537.36"
|
|
91
|
+
* -- it claims Chrome, it sends no Sec-Fetch-Mode, and it is the last thing
|
|
92
|
+
* on earth to charge. Bingbot is built the same way. Anything that declares
|
|
93
|
+
* itself is judged by the lists, never by this check: the whole point of the
|
|
94
|
+
* check is the client that declares nothing.
|
|
95
|
+
*/
|
|
96
|
+
const DECLARES_ITSELF = /compatible;|\bbot\b|bot\/|crawler|spider|slurp/i;
|
|
97
|
+
|
|
78
98
|
/**
|
|
79
99
|
* A request that claims a Chromium user agent but carries none of the
|
|
80
100
|
* fetch-metadata headers Chromium cannot omit.
|
|
@@ -88,5 +108,6 @@ const CLAIMS_CHROMIUM = /\bChrome\/\d+/;
|
|
|
88
108
|
export function isSpoofedBrowser(request) {
|
|
89
109
|
const ua = request.headers.get('user-agent') ?? '';
|
|
90
110
|
if (!CLAIMS_CHROMIUM.test(ua)) return false;
|
|
111
|
+
if (DECLARES_ITSELF.test(ua)) return false;
|
|
91
112
|
return !request.headers.has('sec-fetch-mode');
|
|
92
113
|
}
|