capskip 1.2.0 → 1.4.0

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/CHANGELOG.md CHANGED
@@ -5,6 +5,90 @@ All notable changes to this project are documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [1.4.0] - 2026-11-01
9
+
10
+ ### Added
11
+
12
+ - **AWS WAF support** via `amazonWaf(sitekey, url, options)`, sent as
13
+ `method=amazon_waf`. Only `sitekey` and `url` are required.
14
+ On a challenge page (the HTTP 405 page with `window.gokuProps`), `sitekey`,
15
+ `iv` and `context` are `gokuProps.key`, `.iv` and `.context`, and
16
+ `challenge_script` / `captcha_script` are the page's challenge.js and
17
+ captcha.js. On a widget page (`AwsWafCaptcha.renderCaptcha`), `sitekey` is the
18
+ widget's `apiKey` and `jsapiScript` the URL of jsapi.js.
19
+ An AWS WAF answer is **not a token**: the result expands into
20
+ `captcha_voucher` and `existing_token`, which the site's `voucher` endpoint
21
+ (beside challenge.js) trades for the `aws-waf-token` cookie. `code` keeps the
22
+ raw answer.
23
+ - Parameter aliases `challengeScript` for `challenge_script`, `captchaScript`
24
+ for `captcha_script`, and `jsapi_script` for `jsapiScript`.
25
+ - TypeScript definitions for `AmazonWafOptions`, plus the new `SolveResult`
26
+ fields.
27
+ - `examples/amazon_waf.js`.
28
+
29
+ ### Changed
30
+
31
+ - The Capy answer expansion is now a shared helper, used by Capy and AWS WAF
32
+ alike. Capy results are unchanged.
33
+ - The exported `version` constant now reports the package version; it had been
34
+ left at `1.1.0`.
35
+
36
+ ### Notes
37
+
38
+ - `iv` and `context` are optional but travel together: one without the other is
39
+ refused locally, as the server would refuse it. Left out, CapSkip reads both
40
+ from the page at solve time. An optional passed as `''` is treated as not
41
+ sent, the way the server reads it.
42
+ - Every script URL must be `https` on an `awswaf.com` host, with no credentials,
43
+ no port other than 443, and a path ending in `challenge.js`, `captcha.js` or
44
+ `jsapi.js`. CapSkip posts the solution to the host the script names, so any
45
+ other script is refused before the request is made.
46
+ - AWS WAF uses `recaptchaTimeout`: a real browser mints the token the voucher is
47
+ issued for.
48
+
49
+ ## [1.3.0] - 2026-09-22
50
+
51
+ ### Added
52
+
53
+ - **Capy Puzzle support** via `capy(sitekey, url, options)`. The site key
54
+ (conventionally prefixed `PUZZLE_`) is sent as the `captchakey` the API
55
+ documents. Optional `api_server` selects the Capy API the key lives behind,
56
+ defaulting to `https://jp.api.capy.me`.
57
+ A Capy answer is **not a token**: the result expands into `captchakey`,
58
+ `challengekey` and `answer`, which go into the target form's `capy_captchakey`,
59
+ `capy_challengekey` and `capy_answer` fields. `code` keeps the raw answer.
60
+ - **CaptchaFox support** via `captchafox(sitekey, url, options)`. The result
61
+ exposes `token` (for the form's `cf-captcha-response` field) and, when the
62
+ solve reported one, `userAgent` — the UA the browser actually minted the token
63
+ under, which is not the one you sent. Optional `api_server` selects the widget
64
+ source; the MAM package returns a `MAM_` prefixed token.
65
+ - **Friendly Captcha support** via `friendlyCaptcha(sitekey, url, options)`.
66
+ Pass `version` (`v1`/`v2`, or a bare `1`/`2`), or `moduleScript` /
67
+ `nomoduleScript` with the widget script URLs and let CapSkip read the version
68
+ off the build the site actually loads. Optional `api_server` accepts `global`
69
+ (the default), `eu`, or a full URL for the data-residency tenant. The result
70
+ exposes `token`, for `frc-captcha-solution` on v1 or `frc-captcha-response` on
71
+ v2.
72
+ - Parameter aliases `userAgent`/`user_agent` for `useragent`, `captchaKey` for
73
+ `captchakey`, and `moduleScript`/`nomoduleScript` for `module_script` /
74
+ `nomodule_script`.
75
+ - TypeScript definitions for `CapyOptions`, `CaptchaFoxOptions` and
76
+ `FriendlyCaptchaOptions`, plus the new `SolveResult` fields.
77
+
78
+ ### Notes
79
+
80
+ - `version: 'avatar'` is refused locally for Capy. CapSkip solves the puzzle
81
+ family only, and answering an avatar request with a puzzle answer would bill
82
+ for a solve the target site rejects, indistinguishably from a broken solver.
83
+ - An unknown Friendly Captcha `version` is refused locally too. The two versions
84
+ are different protocols sharing one sitekey namespace, so solving the wrong one
85
+ returns a well-formed token the site rejects with nothing to indicate why.
86
+ - CaptchaFox and Friendly Captcha use `recaptchaTimeout`: the first is a real
87
+ browser solve, and the second has its difficulty set per request by the service
88
+ (and always solves in a browser on v2). Capy uses `defaultTimeout` — it is one
89
+ HTTP fetch plus pixel math, held back to roughly two seconds because Capy
90
+ refuses answers that arrive faster than a human could have produced them.
91
+
8
92
  ## [1.2.0] - 2026-09-12
9
93
 
10
94
  ### Added
package/README.md CHANGED
@@ -5,7 +5,7 @@
5
5
  [![License: MIT](https://img.shields.io/badge/License-MIT-green.svg)](LICENSE)
6
6
  [![Tests](https://github.com/capskip/capskip-node/actions/workflows/ci.yml/badge.svg)](https://github.com/capskip/capskip-node/actions/workflows/ci.yml)
7
7
 
8
- **Solve reCAPTCHA v2, reCAPTCHA v3, Cloudflare Turnstile, GeeTest, ALTCHA and image captchas from Node.js.**
8
+ **Solve reCAPTCHA v2, reCAPTCHA v3, Cloudflare Turnstile, GeeTest, ALTCHA, Capy Puzzle, CaptchaFox, Friendly Captcha, AWS WAF and image captchas from Node.js.**
9
9
 
10
10
  Official Node.js client for [CapSkip](https://capskip.com), a **local captcha solver** that runs on your own machine. Licensed once, not billed per solve. TypeScript definitions included.
11
11
 
@@ -19,7 +19,7 @@ npm install capskip
19
19
 
20
20
  CapSkip is a desktop app. It does the solving on your machine and exposes the standard captcha-solver HTTP API — the same `in.php` / `res.php` endpoints every 2captcha-compatible client already speaks — on `127.0.0.1:8080`.
21
21
 
22
- This SDK is a thin wrapper over that API, with the method names you would expect: `normal()`, `recaptcha()`, `turnstile()`, `geetest()`, `altcha()`. Nothing leaves your network, and there is no credit balance to keep an eye on.
22
+ This SDK is a thin wrapper over that API, with the method names you would expect: `normal()`, `recaptcha()`, `turnstile()`, `geetest()`, `altcha()`, `capy()`, `captchafox()`, `friendlyCaptcha()`, `amazonWaf()`. Nothing leaves your network, and there is no credit balance to keep an eye on.
23
23
 
24
24
  ## Supported captcha types
25
25
 
@@ -35,6 +35,11 @@ This SDK is a thin wrapper over that API, with the method names you would expect
35
35
  | Cloudflare Turnstile (challenge page) | `solver.turnstile(sitekey, url, { data, pagedata })` |
36
36
  | **GeeTest v3 solver** (slide puzzle) | `solver.geetest(gt, challenge, url)` |
37
37
  | **ALTCHA solver** (proof-of-work) | `solver.altcha(url, { challengeUrl })` |
38
+ | **Capy Puzzle solver** (slide puzzle) | `solver.capy(sitekey, url)` |
39
+ | **CaptchaFox solver** (widget) | `solver.captchafox(sitekey, url)` |
40
+ | **Friendly Captcha solver** (proof-of-work) | `solver.friendlyCaptcha(sitekey, url, { version })` |
41
+ | **AWS WAF solver** (challenge page) | `solver.amazonWaf(sitekey, url, { iv, context })` |
42
+ | AWS WAF (widget) | `solver.amazonWaf(sitekey, url, { jsapiScript })` |
38
43
 
39
44
  **hCaptcha and FunCaptcha/Arkose are not supported.** hCaptcha is the one people misidentify most often, since it also puts a `data-sitekey` on the widget — check for `class="h-captcha"` or a `js.hcaptcha.com` script before reaching for `recaptcha()`.
40
45
 
@@ -131,8 +136,9 @@ const solver = new CapSkip({
131
136
  host: '127.0.0.1', // CapSkip host
132
137
  port: 8080, // CapSkip port from app settings
133
138
  defaultTimeout: 120, // seconds — image captcha polling timeout
134
- recaptchaTimeout: 300, // seconds — reCAPTCHA / Turnstile / GeeTest polling timeout
135
- // (ALTCHA uses defaultTimeout — CPU work, not a browser solve)
139
+ recaptchaTimeout: 300, // seconds — reCAPTCHA / Turnstile / GeeTest / CaptchaFox /
140
+ // Friendly Captcha / AWS WAF polling timeout
141
+ // (ALTCHA and Capy use defaultTimeout — neither is a browser solve)
136
142
  pollingInterval: 5, // max seconds between res.php polls (starts at 0.25s, backs off to this)
137
143
  });
138
144
  ```
@@ -230,7 +236,128 @@ result.token;
230
236
  Challenges expire fast — some sites inside two minutes — so fetch one
231
237
  immediately before solving and submit the token promptly.
232
238
 
233
- ### With a proxy (reCAPTCHA, Turnstile, GeeTest & ALTCHA only)
239
+ ### Capy Puzzle
240
+
241
+ A Capy solution is not a token. It is three values that together go into the
242
+ target form, so post all three back exactly as returned.
243
+
244
+ ```js
245
+ const result = await solver.capy(
246
+ 'PUZZLE_Abc1dEFghIJKLM2no34P56q7rStu8v',
247
+ 'https://example.com/login',
248
+ );
249
+
250
+ // capy_captchakey, capy_challengekey and capy_answer respectively
251
+ result.captchakey, result.challengekey, result.answer;
252
+ ```
253
+
254
+ `answer` is the drag path the widget would have recorded — submit it verbatim,
255
+ without trimming or re-encoding it. The challenge key is single-use and
256
+ short-lived, so submit promptly rather than caching the three values.
257
+
258
+ Pass `api_server` when the widget script points somewhere other than
259
+ `https://jp.api.capy.me`. Only the `puzzle` family is solved; `version: 'avatar'`
260
+ is refused rather than answered with a puzzle answer the site would reject.
261
+
262
+ ### CaptchaFox
263
+
264
+ ```js
265
+ const result = await solver.captchafox(
266
+ 'sk_xtNxpk6fCdFbxh1_xJeGflSdCE9tn99G',
267
+ 'https://example.com/signup',
268
+ );
269
+
270
+ // Post this back in the form field the widget uses, named `cf-captcha-response`
271
+ result.token;
272
+
273
+ // The UA the token was minted under — submit under this one, not your own
274
+ result.userAgent;
275
+ ```
276
+
277
+ `url` has to be the page the widget actually runs on: CaptchaFox checks it
278
+ against the domains the key is registered for and refuses a mismatch
279
+ permanently, not intermittently.
280
+
281
+ Pass `api_server` only when the page does not load the default widget. A page
282
+ loading the MAM package expects a `MAM_` prefixed token, and sending the wrong
283
+ source still succeeds — it just returns a token the site will not accept, which
284
+ reads as a silent verification failure rather than an error.
285
+
286
+ ### Friendly Captcha
287
+
288
+ Two different protocols ship under this name and a sitekey does not tell you
289
+ which one a site uses, so say which — or send the widget script and let CapSkip
290
+ read it off the build the site actually loads.
291
+
292
+ ```js
293
+ const result = await solver.friendlyCaptcha(
294
+ 'FCMGEMUD2M567T8G',
295
+ 'https://example.com/signup',
296
+ { version: 'v2' },
297
+ );
298
+
299
+ // v1 → frc-captcha-solution, v2 → frc-captcha-response
300
+ result.token;
301
+ ```
302
+
303
+ ```js
304
+ // Or let the script URL decide the version
305
+ const result = await solver.friendlyCaptcha(
306
+ 'FCMGEMUD2M567T8G',
307
+ 'https://example.com/signup',
308
+ { moduleScript: 'https://cdn.example.com/@friendlycaptcha/sdk@0.1.6/site.min.js' },
309
+ );
310
+ ```
311
+
312
+ Solving the wrong version returns a well-formed token the target site rejects,
313
+ with nothing to indicate the version was the problem. With neither `version` nor
314
+ a script URL, v1 is assumed. Pass `api_server: 'eu'` for a sitekey on the EU
315
+ data-residency tenant. A v2 token is roughly six kilobytes, so size whatever
316
+ carries it accordingly.
317
+
318
+ ### AWS WAF
319
+
320
+ AWS WAF puts its CAPTCHA either on a **challenge page** — the HTTP 405
321
+ interstitial that sets `window.gokuProps` — or in a **widget** an ordinary page
322
+ renders with `AwsWafCaptcha.renderCaptcha`. Only `sitekey` and `url` are required.
323
+
324
+ ```js
325
+ // Challenge page: sitekey, iv and context are gokuProps.key, .iv and .context
326
+ const result = await solver.amazonWaf(
327
+ 'AQIDAHjcYuEXAMPLEghicBgQ/7bFaQZ+m5FKCMDnO+vTbNg96AHDh0IR5vgzHNceHYqZR+GOAAAAfjB8',
328
+ 'https://example.com/protected',
329
+ {
330
+ iv: 'CgAFRDIjfgAAA5yY',
331
+ context: 'Rbp3r8fvbuhmrCqpUe8Mh1TLvs8OSKJZiSs2vCF4dt9rxVZI7xYJa2n5k/9r+XaXe7KUIu2I8nXTDHHkDvIOTDc2',
332
+ challenge_script: 'https://3f2a9c7d41b0.edge.sdk.awswaf.com/3f2a9c7d41b0/8e51d0c7a2f4/challenge.js',
333
+ },
334
+ );
335
+
336
+ // Widget page: sitekey is the widget's apiKey, plus the jsapi.js it loads
337
+ const result = await solver.amazonWaf(
338
+ 'Xr9kEXAMPLE2bWQx1vTq8LmZ0aYc4dHs7nFp3gJt6uKw5eRi9AbCdEfGh=_0_1',
339
+ 'https://example.com/protected',
340
+ { jsapiScript: 'https://5b7e0a19c3d8.us-east-1.captcha-sdk.awswaf.com/5b7e0a19c3d8/jsapi.js' },
341
+ );
342
+
343
+ result.captcha_voucher, result.existing_token;
344
+ ```
345
+
346
+ `iv` and `context` are optional and travel together: send both or neither. Left
347
+ out, CapSkip reads them from the page at solve time, which is the safer choice
348
+ when your copy of the page is more than a few minutes old.
349
+
350
+ The answer is not a token. POST `captcha_voucher` and `existing_token` as JSON
351
+ to the `voucher` endpoint beside the page's `challenge.js`; the response's
352
+ `token` is the `aws-waf-token` cookie. The pair is short-lived, so exchange it
353
+ immediately rather than storing it.
354
+
355
+ Every script URL (`challenge_script`, `captcha_script`, `jsapiScript`) must be an
356
+ https URL on an `awswaf.com` host. CapSkip posts the solution to the host the
357
+ script names, so anything else is refused before the request is made. See the
358
+ [AWS WAF API docs](https://capskip.com/api-docs/#aws-waf).
359
+
360
+ ### With a proxy (every method except image captcha)
234
361
 
235
362
  ```js
236
363
  // Proxy is not supported for image captcha
@@ -325,7 +452,11 @@ Every solve method resolves to:
325
452
  ```
326
453
 
327
454
  GeeTest additionally expands its answer into `challenge`, `validate`, and
328
- `seccode`, while `code` keeps the raw JSON string. ALTCHA adds `token` (the same
455
+ `seccode`, while `code` keeps the raw JSON string. CaptchaFox and Friendly
456
+ Captcha add `token`, the same string as `code`. Capy expands its answer into
457
+ `captchakey`, `challengekey` and `answer` — it returns an object rather than a
458
+ token, and `code` keeps the raw answer. AWS WAF likewise returns an object,
459
+ expanded into `captcha_voucher` and `existing_token`. ALTCHA adds `token` (the same
329
460
  string as `code`) and `number`, the counter that solved it.
330
461
 
331
462
  ---
@@ -371,7 +502,7 @@ const result: SolveResult = await solver.recaptcha('...', 'https://example.com')
371
502
 
372
503
  ### How do I solve a captcha in Node.js?
373
504
 
374
- Install the CapSkip desktop app, `npm install capskip`, then call the method that matches the widget — `recaptcha()`, `turnstile()`, `geetest()`, `altcha()` or `normal()`. Each returns a Promise that resolves once CapSkip has an answer, giving you a token, or the recognized text in the case of an image captcha.
505
+ Install the CapSkip desktop app, `npm install capskip`, then call the method that matches the widget — `recaptcha()`, `turnstile()`, `geetest()`, `altcha()`, `capy()`, `captchafox()`, `friendlyCaptcha()`, `amazonWaf()` or `normal()`. Each returns a Promise that resolves once CapSkip has an answer, giving you a token, or the recognized text in the case of an image captcha.
375
506
 
376
507
  ### Is this a free captcha solver?
377
508
 
@@ -379,7 +510,7 @@ The SDK itself is MIT-licensed and free. Solving needs the CapSkip app, which is
379
510
 
380
511
  ### Which captchas can it solve?
381
512
 
382
- reCAPTCHA v2 (checkbox and invisible), reCAPTCHA v3, reCAPTCHA Enterprise, Cloudflare Turnstile, GeeTest v3, ALTCHA, and image/text captchas. Not hCaptcha, and not FunCaptcha/Arkose.
513
+ reCAPTCHA v2 (checkbox and invisible), reCAPTCHA v3, reCAPTCHA Enterprise, Cloudflare Turnstile, GeeTest v3, ALTCHA, Capy Puzzle, CaptchaFox, Friendly Captcha, AWS WAF, and image/text captchas. Not hCaptcha, and not FunCaptcha/Arkose.
383
514
 
384
515
  ### Does it work with Puppeteer and Playwright?
385
516