Bycf / server.js
maylinejix's picture
Update server.js
ca6cabd verified
Raw History Blame Contribute Delete
11 kB
const express = require('express');
const cors = require('cors');
const app = express();
const PORT = process.env.PORT || 7860;
const API_BASE = 'http://172.235.245.114:1875';
const THEYKA_BASE = 'http://172.235.245.114:1808';
app.use(cors());
app.use(express.json());
async function submitJob(code) {
const response = await fetch(`${API_BASE}/api/s-playwright`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ code, lang: 'python' })
});
if (!response.ok) throw new Error(`API error: ${response.status}`);
const result = await response.json();
if (!result.success) throw new Error(result.error || 'Failed to submit job');
return result.job_id;
}
async function pollJob(jobId, maxWaitTime = 300000) {
const start = Date.now();
while (Date.now() - start < maxWaitTime) {
const r = await fetch(`${API_BASE}/job/${jobId}`);
if (!r.ok) throw new Error(`Status check failed: ${r.status}`);
const data = await r.json();
if (!data.success) throw new Error(data.error || 'Status check error');
const job = data.job;
if (job.status === 'completed') return job.result;
if (job.status === 'failed') throw new Error(job.error || 'Job failed');
await new Promise(resolve => setTimeout(resolve, 1000));
}
throw new Error('Timeout');
}
async function solveWithTheyka(url, sitekey, action, cdata) {
let endpoint = `${THEYKA_BASE}/turnstile?url=${encodeURIComponent(url)}&sitekey=${encodeURIComponent(sitekey)}`;
if (action) endpoint += `&action=${encodeURIComponent(action)}`;
if (cdata) endpoint += `&cdata=${encodeURIComponent(cdata)}`;
const submitRes = await fetch(endpoint);
if (!submitRes.ok) throw new Error(`Theyka submit error: ${submitRes.status}`);
const submitData = await submitRes.json();
const task_id = submitData.task_id;
if (!task_id) throw new Error('Theyka: no task_id returned');
console.log(`[THEYKA] task_id=${task_id}`);
const start = Date.now();
while (Date.now() - start < 60000) {
await new Promise(resolve => setTimeout(resolve, 2000));
const resultRes = await fetch(`${THEYKA_BASE}/result?id=${task_id}`);
if (!resultRes.ok) continue;
const raw = await resultRes.text();
let data;
try {
data = JSON.parse(raw);
} catch {
if (raw.trim() === 'CAPTCHA_NOT_READY') continue;
throw new Error(`Theyka unexpected: ${raw.slice(0, 100)}`);
}
if (data?.value === 'CAPTCHA_FAIL') throw new Error('Theyka: CAPTCHA_FAIL');
if (data?.value && data.value !== 'CAPTCHA_NOT_READY') {
console.log(`[THEYKA] token ok elapsed=${data.elapsed_time}s`);
return { token: data.value, elapsed_ms: Math.round((data.elapsed_time || 0) * 1000) };
}
}
throw new Error('Theyka: timeout');
}
app.post('/bycf', async (req, res) => {
try {
const { url, sitekey, action = null, cdata = null } = req.body;
if (!url || !sitekey) {
return res.status(400).json({ author: 'Herza', status: 400, data: { error: 'URL and SITEKEY are required' } });
}
const t = Date.now();
const isInvisible = sitekey.includes('_') || sitekey.includes('-');
console.log(`[BYCF] url=${url} sitekey=${sitekey} isInvisible=${isInvisible}`);
if (isInvisible) {
const { token, elapsed_ms } = await solveWithTheyka(url, sitekey, action, cdata);
return res.json({ author: 'Herza', status: 200, data: { token, sitekey, url, action, cdata, cookies: {}, elapsed_ms } });
}
const esc = (s) => s ? s.replace(/'/g, "\\'") : null;
const a = esc(action);
const c = esc(cdata);
const urlWithSlash = url.endsWith('/') ? url : url + '/';
const actionAttr = a ? ` data-action="${a}"` : '';
const cdataAttr = c ? ` data-cdata="${c}"` : '';
const htmlB64 = Buffer.from(`<!DOCTYPE html><html><head><meta charset="UTF-8"><title>T</title><script>window.__cfToken=null;function cfCallback(t){window.__cfToken=t;}<\/script><script src="https://challenges.cloudflare.com/turnstile/v0/api.js" async defer><\/script></head><body><div class="cf-turnstile" data-sitekey="${sitekey}" data-callback="cfCallback"${actionAttr}${cdataAttr}></div></body></html>`).toString('base64');
const code = `import random,time,base64
ctx=browser.new_context(viewport={'width':1920,'height':1080},ignore_https_errors=True)
p=ctx.new_page()
try:
html_body=base64.b64decode('${htmlB64}').decode('utf-8')
p.route('${urlWithSlash}',lambda route:route.fulfill(body=html_body,status=200,content_type='text/html'))
p.goto('${urlWithSlash}',wait_until='domcontentloaded',timeout=20000)
time.sleep(2)
tk=None
for i in range(60):
try:
tk=p.evaluate('window.__cfToken')
if tk and len(tk)>50:break
tk=None
inp=p.query_selector('input[name="cf-turnstile-response"]')
if inp:
v=inp.get_attribute('value')
if v and len(v)>50:
tk=v
break
if not tk:
div=p.query_selector('div.cf-turnstile')
if div:
b=div.bounding_box()
if b:
x=b['x']+b['width']/2
y=b['y']+b['height']/2
p.mouse.move(x+random.randint(-10,10),y+random.randint(-10,10))
time.sleep(0.2)
p.mouse.click(x,y)
except:pass
time.sleep(0.3)
if not tk:raise Exception('No token')
ck={c['name']:c['value'] for c in p.context.cookies()}
return_value={'success':True,'token':tk,'sitekey':'${sitekey}','url':'${url}','action':${a ? `'${a}'` : 'None'},'cdata':${c ? `'${c}'` : 'None'},'cookies':ck,'elapsed_ms':int((time.time()*1000)-${t})}
except Exception as e:
return_value={'success':False,'error':str(e)}`;
const jobId = await submitJob(code);
const result = await pollJob(jobId);
if (!result.success) return res.status(500).json({ author: 'Herza', status: 500, data: { error: result.error } });
res.json({ author: 'Herza', status: 200, data: { token: result.token, sitekey: result.sitekey, url: result.url, action: result.action, cdata: result.cdata, cookies: result.cookies, elapsed_ms: result.elapsed_ms } });
} catch (error) {
console.error(`[BYCF] Error: ${error.message}`);
res.status(500).json({ author: 'Herza', status: 500, data: { error: error.message } });
}
});
app.post('/wafsource', async (req, res) => {
try {
const { url } = req.body;
if (!url) return res.status(400).json({ author: 'Herza', status: 400, data: { error: 'URL is required' } });
const startTime = Date.now();
const code = `import random,math
ctx=browser.new_context(viewport={'width':1920,'height':1080},ignore_https_errors=True)
p=ctx.new_page()
time.sleep(0.5)
try:
p.goto('${url}',wait_until='domcontentloaded',timeout=60000)
time.sleep(7)
pg=p.content()
has_cf='cloudflare' in pg.lower() or 'cf-wrapper' in pg.lower()
if has_cf:
for _ in range(random.randint(3,5)):
p.evaluate(f'window.scrollTo(0,{random.randint(50,150)})')
time.sleep(random.uniform(0.4,0.8))
p.evaluate('window.scrollTo(0,0)')
time.sleep(random.uniform(1.0,2.0))
sx,sy=random.randint(100,300),random.randint(100,300)
tx,ty=545,290
d=math.sqrt((tx-sx)**2+(ty-sy)**2)
st=max(15,min(int(d/random.uniform(3,6)),40))
for i in range(st):
t=(i+1)/st
et=t*t*(3-2*t)
bx=(sx+tx)/2+random.uniform(-30,30)
by=(sy+ty)/2+random.uniform(-30,30)
nx=(1-et)**2*sx+2*(1-et)*et*bx+et**2*tx
ny=(1-et)**2*sy+2*(1-et)*et*by+et**2*ty
p.mouse.move(nx,ny)
time.sleep(random.uniform(0.015,0.040))
p.mouse.move(tx,ty)
time.sleep(random.uniform(0.3,0.6))
p.mouse.down()
time.sleep(random.uniform(0.12,0.18))
p.mouse.up()
time.sleep(11)
try:p.wait_for_load_state('networkidle',timeout=10000)
except:pass
time.sleep(5)
fu=p.url
html=p.content()
title=p.title()
ck={c['name']:c['value'] for c in p.context.cookies()}
return_value={'success':True,'url':fu,'html':html,'title':title,'cookies':ck,'had_cloudflare':has_cf,'ms':int((time.time()*1000)-${startTime})}
except Exception as e:
return_value={'success':False,'error':str(e)}`;
const jobId = await submitJob(code);
const result = await pollJob(jobId, 300000);
if (!result.success) return res.status(500).json({ author: 'Herza', status: 500, data: { error: result.error } });
res.json({ author: 'Herza', status: 200, data: { url: result.url, html: result.html, title: result.title, cookies: result.cookies, had_cloudflare: result.had_cloudflare, elapsed_ms: result.ms } });
} catch (error) {
res.status(500).json({ author: 'Herza', status: 500, data: { error: error.message } });
}
});
app.post('/wafsessions', async (req, res) => {
try {
const { url } = req.body;
if (!url) return res.status(400).json({ author: 'Herza', status: 400, data: { error: 'URL is required' } });
const startTime = Date.now();
const code = `import random,math
ctx=browser.new_context(viewport={'width':1920,'height':1080},ignore_https_errors=True)
p=ctx.new_page()
time.sleep(0.5)
try:
p.goto('${url}',wait_until='domcontentloaded',timeout=60000)
time.sleep(7)
pg=p.content()
has_cf='cloudflare' in pg.lower() or 'cf-wrapper' in pg.lower()
if has_cf:
for _ in range(random.randint(3,5)):
p.evaluate(f'window.scrollTo(0,{random.randint(50,150)})')
time.sleep(random.uniform(0.4,0.8))
p.evaluate('window.scrollTo(0,0)')
time.sleep(random.uniform(1.0,2.0))
sx,sy=random.randint(100,300),random.randint(100,300)
tx,ty=545,290
d=math.sqrt((tx-sx)**2+(ty-sy)**2)
st=max(15,min(int(d/random.uniform(3,6)),40))
for i in range(st):
t=(i+1)/st
et=t*t*(3-2*t)
bx=(sx+tx)/2+random.uniform(-30,30)
by=(sy+ty)/2+random.uniform(-30,30)
nx=(1-et)**2*sx+2*(1-et)*et*bx+et**2*tx
ny=(1-et)**2*sy+2*(1-et)*et*by+et**2*ty
p.mouse.move(nx,ny)
time.sleep(random.uniform(0.015,0.040))
p.mouse.move(tx,ty)
time.sleep(random.uniform(0.3,0.6))
p.mouse.down()
time.sleep(random.uniform(0.12,0.18))
p.mouse.up()
time.sleep(11)
try:p.wait_for_load_state('networkidle',timeout=10000)
except:pass
time.sleep(5)
fu=p.url
title=p.title()
ck={c['name']:c['value'] for c in p.context.cookies()}
return_value={'success':True,'url':fu,'title':title,'cookies':ck,'had_cloudflare':has_cf,'ms':int((time.time()*1000)-${startTime})}
except Exception as e:
return_value={'success':False,'error':str(e)}`;
const jobId = await submitJob(code);
const result = await pollJob(jobId, 300000);
if (!result.success) return res.json({ author: 'Herza', status: 500, data: { error: result.error } });
res.json({ author: 'Herza', status: 200, data: { url: result.url, title: result.title, cookies: result.cookies, had_cloudflare: result.had_cloudflare, elapsed_ms: result.ms } });
} catch (error) {
res.json({ author: 'Herza', status: 500, data: { error: error.message } });
}
});
app.get('/', (req, res) => {
res.json({ author: 'Herza', status: 200, data: { message: 'API is running', endpoints: { '/bycf': 'POST', '/wafsource': 'POST', '/wafsessions': 'POST' } } });
});
app.listen(PORT, () => console.log(`Server running on port ${PORT}`));