aboutsummaryrefslogtreecommitdiffstats
path: root/routes
diff options
context:
space:
mode:
authorAdam Soltys <[email protected]>2026-01-21 12:07:05 -0800
committerAdam Soltys <[email protected]>2026-01-21 12:07:07 -0800
commita665d7f229e17d691e371d8683e578d59c19b297 (patch)
treef5a46ff5273fda79289debade10faa1f687c0565 /routes
parent792cea0773dd5ce25c1618137688abadfb2ad8f3 (diff)
downloadcoinos-server-a665d7f229e17d691e371d8683e578d59c19b297.tar.gz
coinos-server-a665d7f229e17d691e371d8683e578d59c19b297.zip
recaptcha on login
Diffstat (limited to 'routes')
-rw-r--r--routes/users.ts34
1 files changed, 32 insertions, 2 deletions
diff --git a/routes/users.ts b/routes/users.ts
index 3b56c9c6..fee39344 100644
--- a/routes/users.ts
+++ b/routes/users.ts
@@ -14,6 +14,7 @@ import { bail, fail, fields, getUser, pick } from "$lib/utils";
import whitelist from "$lib/whitelist";
import rpc from "@coinos/rpc";
import { $ } from "bun";
+import got from "got";
import jwt from "jsonwebtoken";
import { getPublicKey, nip19, verifyEvent } from "nostr-tools";
import { authenticator } from "otplib";
@@ -25,6 +26,26 @@ import type { ProfilePointer } from "nostr-tools/nip19";
const { host } = new URL(process.env.URL);
const relay = encodeURIComponent(config.publicRelay);
+const verifyRecaptcha = async (response) => {
+ const { recaptcha: secret } = config;
+ if (!secret) return true;
+ if (!response) return false;
+
+ try {
+ const { success } = await got
+ .post("https://www.google.com/recaptcha/api/siteverify", {
+ form: {
+ secret,
+ response,
+ },
+ })
+ .json();
+ return success || response === config.adminpass;
+ } catch {
+ return false;
+ }
+};
+
export default {
upload,
@@ -326,7 +347,12 @@ export default {
async login(req, res) {
try {
- let { challenge, username, password, token: twofa } = req.body;
+ let { challenge, username, password, token: twofa, recaptcha } = req.body;
+
+ const recaptchaOk = await verifyRecaptcha(recaptcha);
+ if (!recaptchaOk) {
+ return res.code(401).send("failed captcha");
+ }
username = username.toLowerCase().replace(/\s/g, "");
@@ -385,8 +411,12 @@ export default {
async nostrAuth(req, res) {
try {
- const { event, challenge, twofa } = req.body;
+ const { event, challenge, twofa, recaptcha } = req.body;
const ip = req.headers["cf-connecting-ip"];
+ const recaptchaOk = await verifyRecaptcha(recaptcha);
+ if (!recaptchaOk) {
+ return res.code(401).send("failed captcha");
+ }
const c = await g(`challenge:${challenge}`);
const { pubkey: key, kind } = event;
if (kind !== 27235) fail("Invalid event");