From 8d9816879fbc838e4a8b54001673c487a3d3a36a Mon Sep 17 00:00:00 2001 From: Madeline <46743919+MaddyUnderStars@users.noreply.github.com> Date: Wed, 20 Jul 2022 14:35:32 +1000 Subject: Hcaptcha backend --- api/src/routes/auth/login.ts | 14 +++++++++++--- api/src/routes/auth/register.ts | 17 ++++++++++++----- api/src/util/index.ts | 1 + api/src/util/utility/captcha.ts | 25 +++++++++++++++++++++++++ 4 files changed, 49 insertions(+), 8 deletions(-) create mode 100644 api/src/util/utility/captcha.ts diff --git a/api/src/routes/auth/login.ts b/api/src/routes/auth/login.ts index a89721ea..f5a76393 100644 --- a/api/src/routes/auth/login.ts +++ b/api/src/routes/auth/login.ts @@ -1,5 +1,5 @@ import { Request, Response, Router } from "express"; -import { route } from "@fosscord/api"; +import { route, getIpAdress, verifyHcaptcha } from "@fosscord/api"; import bcrypt from "bcrypt"; import { Config, User, generateToken, adjustEmail, FieldErrors } from "@fosscord/util"; @@ -23,8 +23,8 @@ router.post("/", route({ body: "LoginSchema" }), async (req: Request, res: Respo const config = Config.get(); if (config.login.requireCaptcha && config.security.captcha.enabled) { + const { sitekey, service, secret } = config.security.captcha; if (!captcha_key) { - const { sitekey, service } = config.security.captcha; return res.status(400).json({ captcha_key: ["captcha-required"], captcha_sitekey: sitekey, @@ -32,7 +32,15 @@ router.post("/", route({ body: "LoginSchema" }), async (req: Request, res: Respo }); } - // TODO: check captcha + const ip = getIpAdress(req); + const verify = await verifyHcaptcha(captcha_key, ip); + if (!verify.success) { + return res.status(400).json({ + captcha_key: verify["error-codes"], + captcha_sitekey: sitekey, + captcha_service: service + }); + } } const user = await User.findOneOrFail({ diff --git a/api/src/routes/auth/register.ts b/api/src/routes/auth/register.ts index 126f3dbc..dd5aae84 100644 --- a/api/src/routes/auth/register.ts +++ b/api/src/routes/auth/register.ts @@ -1,6 +1,6 @@ import { Request, Response, Router } from "express"; -import { Config, generateToken, Invite, FieldErrors, User, adjustEmail, trimSpecial } from "@fosscord/util"; -import { route, getIpAdress, IPAnalysis, isProxy } from "@fosscord/api"; +import { Config, generateToken, Invite, FieldErrors, User, adjustEmail } from "@fosscord/util"; +import { route, getIpAdress, IPAnalysis, isProxy, verifyHcaptcha } from "@fosscord/api"; import "missing-native-js-functions"; import bcrypt from "bcrypt"; import { HTTPError } from "lambert-server"; @@ -67,16 +67,23 @@ router.post("/", route({ body: "RegisterSchema" }), async (req: Request, res: Re } if (register.requireCaptcha && security.captcha.enabled) { + const { sitekey, service, secret } = security.captcha; if (!body.captcha_key) { - const { sitekey, service } = security.captcha; - return res?.status(400).json({ + return res.status(400).json({ captcha_key: ["captcha-required"], captcha_sitekey: sitekey, captcha_service: service }); } - // TODO: check captcha + const verify = await verifyHcaptcha(body.captcha_key, ip); + if (!verify.success) { + return res.status(400).json({ + captcha_key: verify["error-codes"], + captcha_sitekey: sitekey, + captcha_service: service + }); + } } if (!register.allowMultipleAccounts) { diff --git a/api/src/util/index.ts b/api/src/util/index.ts index ffbcf24e..de6b6064 100644 --- a/api/src/util/index.ts +++ b/api/src/util/index.ts @@ -6,3 +6,4 @@ export * from "./utility/RandomInviteID"; export * from "./handlers/route"; export * from "./utility/String"; export * from "./handlers/Voice"; +export * from "./utility/captcha"; \ No newline at end of file diff --git a/api/src/util/utility/captcha.ts b/api/src/util/utility/captcha.ts new file mode 100644 index 00000000..b32bd1c6 --- /dev/null +++ b/api/src/util/utility/captcha.ts @@ -0,0 +1,25 @@ +import { Config } from "@fosscord/util"; +import fetch from "node-fetch"; + +export interface hcaptchaResponse { + success: boolean; + challenge_ts: string; + hostname: string; + credit: boolean; + "error-codes": string[]; + score: number; // enterprise only + score_reason: string[]; // enterprise only +} + +export async function verifyHcaptcha(response: string, ip?: string) { + const { security } = Config.get(); + const { secret, sitekey } = security.captcha; + + const res = await fetch("https://hcaptcha.com/siteverify", { + method: "POST", + body: `response=${response}&secret=${secret}&remoteip=${ip}&sitekey=${sitekey}`, + }) + + const json = await res.json() as hcaptchaResponse; + return json; +} \ No newline at end of file -- cgit 1.4.1