135 lines
3.2 KiB
TypeScript
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;
|