peas/packages/web/src/routes/api/signin.ts

135 lines
3.2 KiB
TypeScript

import { Hono } from "hono";
import pool from "../../lib/database.js";
import type { RowDataPacket } from "mysql2";
import { getKeys as TurnstileKeys, isEnabled as Turnstile } from "../../lib/turnstile.js";
import { getConnInfo } from "@hono/node-server/conninfo";
import { compareSync as passwordHashCheck } from "bcrypt";
import { v4 as uuid } from "uuid";
import { createAPIToken } from "src/lib/token.js";
import { setCookie } from "hono/cookie";
import type scope from "../../../types/api/scope.js";
const SignInAPI = new Hono();
SignInAPI.post("/", async (c) => {
const body = await c.req.json();
if (
body.username === undefined ||
body.password === undefined
) {
return c.json({
success: false,
error: "input_lack",
}, 400);
}
if (
body.username.length < 3 ||
body.username.length > 20 ||
body.password.length < 8 ||
body.password.length > 15
) {
return c.json({
success: false,
error: "length_different",
}, 400);
}
if (
await Turnstile() &&
body.turnstile === undefined
) {
return c.json({
success: false,
error: "input_lack",
}, 400);
}
if (await Turnstile()) {
const sendData = new FormData();
const ip = getConnInfo(c).remote.address;
if (ip !== undefined) {
sendData.append("remoteip", ip);
}
sendData.append("secret", (await TurnstileKeys())[1]);
sendData.append("response", body.turnstile);
sendData.append("idempotency_key", uuid())
try {
const req = await fetch("https://challenges.cloudflare.com/turnstile/v0/siteverify", {
method: "POST",
cache: "no-store",
body: sendData,
});
if (!req.ok) {
return c.json({
success: false,
error: "turnstile_request_failed",
}, 500);
}
const res = await req.json();
if (res.success === false) {
return c.json({
success: false,
error: "turnstile_failed",
}, 400);
}
} catch (err) {
return c.json({
success: false,
error: "turnstile_request_failed",
}, 500);
}
}
const [user] = await pool.execute<RowDataPacket[]>(
"SELECT * FROM users WHERE id = ?",
[body.username],
);
if (user === undefined) {
return c.json({
success: false,
error: "user_not_found",
}, 400);
}
if (user[0].mailverify === 0) {
return c.json({
success: false,
error: "not_mailverify",
}, 400);
}
if (passwordHashCheck(body.password, user[0].password)) {
const scope: scope[] = ["user:client"];
if (user[0].isAdmin === 1) {
scope.push("admin:client");
}
const token = await createAPIToken(
body.username,
scope,
"Peas Client"
);
setCookie(c, "token", token, {
path: "/",
sameSite: "Lax",
maxAge: 86400 * 365,
});
return c.json({
success: true,
token: token,
});
} else {
return c.json({
success: false,
error: "password_invalid",
}, 400);
}
});
export default SignInAPI;