From 6bdcfa7e8af5cd8eaf15bf61fc33cadea42de418 Mon Sep 17 00:00:00 2001 From: localhost Date: Fri, 20 Feb 2026 22:53:03 +0100 Subject: [PATCH] switch to hcaptcha --- src/router/websocket.ts | 9 +++++++-- src/utils/common.ts | 14 ++++++++------ 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/src/router/websocket.ts b/src/router/websocket.ts index 300fa07..14a7229 100644 --- a/src/router/websocket.ts +++ b/src/router/websocket.ts @@ -107,8 +107,10 @@ app.ws('/save', { if (await redis.get(videoId) !== 'downloading') { await redis.set(videoId, 'downloading', 'EX', 300) - if (!(await checkCaptcha(message))) { + const captchaCheck = await checkCaptcha(message, ws.data.headers['cf-connecting-ip'] || '0.0.0.0') + if (!captchaCheck.success) { await cleanup(ws, videoId); + console.log(`captcha failed for ${videoId} - ${JSON.stringify(captchaCheck)}`) return sendError(ws, 'Captcha validation failed.'); } else { ws.send('DATA - Captcha validated. Starting download...'); @@ -158,8 +160,11 @@ app.ws('/savechannel', { if (!status || !status.startsWith('captcha-')) return sendError(ws, 'No channel associated with this session.'); const channelId = status.replace('captcha-', ''); - if (!(await checkCaptcha(message))) { + const captchaCheck = await checkCaptcha(message, ws.data.headers['cf-connecting-ip'] || '0.0.0.0') + + if (!captchaCheck.success) { await cleanup(ws, channelId); + console.log(`captcha failed for ${channelId} - ${JSON.stringify(captchaCheck)}`) return sendError(ws, 'Captcha validation failed.'); } else { ws.send('DATA - Captcha validated. Starting download...'); diff --git a/src/utils/common.ts b/src/utils/common.ts index c93eecb..ec287a6 100644 --- a/src/utils/common.ts +++ b/src/utils/common.ts @@ -36,19 +36,21 @@ function convertRelativeToDate(relativeTime: string) { return currentDate; } -async function checkCaptcha(response: string) { - const confirm = await (await fetch('https://challenges.cloudflare.com/turnstile/v0/siteverify', { +async function checkCaptcha(response: string, remoteIp: string): any { + const confirm = await (await fetch('https://api.hcaptcha.com/siteverify', { method: 'POST', - body: JSON.stringify({ + body: new URLSearchParams({ 'response': response, - 'secret': process.env.CAPTCHA_SECRET + 'secret': process.env.CAPTCHA_SECRET!, + 'remoteip': remoteIp, + 'sitekey': process.env.SITEKEY! }), headers: { - 'content-type': 'application/json' + 'content-type': 'application/x-www-form-urlencoded' } })).json() - return confirm.success + return confirm } async function createDatabaseVideo(id: string, videoUrl: string) {