-
Notifications
You must be signed in to change notification settings - Fork 34
/
index.js
140 lines (125 loc) · 3.22 KB
/
index.js
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
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
const request = require('request-promise-native');
const Url = require('url');
const vm = require('vm');
const {
randomFromRange,
randomTrueFalse,
delay,
uuid,
getRandomUserAgent
} = require('./src/utils');
function getMouseMovements(timestamp) {
let lastMovement = timestamp;
const motionCount = randomFromRange(1000, 10000);
const mouseMovements = [];
for (let i = 0; i < motionCount; i++) {
lastMovement += randomFromRange(0, 10);
mouseMovements.push([randomFromRange(0, 500), randomFromRange(0, 500), lastMovement]);
}
return mouseMovements;
}
async function hsl(req) {
const hsl = await request.get('https://assets.hcaptcha.com/c/500c658/hsl.js');
return new Promise((resolve, reject) => {
const code = `
var self = {};
function atob(a) {
return new Buffer(a, 'base64').toString('binary');
}
${hsl}
hsl('${req}').then(resolve).catch(reject)
`;
vm.runInNewContext(code, {
Buffer,
resolve,
reject,
});
});
}
async function tryToSolve(sitekey, host) {
const userAgent = getRandomUserAgent();
const headers = {
'User-Agent': userAgent
};
let response = await request({
method: 'get',
headers,
json: true,
url: `https://hcaptcha.com/checksiteconfig?host=${host}&sitekey=${sitekey}&sc=1&swa=0`
});
let timestamp = Date.now() + randomFromRange(30, 120);
response = await request({
method: 'post',
headers,
json: true,
url: 'https://hcaptcha.com/getcaptcha',
form: {
sitekey,
host,
n: await hsl(response.c.req),
c: JSON.stringify(response.c),
motionData: {
st: timestamp,
dct: timestamp,
mm: getMouseMovements(timestamp)
}
}
});
if (response.generated_pass_UUID) {
return response.generated_pass_UUID;
}
const key = response.key;
const tasks = response.tasklist;
const job = response.request_type;
timestamp = Date.now() + randomFromRange(30, 120);
const answers = tasks.reduce((accum, t) => ({ ...accum, [t.task_key]: randomTrueFalse() }), {});
const captchaResponse = {
answers,
sitekey,
serverdomain: host,
job_mode: job,
motionData: {
st: timestamp,
dct: timestamp,
mm: getMouseMovements(timestamp)
}
};
response = await request(`https://hcaptcha.com/checkcaptcha/${key}`, {
method: 'post',
headers,
json: true,
form: captchaResponse
});
if (response.generated_pass_UUID) {
return response.generated_pass_UUID;
}
}
async function solveCaptcha(url, options = {}) {
const { gentleMode, timeoutInMs = 12000000 } = options;
const { hostname } = Url.parse(url);
const siteKey = uuid();
const startingTime = Date.now();
while (true) {
try {
const result = await tryToSolve(siteKey, hostname);
if (result) {
return result;
}
} catch (e) {
if (e.statusCode === 429) {
// reached rate limit, wait 30 sec
await delay(30000);
} else {
throw e;
}
}
if (Date.now() - startingTime > timeoutInMs) {
throw new Error('captcha resolution timeout');
}
if (gentleMode) {
// wait a bit to avoid rate limit errors
delay(3000);
}
}
}
module.exports = solveCaptcha;