import "dotenv/config"; import { drizzle } from "drizzle-orm/libsql"; import { eq } from "drizzle-orm"; import { createClient } from "@libsql/client"; import { SignJWT } from "jose"; import { Hono } from "@hono/hono"; import { commonResponse } from "./utils/response.ts"; import { hashPassword, verifyPassword } from "./utils/crypto.ts"; import { metasTable } from "./db/schema.ts"; const client = createClient({ url: `file:${process.env.DATABASE_PATH!}`, }); const db = drizzle(client); const JWT_SECRET = crypto.getRandomValues(new Uint8Array(32)); async function initDefaultUser() { const row = await db .select() .from(metasTable) .where(eq(metasTable.key, "userinfo_username")) .get(); if (row) return; const usernameHash = await hashPassword("ah"); const passwordHash = await hashPassword("123456"); await db .insert(metasTable) .values([ { key: "userinfo_username", value: usernameHash }, { key: "userinfo_password", value: passwordHash }, ]) .run(); console.log("Default user created (username: ah, password: 123456)"); } await initDefaultUser(); const app = new Hono(); app.get("/", (c) => { return commonResponse(c, true, 200, { "hint": "Hello! But nothing here." }); }); app.get("/ping", (c) => { return commonResponse(c, true, 200, {}); }); app.post("/authenticate", async (c) => { const body = await c.req.json<{ username?: string; password?: string }>(); if (!body.username || !body.password) { return commonResponse( c, false, 400, {}, "Missing username or password", ); } const storedUsername = await db .select() .from(metasTable) .where(eq(metasTable.key, "userinfo_username")) .get(); const storedPassword = await db .select() .from(metasTable) .where(eq(metasTable.key, "userinfo_password")) .get(); if (!storedUsername?.value || !storedPassword?.value) { return commonResponse(c, false, 500, {}, "User not configured"); } const usernameValid = await verifyPassword( body.username, storedUsername.value, ); if (!usernameValid) { return commonResponse(c, false, 401, {}, "Invalid credentials"); } const passwordValid = await verifyPassword( body.password, storedPassword.value, ); if (!passwordValid) { return commonResponse(c, false, 401, {}, "Invalid credentials"); } const jwt = await new SignJWT({ username: body.username }) .setProtectedHeader({ alg: "HS256" }) .setIssuedAt() .setExpirationTime("24h") .sign(JWT_SECRET); return commonResponse(c, true, 200, { token: jwt }); }); Deno.serve(app.fetch); const handleExit = () => { console.log("Closing database connection..."); db.$client.close(); console.log("Disconnected."); process.exit(0); }; process.on("SIGINT", handleExit); process.on("SIGTERM", handleExit);