capskip 1.0.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/CHANGELOG.md +55 -0
- package/LICENSE +21 -0
- package/README.md +274 -0
- package/SECURITY.md +35 -0
- package/docs/API_REFERENCE.md +292 -0
- package/docs/GETTING_STARTED.md +167 -0
- package/docs/TROUBLESHOOTING.md +206 -0
- package/docs/TUTORIAL.md +504 -0
- package/examples/async_example.js +34 -0
- package/examples/captcha.png +0 -0
- package/examples/image_captcha.js +20 -0
- package/examples/recaptcha.js +19 -0
- package/examples/turnstile.js +20 -0
- package/examples/verify_connection.js +50 -0
- package/package.json +50 -0
- package/src/apiClient.js +96 -0
- package/src/apiParams.js +175 -0
- package/src/exceptions.js +37 -0
- package/src/http.js +158 -0
- package/src/index.js +31 -0
- package/src/solver.js +266 -0
- package/types/index.d.ts +167 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project are documented in this file.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
+
|
|
8
|
+
## [1.0.2] - 2026-07-15
|
|
9
|
+
|
|
10
|
+
### Fixed
|
|
11
|
+
|
|
12
|
+
- Submitting with `json=1` no longer fails with `ApiException: cannot recognize
|
|
13
|
+
response`. With `json=1` CapSkip's `in.php` returns `{"status":1,"request":"<id>"}`
|
|
14
|
+
instead of `OK|<id>`; `send()` now parses both forms, so `normal(file, { json: 1 })`
|
|
15
|
+
and the equivalent reCAPTCHA/Turnstile calls submit and solve correctly.
|
|
16
|
+
|
|
17
|
+
## [1.0.1] - 2026-07-14
|
|
18
|
+
|
|
19
|
+
### Fixed
|
|
20
|
+
|
|
21
|
+
- Polling no longer crashes with `ApiException: cannot recognize response` when
|
|
22
|
+
CapSkip returns an empty response body. CapSkip returns an empty body while no
|
|
23
|
+
result is available yet — briefly right after a captcha is submitted (before it
|
|
24
|
+
reports `CAPCHA_NOT_READY`), for an unknown id, and after a solved token has
|
|
25
|
+
already been read. The SDK now treats an empty body as "not ready" and keeps
|
|
26
|
+
polling, so `recaptcha()`, `turnstile()`, and `normal()` solve reliably instead
|
|
27
|
+
of failing on the first poll.
|
|
28
|
+
|
|
29
|
+
## [1.0.0] - 2026-07-14
|
|
30
|
+
|
|
31
|
+
### Added
|
|
32
|
+
|
|
33
|
+
- Initial release of the CapSkip Node.js SDK
|
|
34
|
+
- `CapSkip` client for the local CapSkip API — every method returns a Promise
|
|
35
|
+
- `AsyncCapSkip` / `AsyncApiClient` exported as aliases for cross-SDK parity
|
|
36
|
+
- Image CAPTCHA solving via `normal()` (file, URL, base64, or data-URI)
|
|
37
|
+
- reCAPTCHA v2 / v3 solving via `recaptcha()` (invisible, enterprise, proxy)
|
|
38
|
+
- Cloudflare Turnstile solving via `turnstile()` (widget and challenge page)
|
|
39
|
+
- Turnstile automatically polls with `json=1` and returns `userAgent` when provided
|
|
40
|
+
- Manual workflow: `send()`, `getResult()`, `solve()`
|
|
41
|
+
- Adaptive result polling — starts at 0.25s and backs off (doubling) up to the
|
|
42
|
+
configured `pollingInterval`, so fast solves (e.g. image captchas) return in a
|
|
43
|
+
fraction of a second; `pollingInterval` also accepts sub-second values
|
|
44
|
+
- Familiar parameter aliases (`url`→`pageurl`, `score`→`min_score`, etc.)
|
|
45
|
+
- Proxy support via object format `{ type: '...', uri: '...' }`
|
|
46
|
+
- Strict per-captcha parameter validation — only documented parameters are accepted
|
|
47
|
+
- Error hierarchy: `ValidationException`, `NetworkException`, `ApiException`, `TimeoutException`
|
|
48
|
+
- Bundled TypeScript type definitions
|
|
49
|
+
- Example scripts for every supported captcha type
|
|
50
|
+
- Unit and integration tests using Node's built-in test runner — no runtime dependencies
|
|
51
|
+
- Documentation: Tutorial, Getting Started, API Reference, Troubleshooting
|
|
52
|
+
|
|
53
|
+
[1.0.2]: https://github.com/capskip/capskip-node/releases/tag/v1.0.2
|
|
54
|
+
[1.0.1]: https://github.com/capskip/capskip-node/releases/tag/v1.0.1
|
|
55
|
+
[1.0.0]: https://github.com/capskip/capskip-node/releases/tag/v1.0.0
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 CapSkip
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,274 @@
|
|
|
1
|
+
# CapSkip Node.js SDK
|
|
2
|
+
|
|
3
|
+
[](https://nodejs.org/)
|
|
4
|
+
[](LICENSE)
|
|
5
|
+
[](https://github.com/capskip/capskip-node/actions/workflows/ci.yml)
|
|
6
|
+
|
|
7
|
+
Official Node.js client for the [CapSkip](https://capskip.com) **local** captcha solver.
|
|
8
|
+
|
|
9
|
+
CapSkip runs on your machine and exposes a standard captcha-solver HTTP API (the familiar `in.php` / `res.php` endpoints). This SDK wraps that API with clean, familiar method names, so you can solve captchas locally — no cloud service and no per-solve API fees beyond your CapSkip license.
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
## Quick start (5 minutes)
|
|
14
|
+
|
|
15
|
+
### 1. Install CapSkip
|
|
16
|
+
|
|
17
|
+
Download and run the CapSkip desktop app from [capskip.com](https://capskip.com). Leave it running in the background.
|
|
18
|
+
|
|
19
|
+
In CapSkip settings, note:
|
|
20
|
+
|
|
21
|
+
- **API port** (default: `8080`)
|
|
22
|
+
- **API key** (optional — if validation is disabled, any string works)
|
|
23
|
+
|
|
24
|
+
### 2. Install the SDK
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
npm install capskip
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
Or from source:
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
git clone https://github.com/capskip/capskip-node.git
|
|
34
|
+
cd capskip-node
|
|
35
|
+
npm install
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
### 3. Solve your first captcha
|
|
39
|
+
|
|
40
|
+
```js
|
|
41
|
+
const { CapSkip } = require('capskip');
|
|
42
|
+
|
|
43
|
+
const solver = new CapSkip({ host: '127.0.0.1', port: 8080 });
|
|
44
|
+
|
|
45
|
+
(async () => {
|
|
46
|
+
const result = await solver.recaptcha(
|
|
47
|
+
'YOUR_SITEKEY',
|
|
48
|
+
'https://example.com/page-with-recaptcha',
|
|
49
|
+
);
|
|
50
|
+
|
|
51
|
+
console.log(result.code); // g-recaptcha-response token
|
|
52
|
+
})();
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
> **Prerequisite:** CapSkip must be running before you call the SDK. If you see a connection error, see [Troubleshooting](docs/TROUBLESHOOTING.md).
|
|
56
|
+
|
|
57
|
+
Every solve method returns a Promise — use `await` or `.then()`.
|
|
58
|
+
|
|
59
|
+
---
|
|
60
|
+
|
|
61
|
+
## Supported captcha types
|
|
62
|
+
|
|
63
|
+
| Type | SDK method |
|
|
64
|
+
|---|---|
|
|
65
|
+
| Image CAPTCHA (distorted text) | `solver.normal(file)` |
|
|
66
|
+
| reCAPTCHA v2 (checkbox) | `solver.recaptcha(sitekey, url)` |
|
|
67
|
+
| reCAPTCHA v2 Invisible | `solver.recaptcha(sitekey, url, { invisible: 1 })` |
|
|
68
|
+
| reCAPTCHA v2 Enterprise | `solver.recaptcha(sitekey, url, { enterprise: 1 })` |
|
|
69
|
+
| reCAPTCHA v3 | `solver.recaptcha(sitekey, url, { version: 'v3' })` |
|
|
70
|
+
| reCAPTCHA v3 Enterprise | `solver.recaptcha(sitekey, url, { version: 'v3', enterprise: 1 })` |
|
|
71
|
+
| Cloudflare Turnstile (widget) | `solver.turnstile(sitekey, url)` |
|
|
72
|
+
| Cloudflare Turnstile (challenge page) | `solver.turnstile(sitekey, url, { data, pagedata })` |
|
|
73
|
+
|
|
74
|
+
---
|
|
75
|
+
|
|
76
|
+
## Documentation
|
|
77
|
+
|
|
78
|
+
| Guide | Description |
|
|
79
|
+
|---|---|
|
|
80
|
+
| [Tutorial](docs/TUTORIAL.md) | Complete walkthrough of every captcha type |
|
|
81
|
+
| [Getting Started](docs/GETTING_STARTED.md) | Full setup: CapSkip app, SDK install, first script |
|
|
82
|
+
| [API Reference](docs/API_REFERENCE.md) | All classes, methods, parameters, and return values |
|
|
83
|
+
| [Examples](examples/) | Ready-to-run scripts for every captcha type |
|
|
84
|
+
| [Troubleshooting](docs/TROUBLESHOOTING.md) | Connection errors, timeouts, proxy issues |
|
|
85
|
+
| [Contributing](CONTRIBUTING.md) | Development setup, tests, pull requests |
|
|
86
|
+
| [Changelog](CHANGELOG.md) | Release history |
|
|
87
|
+
|
|
88
|
+
---
|
|
89
|
+
|
|
90
|
+
## Configuration
|
|
91
|
+
|
|
92
|
+
```js
|
|
93
|
+
const { CapSkip } = require('capskip');
|
|
94
|
+
|
|
95
|
+
const solver = new CapSkip({
|
|
96
|
+
apiKey: 'capskip', // your CapSkip API key (or any string if validation is off)
|
|
97
|
+
host: '127.0.0.1', // CapSkip host
|
|
98
|
+
port: 8080, // CapSkip port from app settings
|
|
99
|
+
defaultTimeout: 120, // seconds — image captcha polling timeout
|
|
100
|
+
recaptchaTimeout: 300, // seconds — reCAPTCHA / Turnstile polling timeout
|
|
101
|
+
pollingInterval: 5, // max seconds between res.php polls (starts at 0.25s, backs off to this)
|
|
102
|
+
});
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
Use environment variables in production:
|
|
106
|
+
|
|
107
|
+
```bash
|
|
108
|
+
# Linux / macOS
|
|
109
|
+
export CAPSKIP_API_KEY="your-key"
|
|
110
|
+
export CAPSKIP_HOST="127.0.0.1"
|
|
111
|
+
export CAPSKIP_PORT="8080"
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
```powershell
|
|
115
|
+
# Windows PowerShell
|
|
116
|
+
$env:CAPSKIP_API_KEY = "your-key"
|
|
117
|
+
$env:CAPSKIP_HOST = "127.0.0.1"
|
|
118
|
+
$env:CAPSKIP_PORT = "8080"
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
```js
|
|
122
|
+
const { CapSkip } = require('capskip');
|
|
123
|
+
|
|
124
|
+
const solver = new CapSkip({
|
|
125
|
+
apiKey: process.env.CAPSKIP_API_KEY || 'capskip',
|
|
126
|
+
host: process.env.CAPSKIP_HOST || '127.0.0.1',
|
|
127
|
+
port: parseInt(process.env.CAPSKIP_PORT || '8080', 10),
|
|
128
|
+
});
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
---
|
|
132
|
+
|
|
133
|
+
## Usage examples
|
|
134
|
+
|
|
135
|
+
### Image captcha
|
|
136
|
+
|
|
137
|
+
```js
|
|
138
|
+
await solver.normal('captcha.png');
|
|
139
|
+
await solver.normal('https://example.com/captcha.jpg');
|
|
140
|
+
await solver.normal('data:image/png;base64,iVBORw0KGgo...');
|
|
141
|
+
// result.code holds the recognized text
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
### reCAPTCHA v2 / v3
|
|
145
|
+
|
|
146
|
+
```js
|
|
147
|
+
// reCAPTCHA v2
|
|
148
|
+
const v2 = await solver.recaptcha('...', 'https://example.com');
|
|
149
|
+
|
|
150
|
+
// reCAPTCHA v3
|
|
151
|
+
const v3 = await solver.recaptcha('...', 'https://example.com', {
|
|
152
|
+
version: 'v3',
|
|
153
|
+
action: 'submit',
|
|
154
|
+
score: 0.7,
|
|
155
|
+
});
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
### Cloudflare Turnstile
|
|
159
|
+
|
|
160
|
+
```js
|
|
161
|
+
const result = await solver.turnstile('0x4AAAAAAA...', 'https://example.com');
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
### With a proxy (reCAPTCHA & Turnstile only)
|
|
165
|
+
|
|
166
|
+
```js
|
|
167
|
+
// Proxy is not supported for image captcha
|
|
168
|
+
await solver.recaptcha('...', 'https://example.com', {
|
|
169
|
+
proxy: { type: 'HTTPS', uri: 'user:pass@1.2.3.4:3128' },
|
|
170
|
+
});
|
|
171
|
+
await solver.turnstile('...', 'https://example.com', {
|
|
172
|
+
proxy: { type: 'HTTP', uri: '1.2.3.4:3128' },
|
|
173
|
+
});
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
### Parallel solving
|
|
177
|
+
|
|
178
|
+
```js
|
|
179
|
+
const { CapSkip } = require('capskip');
|
|
180
|
+
|
|
181
|
+
async function main() {
|
|
182
|
+
const solver = new CapSkip();
|
|
183
|
+
const [r1, r2] = await Promise.all([
|
|
184
|
+
solver.recaptcha('...', 'https://a.com'),
|
|
185
|
+
solver.turnstile('...', 'https://b.com'),
|
|
186
|
+
]);
|
|
187
|
+
console.log(r1.code, r2.code);
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
main();
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
> `AsyncCapSkip` is exported as an alias of `CapSkip` — Node I/O is asynchronous by nature, so every method already returns a Promise.
|
|
194
|
+
|
|
195
|
+
More examples: [`examples/`](examples/)
|
|
196
|
+
|
|
197
|
+
---
|
|
198
|
+
|
|
199
|
+
## Return value
|
|
200
|
+
|
|
201
|
+
Every solve method resolves to:
|
|
202
|
+
|
|
203
|
+
```js
|
|
204
|
+
{
|
|
205
|
+
captchaId: '12345', // internal ID from CapSkip
|
|
206
|
+
code: 'TOKEN_OR_TEXT', // solution — text for image, token for reCAPTCHA/Turnstile
|
|
207
|
+
userAgent: '...', // Turnstile only — use when submitting challenge-page tokens
|
|
208
|
+
}
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
---
|
|
212
|
+
|
|
213
|
+
## Error handling
|
|
214
|
+
|
|
215
|
+
```js
|
|
216
|
+
const {
|
|
217
|
+
CapSkip, ValidationException, NetworkException, ApiException, TimeoutException,
|
|
218
|
+
} = require('capskip');
|
|
219
|
+
|
|
220
|
+
try {
|
|
221
|
+
const result = await solver.recaptcha('...', '...');
|
|
222
|
+
} catch (err) {
|
|
223
|
+
if (err instanceof ValidationException) {
|
|
224
|
+
// invalid parameters
|
|
225
|
+
} else if (err instanceof NetworkException) {
|
|
226
|
+
// CapSkip not running, or captcha not ready (manual polling)
|
|
227
|
+
} else if (err instanceof ApiException) {
|
|
228
|
+
// API returned an error code
|
|
229
|
+
} else if (err instanceof TimeoutException) {
|
|
230
|
+
// polling timeout exceeded
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
---
|
|
236
|
+
|
|
237
|
+
## TypeScript
|
|
238
|
+
|
|
239
|
+
Type definitions ship with the package — no `@types` install required.
|
|
240
|
+
|
|
241
|
+
```ts
|
|
242
|
+
import { CapSkip, SolveResult } from 'capskip';
|
|
243
|
+
|
|
244
|
+
const solver = new CapSkip({ host: '127.0.0.1', port: 8080 });
|
|
245
|
+
const result: SolveResult = await solver.recaptcha('...', 'https://example.com');
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
---
|
|
249
|
+
|
|
250
|
+
## Development
|
|
251
|
+
|
|
252
|
+
```bash
|
|
253
|
+
git clone https://github.com/capskip/capskip-node.git
|
|
254
|
+
cd capskip-node
|
|
255
|
+
npm install
|
|
256
|
+
npm test
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
The test suite uses Node's built-in test runner — no extra dependencies. See [CONTRIBUTING.md](CONTRIBUTING.md) for the full development workflow.
|
|
260
|
+
|
|
261
|
+
---
|
|
262
|
+
|
|
263
|
+
## Links
|
|
264
|
+
|
|
265
|
+
- [CapSkip website](https://capskip.com)
|
|
266
|
+
- [CapSkip API docs](https://capskip.com/api-docs/)
|
|
267
|
+
- [Report an issue](https://github.com/capskip/capskip-node/issues)
|
|
268
|
+
- [npm package](https://www.npmjs.com/package/capskip)
|
|
269
|
+
|
|
270
|
+
---
|
|
271
|
+
|
|
272
|
+
## License
|
|
273
|
+
|
|
274
|
+
MIT — see [LICENSE](LICENSE).
|
package/SECURITY.md
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# Security Policy
|
|
2
|
+
|
|
3
|
+
## Supported versions
|
|
4
|
+
|
|
5
|
+
| Version | Supported |
|
|
6
|
+
|---|---|
|
|
7
|
+
| 1.0.x | Yes |
|
|
8
|
+
|
|
9
|
+
## Reporting a vulnerability
|
|
10
|
+
|
|
11
|
+
If you discover a security vulnerability in the CapSkip Node.js SDK, please report it responsibly.
|
|
12
|
+
|
|
13
|
+
**Do not** open a public GitHub issue for security vulnerabilities.
|
|
14
|
+
|
|
15
|
+
Instead, email **support@capskip.com** with:
|
|
16
|
+
|
|
17
|
+
- Description of the vulnerability
|
|
18
|
+
- Steps to reproduce
|
|
19
|
+
- Potential impact
|
|
20
|
+
- Suggested fix (if any)
|
|
21
|
+
|
|
22
|
+
We aim to acknowledge reports within 48 hours and provide a status update within 7 days.
|
|
23
|
+
|
|
24
|
+
## Scope
|
|
25
|
+
|
|
26
|
+
This policy covers the `capskip` npm package in this repository.
|
|
27
|
+
|
|
28
|
+
The CapSkip desktop application itself is maintained separately — report app-level issues to CapSkip support.
|
|
29
|
+
|
|
30
|
+
## Best practices for SDK users
|
|
31
|
+
|
|
32
|
+
- Do not commit API keys or captcha tokens to version control
|
|
33
|
+
- Use environment variables for `CAPSKIP_API_KEY`
|
|
34
|
+
- CapSkip runs locally — ensure your firewall rules match your security requirements
|
|
35
|
+
- When using proxies, avoid logging credentials in application logs
|
|
@@ -0,0 +1,292 @@
|
|
|
1
|
+
# CapSkip API Reference
|
|
2
|
+
|
|
3
|
+
Complete reference aligned with the [official CapSkip API](https://capskip.com/api-docs/).
|
|
4
|
+
|
|
5
|
+
CapSkip exposes a standard captcha-solver HTTP API on your local machine:
|
|
6
|
+
|
|
7
|
+
```
|
|
8
|
+
POST http://<host>:<port>/in.php → submit captcha
|
|
9
|
+
GET http://<host>:<port>/res.php → poll result
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
The SDK only supports the four captcha types documented by CapSkip. Every solve
|
|
13
|
+
method returns a `Promise`.
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
## Supported captcha types
|
|
18
|
+
|
|
19
|
+
| Type | SDK method | `method` (POST) |
|
|
20
|
+
|---|---|---|
|
|
21
|
+
| Image captcha | `normal()` | `post` or `base64` |
|
|
22
|
+
| reCAPTCHA v2 | `recaptcha(sitekey, url)` | `userrecaptcha` |
|
|
23
|
+
| reCAPTCHA v3 | `recaptcha(sitekey, url, { version: 'v3' })` | `userrecaptcha` + `version=v3` |
|
|
24
|
+
| Cloudflare Turnstile | `turnstile()` | `turnstile` |
|
|
25
|
+
|
|
26
|
+
**Proxy** is supported for reCAPTCHA and Turnstile only — not for image captcha.
|
|
27
|
+
|
|
28
|
+
---
|
|
29
|
+
|
|
30
|
+
## CapSkip
|
|
31
|
+
|
|
32
|
+
```js
|
|
33
|
+
const { CapSkip } = require('capskip');
|
|
34
|
+
|
|
35
|
+
const solver = new CapSkip({
|
|
36
|
+
apiKey: 'capskip',
|
|
37
|
+
host: '127.0.0.1',
|
|
38
|
+
port: 8080,
|
|
39
|
+
defaultTimeout: 120,
|
|
40
|
+
recaptchaTimeout: 300,
|
|
41
|
+
pollingInterval: 5, // max seconds between polls; starts at 0.25s and backs off to this
|
|
42
|
+
});
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
`AsyncCapSkip` is exported as an alias of `CapSkip`.
|
|
46
|
+
|
|
47
|
+
---
|
|
48
|
+
|
|
49
|
+
## 1. Image captcha — `normal(file, { json })`
|
|
50
|
+
|
|
51
|
+
### POST `/in.php`
|
|
52
|
+
|
|
53
|
+
| Parameter | Type | Required | Description |
|
|
54
|
+
|---|---|---|---|
|
|
55
|
+
| `key` | string | Yes | CapSkip API key |
|
|
56
|
+
| `method` | string | Yes | `post` (multipart file) or `base64` |
|
|
57
|
+
| `file` | file | Yes* | Image file when `method=post` |
|
|
58
|
+
| `body` | string | Yes* | Base64 image when `method=base64` |
|
|
59
|
+
| `json` | int | No | `0` plain text (default), `1` JSON |
|
|
60
|
+
|
|
61
|
+
### GET `/res.php`
|
|
62
|
+
|
|
63
|
+
| Parameter | Type | Required | Description |
|
|
64
|
+
|---|---|---|---|
|
|
65
|
+
| `key` | string | Yes | CapSkip API key |
|
|
66
|
+
| `action` | string | Yes | `get` |
|
|
67
|
+
| `id` | int | Yes | Captcha ID from `in.php` |
|
|
68
|
+
| `json` | int | No | `0` plain text (default), `1` JSON |
|
|
69
|
+
|
|
70
|
+
### SDK usage
|
|
71
|
+
|
|
72
|
+
```js
|
|
73
|
+
await solver.normal('captcha.png');
|
|
74
|
+
await solver.normal('https://example.com/captcha.jpg');
|
|
75
|
+
const result = await solver.normal('data:image/png;base64,iVBORw0KGgo...', { json: 1 });
|
|
76
|
+
console.log(result.code);
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
Only `json` is accepted as an extra parameter. Proxy is **not** supported.
|
|
80
|
+
|
|
81
|
+
---
|
|
82
|
+
|
|
83
|
+
## 2. reCAPTCHA v2 — `recaptcha(sitekey, url, { ... })`
|
|
84
|
+
|
|
85
|
+
### POST `/in.php`
|
|
86
|
+
|
|
87
|
+
| Parameter | Type | Required | Default | Description |
|
|
88
|
+
|---|---|---|---|---|
|
|
89
|
+
| `key` | string | Yes | — | CapSkip API key |
|
|
90
|
+
| `method` | string | Yes | — | `userrecaptcha` |
|
|
91
|
+
| `googlekey` | string | Yes | — | Site key (`data-sitekey` / `k`) |
|
|
92
|
+
| `pageurl` | string | Yes | — | Full page URL |
|
|
93
|
+
| `enterprise` | int | No | `0` | `1` = Enterprise v2 |
|
|
94
|
+
| `invisible` | int | No | `0` | `1` = Invisible reCAPTCHA |
|
|
95
|
+
| `data-s` | string | No | — | Google Search / services `data-s` value |
|
|
96
|
+
| `json` | int | No | `0` | `1` = JSON response |
|
|
97
|
+
| `proxy` | string | No | — | `IP:PORT` or `login:pass@IP:PORT` |
|
|
98
|
+
| `proxytype` | string | No | `HTTP` | `HTTP`, `HTTPS`, `SOCKS5`, `SOCKS5H` |
|
|
99
|
+
|
|
100
|
+
Do **not** send `version`, `action`, or `min_score` for v2.
|
|
101
|
+
|
|
102
|
+
### GET `/res.php`
|
|
103
|
+
|
|
104
|
+
Same as image captcha poll parameters.
|
|
105
|
+
|
|
106
|
+
### SDK usage
|
|
107
|
+
|
|
108
|
+
```js
|
|
109
|
+
// Standard v2
|
|
110
|
+
await solver.recaptcha('...', 'https://example.com');
|
|
111
|
+
|
|
112
|
+
// Invisible v2
|
|
113
|
+
await solver.recaptcha('...', '...', { invisible: 1 });
|
|
114
|
+
|
|
115
|
+
// Enterprise v2
|
|
116
|
+
await solver.recaptcha('...', '...', { enterprise: 1 });
|
|
117
|
+
|
|
118
|
+
// Enterprise v2 with data-s (SDK alias: datas)
|
|
119
|
+
await solver.recaptcha('...', '...', { enterprise: 1, datas: '...' });
|
|
120
|
+
|
|
121
|
+
// With proxy
|
|
122
|
+
await solver.recaptcha('...', '...', {
|
|
123
|
+
proxy: { type: 'HTTPS', uri: 'user:pass@1.2.3.4:3128' },
|
|
124
|
+
});
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
---
|
|
128
|
+
|
|
129
|
+
## 3. reCAPTCHA v3 — `recaptcha(sitekey, url, { version: 'v3', ... })`
|
|
130
|
+
|
|
131
|
+
### POST `/in.php`
|
|
132
|
+
|
|
133
|
+
| Parameter | Type | Required | Default | Description |
|
|
134
|
+
|---|---|---|---|---|
|
|
135
|
+
| `key` | string | Yes | — | CapSkip API key |
|
|
136
|
+
| `method` | string | Yes | — | `userrecaptcha` |
|
|
137
|
+
| `version` | string | Yes | — | `v3` |
|
|
138
|
+
| `googlekey` | string | Yes | — | Site key |
|
|
139
|
+
| `pageurl` | string | Yes | — | Full page URL |
|
|
140
|
+
| `enterprise` | int | No | `0` | `1` = Enterprise v3 |
|
|
141
|
+
| `action` | string | No | `verify` | Action from `grecaptcha.execute()` |
|
|
142
|
+
| `min_score` | float | No | `0.4` | Minimum acceptable score |
|
|
143
|
+
| `json` | int | No | `0` | `1` = JSON response |
|
|
144
|
+
| `proxy` | string | No | — | Proxy address |
|
|
145
|
+
| `proxytype` | string | No | `HTTP` | Proxy type |
|
|
146
|
+
|
|
147
|
+
Do **not** send `invisible` for v3.
|
|
148
|
+
|
|
149
|
+
### SDK usage
|
|
150
|
+
|
|
151
|
+
```js
|
|
152
|
+
await solver.recaptcha('...', 'https://example.com', {
|
|
153
|
+
version: 'v3',
|
|
154
|
+
action: 'submit',
|
|
155
|
+
min_score: 0.7, // or SDK alias: score: 0.7
|
|
156
|
+
enterprise: 0,
|
|
157
|
+
});
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
---
|
|
161
|
+
|
|
162
|
+
## 4. Cloudflare Turnstile — `turnstile(sitekey, url, { ... })`
|
|
163
|
+
|
|
164
|
+
### POST `/in.php`
|
|
165
|
+
|
|
166
|
+
| Parameter | Type | Required | Description |
|
|
167
|
+
|---|---|---|---|
|
|
168
|
+
| `key` | string | Yes | CapSkip API key |
|
|
169
|
+
| `method` | string | Yes | `turnstile` |
|
|
170
|
+
| `sitekey` | string | Yes | Turnstile sitekey |
|
|
171
|
+
| `pageurl` | string | Yes | Full page URL |
|
|
172
|
+
| `action` | string | No | From `data-action` or `turnstile.render()` |
|
|
173
|
+
| `data` | string | No | `cData` / `data-cdata` |
|
|
174
|
+
| `pagedata` | string | No | `chlPageData` (challenge pages) |
|
|
175
|
+
| `json` | int | No | `0` plain text, `1` JSON |
|
|
176
|
+
| `proxy` | string | No | Proxy address |
|
|
177
|
+
| `proxytype` | string | No | Proxy type |
|
|
178
|
+
|
|
179
|
+
### GET `/res.php`
|
|
180
|
+
|
|
181
|
+
| Parameter | Type | Required | Description |
|
|
182
|
+
|---|---|---|---|
|
|
183
|
+
| `key` | string | Yes | CapSkip API key |
|
|
184
|
+
| `action` | string | Yes | `get` |
|
|
185
|
+
| `id` | int | Yes | Captcha ID |
|
|
186
|
+
| `json` | int | **Yes** | Must be `1` to receive User-Agent |
|
|
187
|
+
|
|
188
|
+
The SDK **automatically** polls Turnstile results with `json=1` and includes `userAgent` in the result when CapSkip returns it.
|
|
189
|
+
|
|
190
|
+
### SDK usage
|
|
191
|
+
|
|
192
|
+
```js
|
|
193
|
+
// Standalone widget
|
|
194
|
+
const result = await solver.turnstile('0x4AAAAAAA...', 'https://example.com');
|
|
195
|
+
console.log(result.code);
|
|
196
|
+
console.log(result.userAgent); // present when CapSkip returns it
|
|
197
|
+
|
|
198
|
+
// Challenge page
|
|
199
|
+
const challenge = await solver.turnstile('0x4AAAAAAA...', 'https://example.com', {
|
|
200
|
+
action: 'managed',
|
|
201
|
+
data: 'cData_value',
|
|
202
|
+
pagedata: 'chlPageData_value',
|
|
203
|
+
});
|
|
204
|
+
// Use challenge.userAgent when submitting the token
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
---
|
|
208
|
+
|
|
209
|
+
## Return value
|
|
210
|
+
|
|
211
|
+
Every solve method resolves to:
|
|
212
|
+
|
|
213
|
+
```js
|
|
214
|
+
{
|
|
215
|
+
captchaId: '12345',
|
|
216
|
+
code: 'TOKEN_OR_TEXT',
|
|
217
|
+
userAgent: '...', // Turnstile only, when json=1 poll includes it
|
|
218
|
+
}
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
---
|
|
222
|
+
|
|
223
|
+
## SDK parameter aliases
|
|
224
|
+
|
|
225
|
+
Convenience aliases mapped before sending to CapSkip:
|
|
226
|
+
|
|
227
|
+
| SDK alias | CapSkip API param |
|
|
228
|
+
|---|---|
|
|
229
|
+
| `url` | `pageurl` |
|
|
230
|
+
| `score` | `min_score` |
|
|
231
|
+
| `minScore` | `min_score` |
|
|
232
|
+
| `datas` | `data-s` |
|
|
233
|
+
| `data_s` | `data-s` |
|
|
234
|
+
| `proxy` object | `proxy` + `proxytype` strings |
|
|
235
|
+
|
|
236
|
+
```js
|
|
237
|
+
const proxy = { type: 'HTTPS', uri: 'login:password@1.2.3.4:3128' };
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
Unsupported parameters (e.g. `numeric` on image captcha, `action` on v2) throw `ValidationException`.
|
|
241
|
+
|
|
242
|
+
---
|
|
243
|
+
|
|
244
|
+
## Manual workflow
|
|
245
|
+
|
|
246
|
+
### `send(params)`
|
|
247
|
+
|
|
248
|
+
Submit without polling. Resolves to the captcha ID string.
|
|
249
|
+
|
|
250
|
+
```js
|
|
251
|
+
const captchaId = await solver.send({
|
|
252
|
+
method: 'userrecaptcha',
|
|
253
|
+
googlekey: '...',
|
|
254
|
+
pageurl: 'https://example.com',
|
|
255
|
+
});
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
### `getResult(id, json = 0)`
|
|
259
|
+
|
|
260
|
+
Poll once. Rejects with `NetworkException` while `CAPCHA_NOT_READY`.
|
|
261
|
+
|
|
262
|
+
```js
|
|
263
|
+
const { NetworkException } = require('capskip');
|
|
264
|
+
|
|
265
|
+
const code = await solver.getResult(captchaId); // plain text
|
|
266
|
+
const data = await solver.getResult(captchaId, 1); // object when json=1
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
---
|
|
270
|
+
|
|
271
|
+
## Low-level HTTP (ApiClient)
|
|
272
|
+
|
|
273
|
+
```js
|
|
274
|
+
const { ApiClient } = require('capskip');
|
|
275
|
+
|
|
276
|
+
const client = new ApiClient({ host: '127.0.0.1', port: 8080 });
|
|
277
|
+
await client.in_({ method: 'turnstile', key: 'capskip', sitekey: '...', pageurl: '...' });
|
|
278
|
+
await client.res({ key: 'capskip', action: 'get', id: '12345', json: 1 });
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
---
|
|
282
|
+
|
|
283
|
+
## Exceptions
|
|
284
|
+
|
|
285
|
+
| Exception | When |
|
|
286
|
+
|---|---|
|
|
287
|
+
| `ValidationException` | Invalid/unsupported parameters |
|
|
288
|
+
| `NetworkException` | Connection error, or captcha not ready |
|
|
289
|
+
| `ApiException` | CapSkip API error response |
|
|
290
|
+
| `TimeoutException` | Polling timeout exceeded |
|
|
291
|
+
|
|
292
|
+
All extend `CapSkipError`, so `catch (err) { if (err instanceof CapSkipError) ... }` catches them all.
|