Files
anyhealth/src/main.ts
T

113 lines
3.0 KiB
TypeScript

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);