Add solver
This commit is contained in:
@@ -0,0 +1,34 @@
|
||||
# dependencies (bun install)
|
||||
node_modules
|
||||
|
||||
# output
|
||||
out
|
||||
dist
|
||||
*.tgz
|
||||
|
||||
# code coverage
|
||||
coverage
|
||||
*.lcov
|
||||
|
||||
# logs
|
||||
logs
|
||||
_.log
|
||||
report.[0-9]_.[0-9]_.[0-9]_.[0-9]_.json
|
||||
|
||||
# dotenv environment variable files
|
||||
.env
|
||||
.env.development.local
|
||||
.env.test.local
|
||||
.env.production.local
|
||||
.env.local
|
||||
|
||||
# caches
|
||||
.eslintcache
|
||||
.cache
|
||||
*.tsbuildinfo
|
||||
|
||||
# IntelliJ based IDEs
|
||||
.idea
|
||||
|
||||
# Finder (MacOS) folder config
|
||||
.DS_Store
|
||||
@@ -0,0 +1,15 @@
|
||||
# solver
|
||||
|
||||
To install dependencies:
|
||||
|
||||
```bash
|
||||
bun install
|
||||
```
|
||||
|
||||
To run:
|
||||
|
||||
```bash
|
||||
bun run index.js
|
||||
```
|
||||
|
||||
This project was created using `bun init` in bun v1.2.9. [Bun](https://bun.sh) is a fast all-in-one JavaScript runtime.
|
||||
@@ -0,0 +1,32 @@
|
||||
{
|
||||
"lockfileVersion": 1,
|
||||
"workspaces": {
|
||||
"": {
|
||||
"name": "solver",
|
||||
"dependencies": {
|
||||
"@cap.js/solver": "latest",
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/bun": "latest",
|
||||
},
|
||||
"peerDependencies": {
|
||||
"typescript": "^5",
|
||||
},
|
||||
},
|
||||
},
|
||||
"packages": {
|
||||
"@cap.js/solver": ["@cap.js/solver@0.0.2", "", {}, "sha512-DMEth1+iQgRDHibb4alEeYhV32lRpGVkiIVXk9tS7s8So6CV8Gd1U+/KWqB+k7K6yHUqWzRkVQP7INOLUTyqlA=="],
|
||||
|
||||
"@types/bun": ["@types/bun@1.2.9", "", { "dependencies": { "bun-types": "1.2.9" } }, "sha512-epShhLGQYc4Bv/aceHbmBhOz1XgUnuTZgcxjxk+WXwNyDXavv5QHD1QEFV0FwbTSQtNq6g4ZcV6y0vZakTjswg=="],
|
||||
|
||||
"@types/node": ["@types/node@22.14.1", "", { "dependencies": { "undici-types": "~6.21.0" } }, "sha512-u0HuPQwe/dHrItgHHpmw3N2fYCR6x4ivMNbPHRkBVP4CvN+kiRrKHWk3i8tXiO/joPwXLMYvF9TTF0eqgHIuOw=="],
|
||||
|
||||
"@types/ws": ["@types/ws@8.18.1", "", { "dependencies": { "@types/node": "*" } }, "sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg=="],
|
||||
|
||||
"bun-types": ["bun-types@1.2.9", "", { "dependencies": { "@types/node": "*", "@types/ws": "*" } }, "sha512-dk/kOEfQbajENN/D6FyiSgOKEuUi9PWfqKQJEgwKrCMWbjS/S6tEXp178mWvWAcUSYm9ArDlWHZKO3T/4cLXiw=="],
|
||||
|
||||
"typescript": ["typescript@5.8.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ=="],
|
||||
|
||||
"undici-types": ["undici-types@6.21.0", "", {}, "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ=="],
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
import solver from "@cap.js/solver";
|
||||
|
||||
const CHALLENGES = [
|
||||
["e455cea65e98bc3c36287f43769da211", "dceb"],
|
||||
["fb8d25f6abac5aa9b6360051f37e010b", "93f1"],
|
||||
["91ef47db578fbeb2565d3f9c82bb7960", "3698"],
|
||||
["b7ad7667486a691cda8ef297098f64a7", "d72a"],
|
||||
["1aca3fb7cef7a2be0dee563ed4136758", "3b58"],
|
||||
["d9ec39af92b430e5a329274d8aa58fa8", "e1d3"],
|
||||
["781a3cc9217d73c908a321d3fdabd62f", "22c6"],
|
||||
["e37a0752c9ac2f3d2517747fde373ac9", "f6f1"],
|
||||
["bba070197569f322beda5b240f639a95", "4751"],
|
||||
["89297515aeac646bee9653ba405e0beb", "a7de"],
|
||||
["444571a0d5039c15be6141d6cd8434f9", "a783"],
|
||||
["ba75f2bf8e9b92cc32caa17237a52d14", "7e30"],
|
||||
["22bfc18ba8e3ecee080c5d1ef64ed6e9", "5fcf"],
|
||||
["885fb78ff76b4eddd2f5bc04ac5ee673", "93e5"],
|
||||
["308758072931bb3b254a7b1ed351d04a", "3e49"],
|
||||
["724f89bb167db4b881e1dc7b0949ac8f", "b82e"],
|
||||
["8b79506e4630de15be225c18623eff65", "f0e5"],
|
||||
["0c21ade6e63a4e37b13cb8b087f31863", "65c9"],
|
||||
];
|
||||
|
||||
console.log(await solver(CHALLENGES));
|
||||
@@ -0,0 +1,28 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
// Environment setup & latest features
|
||||
"lib": ["ESNext"],
|
||||
"target": "ESNext",
|
||||
"module": "ESNext",
|
||||
"moduleDetection": "force",
|
||||
"jsx": "react-jsx",
|
||||
"allowJs": true,
|
||||
|
||||
// Bundler mode
|
||||
"moduleResolution": "bundler",
|
||||
"allowImportingTsExtensions": true,
|
||||
"verbatimModuleSyntax": true,
|
||||
"noEmit": true,
|
||||
|
||||
// Best practices
|
||||
"strict": true,
|
||||
"skipLibCheck": true,
|
||||
"noFallthroughCasesInSwitch": true,
|
||||
"noUncheckedIndexedAccess": true,
|
||||
|
||||
// Some stricter flags (disabled by default)
|
||||
"noUnusedLocals": false,
|
||||
"noUnusedParameters": false,
|
||||
"noPropertyAccessFromIndexSignature": false
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"name": "solver",
|
||||
"module": "index.js",
|
||||
"type": "module",
|
||||
"private": true,
|
||||
"devDependencies": {
|
||||
"@types/bun": "latest"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"typescript": "^5"
|
||||
},
|
||||
"dependencies": {
|
||||
"@cap.js/solver": "latest"
|
||||
}
|
||||
}
|
||||
@@ -33,7 +33,8 @@ export default defineConfig({
|
||||
text: 'Libraries',
|
||||
items: [
|
||||
{ text: '@cap.js/server', link: '/guide/server.md' },
|
||||
{ text: '@cap.js/widget', link: '/guide/widget.md' }
|
||||
{ text: '@cap.js/widget', link: '/guide/widget.md' },
|
||||
{ text: '@cap.js/solver', link: '/guide/solver.md' }
|
||||
]
|
||||
},
|
||||
{ text: "Demo", link: "https://cap-starter.glitch.me/" },
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
# @cap.js/solver
|
||||
|
||||
`@cap.js/solver` is a standalone library that can be used to solve Cap challenges from the server. It's extremely simple (no dependencies, one single file) yet very fast and efficient. Note that it can only be used with Bun.
|
||||
|
||||
## Installation
|
||||
|
||||
```bash
|
||||
bun add @cap.js/solver
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
```js
|
||||
import solver from "@cap.js/solver";
|
||||
|
||||
const CHALLENGES = [
|
||||
["a5b6fda4aaed97cf61d7dd9259f733b5", "d455"],
|
||||
["286bcc39249f9ee698314b600c32e40f", "f0ff"],
|
||||
["501350aa7c46573cb604284554045703", "4971"],
|
||||
["a55c02f3b9b4cd088a5a7ee3d4941c14", "eab7"],
|
||||
["5f3362c12e2779f56f4ef75b4494f5e6", "999f"],
|
||||
/* ... */
|
||||
];
|
||||
|
||||
console.log(await solver(CHALLENGES));
|
||||
```
|
||||
|
||||
**Output:**
|
||||
|
||||
```json
|
||||
[
|
||||
["a5b6fda4aaed97cf61d7dd9259f733b5", "d455", 67302],
|
||||
["286bcc39249f9ee698314b600c32e40f", "f0ff", 64511],
|
||||
["501350aa7c46573cb604284554045703", "4971", 40440],
|
||||
["a55c02f3b9b4cd088a5a7ee3d4941c14", "eab7", 27959],
|
||||
["5f3362c12e2779f56f4ef75b4494f5e6", "999f", 71259],
|
||||
...
|
||||
]
|
||||
```
|
||||
@@ -0,0 +1,2 @@
|
||||
# Server solver for the Cap CAPTCHA
|
||||
See [https://cap.tiagorangel.com](https://cap.tiagorangel.com)
|
||||
@@ -0,0 +1,24 @@
|
||||
import solver from "./index.js";
|
||||
|
||||
const CHALLENGES = [
|
||||
["e455cea65e98bc3c36287f43769da211", "dceb"],
|
||||
["fb8d25f6abac5aa9b6360051f37e010b", "93f1"],
|
||||
["91ef47db578fbeb2565d3f9c82bb7960", "3698"],
|
||||
["b7ad7667486a691cda8ef297098f64a7", "d72a"],
|
||||
["1aca3fb7cef7a2be0dee563ed4136758", "3b58"],
|
||||
["d9ec39af92b430e5a329274d8aa58fa8", "e1d3"],
|
||||
["781a3cc9217d73c908a321d3fdabd62f", "22c6"],
|
||||
["e37a0752c9ac2f3d2517747fde373ac9", "f6f1"],
|
||||
["bba070197569f322beda5b240f639a95", "4751"],
|
||||
["89297515aeac646bee9653ba405e0beb", "a7de"],
|
||||
["444571a0d5039c15be6141d6cd8434f9", "a783"],
|
||||
["ba75f2bf8e9b92cc32caa17237a52d14", "7e30"],
|
||||
["22bfc18ba8e3ecee080c5d1ef64ed6e9", "5fcf"],
|
||||
["885fb78ff76b4eddd2f5bc04ac5ee673", "93e5"],
|
||||
["308758072931bb3b254a7b1ed351d04a", "3e49"],
|
||||
["724f89bb167db4b881e1dc7b0949ac8f", "b82e"],
|
||||
["8b79506e4630de15be225c18623eff65", "f0e5"],
|
||||
["0c21ade6e63a4e37b13cb8b087f31863", "65c9"],
|
||||
];
|
||||
|
||||
console.log(await solver(CHALLENGES));
|
||||
@@ -0,0 +1,92 @@
|
||||
import { Worker } from "worker_threads";
|
||||
import os from "os";
|
||||
|
||||
const workerBlob = new Blob(
|
||||
[
|
||||
`
|
||||
import crypto from "crypto";
|
||||
import { parentPort, workerData } from "worker_threads";
|
||||
|
||||
const { salt, target } = workerData;
|
||||
|
||||
const saltBuffer = Buffer.from(salt);
|
||||
const targetLen = target.length;
|
||||
const targetBytes = Math.ceil(targetLen / 2);
|
||||
|
||||
let nonce = 0;
|
||||
|
||||
while (true) {
|
||||
const nonceStr = nonce.toString();
|
||||
|
||||
const hash = crypto.createHash("sha256");
|
||||
|
||||
hash.update(saltBuffer);
|
||||
hash.update(nonceStr);
|
||||
|
||||
const hashBuffer = hash.digest();
|
||||
|
||||
const hashPrefixHex = hashBuffer.toString("hex", 0, targetBytes);
|
||||
|
||||
if (hashPrefixHex.startsWith(target)) {
|
||||
parentPort.postMessage({
|
||||
nonce: Number(nonce),
|
||||
salt,
|
||||
target,
|
||||
});
|
||||
break;
|
||||
}
|
||||
|
||||
nonce++;
|
||||
}`,
|
||||
],
|
||||
{
|
||||
type: "application/typescript",
|
||||
}
|
||||
);
|
||||
const workerUrl = URL.createObjectURL(workerBlob);
|
||||
|
||||
export default function solver(challenges, config) {
|
||||
const totalChallenges = challenges.length;
|
||||
const numWorkers =
|
||||
config?.workerCount || Math.min(totalChallenges, 14, os.cpus().length);
|
||||
|
||||
let challengesProcessed = 0;
|
||||
let nextChallengeIndex = 0;
|
||||
let activeWorkers = 0;
|
||||
const results = [];
|
||||
|
||||
return new Promise((resolve) => {
|
||||
function startWorker() {
|
||||
if (nextChallengeIndex < totalChallenges && activeWorkers < numWorkers) {
|
||||
const currentChallengeIndex = nextChallengeIndex;
|
||||
const [salt, target] = challenges[currentChallengeIndex];
|
||||
nextChallengeIndex++;
|
||||
activeWorkers++;
|
||||
|
||||
const worker = new Worker(workerUrl, {
|
||||
workerData: { salt, target, challengeIndex: currentChallengeIndex },
|
||||
});
|
||||
|
||||
worker.on("message", (result) => {
|
||||
results.push([result.salt, result.target, result.nonce]);
|
||||
challengesProcessed++;
|
||||
activeWorkers--;
|
||||
|
||||
if (challengesProcessed === totalChallenges) {
|
||||
resolve(results);
|
||||
} else {
|
||||
startWorker();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
for (let i = 0; i < numWorkers; i++) {
|
||||
startWorker();
|
||||
}
|
||||
|
||||
if (totalChallenges === 0) {
|
||||
resolve([]);
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
{
|
||||
"name": "@cap.js/solver",
|
||||
"version": "0.0.2",
|
||||
"description": "Server-side solver for Cap's SHA-256 PoW captchas",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"test": "bun ./example.js",
|
||||
"npm:publish": "npm publish --access public"
|
||||
},
|
||||
"author": "Tiago",
|
||||
"license": "AGPL-3.0-or-later",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/tiagorangel1/cap.git"
|
||||
},
|
||||
"keywords": [
|
||||
"captcha",
|
||||
"recaptcha"
|
||||
],
|
||||
"bugs": {
|
||||
"url": "https://github.com/tiagorangel1/cap/issues"
|
||||
},
|
||||
"homepage": "https://github.com/tiagorangel1/cap#readme"
|
||||
}
|
||||
Reference in New Issue
Block a user