-
Notifications
You must be signed in to change notification settings - Fork 9
Expand file tree
/
Copy pathfetch-anchor-generic.mjs
More file actions
32 lines (31 loc) · 2.38 KB
/
Copy pathfetch-anchor-generic.mjs
File metadata and controls
32 lines (31 loc) · 2.38 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
/**
* Fetch a fresh VALID v3 anchor for ANY standard reCAPTCHA v3 sitekey -> $OUT.
* Usage: SITEKEY=6L... ORIGIN=https://localhost OUT=live/v3-own node fetch-anchor-generic.mjs
* (ORIGIN may be http://localhost, https://yourdomain.com, etc. co is derived from it.)
*/
import fs from 'node:fs';
const UA = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/148.0.0.0 Safari/537.36';
const H = { 'user-agent': UA, 'accept-language': 'en-US,en;q=0.9', accept: 'text/html,*/*' };
const SITEKEY = process.env.SITEKEY;
const ORIGIN = process.env.ORIGIN || 'http://localhost';
const OUT = process.env.OUT || 'live/v3-own';
if (!SITEKEY) { console.error('Set SITEKEY env'); process.exit(1); }
// co = base64url(origin + ':443') (url-safe: + -> -, / -> _, = -> .) matches reCAPTCHA's scheme
const CO = Buffer.from(ORIGIN + ':443').toString('base64').replace(/\+/g, '-').replace(/\//g, '_').replace(/=/g, '.');
fs.mkdirSync(OUT, { recursive: true });
async function get(url, label) { const r = await fetch(url, { headers: H }); const b = await r.text(); console.log(`[${label}] ${r.status} -> ${b.length}B`); return { status: r.status, body: b }; }
const api = await get(`https://www.google.com/recaptcha/api.js?render=${SITEKEY}`, 'api.js');
const ver = api.body.match(/releases\/([A-Za-z0-9_-]{16,})\//)?.[1];
console.log(' version:', ver, '| origin:', ORIGIN, '| co:', CO);
const anchorUrl = `https://www.google.com/recaptcha/api2/anchor?ar=1&k=${SITEKEY}&co=${CO}&hl=en&v=${ver}&size=invisible&cb=owntest`;
const anchor = await get(anchorUrl, 'anchor');
const valid = /recaptcha\.anchor\.Main\.init/.test(anchor.body), err = /ErrorMain\.init/.test(anchor.body);
console.log(' anchor valid=' + valid + ' error=' + err);
if (!valid) { console.log(' !! anchor not valid: domain may not be registered for this sitekey, or co/origin mismatch'); }
const eng = await get(`https://www.gstatic.com/recaptcha/releases/${ver}/recaptcha__en.js`, 'engine');
const ww = await get(`https://www.google.com/recaptcha/api2/webworker.js?hl=en&v=${ver}`, 'webworker');
fs.writeFileSync(`${OUT}/anchor.html`, anchor.body);
fs.writeFileSync(`${OUT}/recap-live.js`, eng.body);
fs.writeFileSync(`${OUT}/webworker.js`, ww.body);
fs.writeFileSync(`${OUT}/meta.json`, JSON.stringify({ version: ver, sitekey: SITEKEY, co: CO, origin: ORIGIN, anchorUrl }, null, 2));
console.log('saved -> ' + OUT + ' (valid=' + valid + ')');