Enhance verification system with multi-provider support and alt-account detection
- Added support for multiple captcha providers including Google reCAPTCHA (v2 and v3), hCaptcha, and Cloudflare Turnstile. - Introduced new fields in the verification configuration for selecting captcha providers and enabling alt-account detection. - Implemented logic to handle verification attempts and flag potential alt accounts based on IP and invite code analysis. - Updated environment configuration to include necessary keys for captcha providers. - Enhanced the user interface to allow selection of captcha providers in the verification setup. - Improved backend handling of verification records to store additional data related to captcha provider usage.
This commit is contained in:
@@ -71,9 +71,17 @@ async function handleCaptchaGet(url: URL, res: ServerResponse): Promise<void> {
|
||||
res.end('Captcha expired');
|
||||
return;
|
||||
}
|
||||
// External providers (reCAPTCHA / hCaptcha / Turnstile) are served by the WebUI.
|
||||
if (challenge.provider !== 'MATH' && env.WEBUI_URL) {
|
||||
const target = `${env.WEBUI_URL.replace(/\/$/, '')}/verify/captcha?token=${encodeURIComponent(token)}`;
|
||||
res.statusCode = 302;
|
||||
res.setHeader('Location', target);
|
||||
res.end();
|
||||
return;
|
||||
}
|
||||
res.statusCode = 200;
|
||||
res.setHeader('Content-Type', 'text/html; charset=utf-8');
|
||||
res.end(renderCaptchaPage(token, challenge.question));
|
||||
res.end(renderCaptchaPage(token, challenge.question ?? '?'));
|
||||
}
|
||||
|
||||
async function handleCaptchaPost(req: IncomingMessage, res: ServerResponse): Promise<void> {
|
||||
@@ -92,16 +100,32 @@ async function handleCaptchaPost(req: IncomingMessage, res: ServerResponse): Pro
|
||||
res.end('Captcha expired');
|
||||
return;
|
||||
}
|
||||
if (hashCaptchaAnswer(answer) !== challenge.answerHash) {
|
||||
if (challenge.provider !== 'MATH') {
|
||||
if (env.WEBUI_URL) {
|
||||
const target = `${env.WEBUI_URL.replace(/\/$/, '')}/verify/captcha?token=${encodeURIComponent(token)}`;
|
||||
res.statusCode = 302;
|
||||
res.setHeader('Location', target);
|
||||
res.end();
|
||||
return;
|
||||
}
|
||||
res.statusCode = 400;
|
||||
res.end('Use the WebUI captcha URL for this provider');
|
||||
return;
|
||||
}
|
||||
if (!challenge.answerHash || hashCaptchaAnswer(answer) !== challenge.answerHash) {
|
||||
res.statusCode = 200;
|
||||
res.setHeader('Content-Type', 'text/html; charset=utf-8');
|
||||
res.end(renderCaptchaPage(token, challenge.question, 'Wrong answer. Try again.'));
|
||||
res.end(renderCaptchaPage(token, challenge.question ?? '?', 'Wrong answer. Try again.'));
|
||||
return;
|
||||
}
|
||||
await deleteCaptchaChallenge(redis, token);
|
||||
await verificationQueue.add(
|
||||
'verificationComplete',
|
||||
{ guildId: challenge.guildId, userId: challenge.userId },
|
||||
{
|
||||
guildId: challenge.guildId,
|
||||
userId: challenge.userId,
|
||||
captchaProvider: challenge.provider
|
||||
},
|
||||
{ removeOnComplete: 1000, removeOnFail: 500 }
|
||||
);
|
||||
res.statusCode = 200;
|
||||
|
||||
Reference in New Issue
Block a user