mirror of
https://github.com/nicotsx/ironmount.git
synced 2025-12-10 12:10:51 +01:00
feat: auth client middleware
This commit is contained in:
@@ -1,7 +1,16 @@
|
||||
import { arktypeValidator } from "@hono/arktype-validator";
|
||||
import { validator } from "hono-openapi";
|
||||
|
||||
import { Hono } from "hono";
|
||||
import { deleteCookie, getCookie, setCookie } from "hono/cookie";
|
||||
import { getMeDto, loginBodySchema, loginDto, logoutDto, registerBodySchema, registerDto } from "./auth.dto";
|
||||
import {
|
||||
getMeDto,
|
||||
getStatusDto,
|
||||
loginBodySchema,
|
||||
loginDto,
|
||||
logoutDto,
|
||||
registerBodySchema,
|
||||
registerDto,
|
||||
} from "./auth.dto";
|
||||
import { authService } from "./auth.service";
|
||||
|
||||
const COOKIE_NAME = "session_id";
|
||||
@@ -13,24 +22,23 @@ const COOKIE_OPTIONS = {
|
||||
};
|
||||
|
||||
export const authController = new Hono()
|
||||
.post("/register", registerDto, arktypeValidator("json", registerBodySchema), async (c) => {
|
||||
.post("/register", registerDto, validator("json", registerBodySchema), async (c) => {
|
||||
const body = c.req.valid("json");
|
||||
|
||||
try {
|
||||
const { user } = await authService.register(body.username, body.password);
|
||||
const { user, sessionId } = await authService.register(body.username, body.password);
|
||||
|
||||
return c.json(
|
||||
{
|
||||
message: "User registered successfully",
|
||||
user: { id: user.id, username: user.username },
|
||||
},
|
||||
201,
|
||||
);
|
||||
setCookie(c, COOKIE_NAME, sessionId, {
|
||||
...COOKIE_OPTIONS,
|
||||
expires: new Date(Date.now() + 7 * 24 * 60 * 60 * 1000), // 7 days
|
||||
});
|
||||
|
||||
return c.json({ message: "User registered successfully", user: { id: user.id, username: user.username } }, 201);
|
||||
} catch (error) {
|
||||
return c.json({ message: error instanceof Error ? error.message : "Registration failed" }, 400);
|
||||
}
|
||||
})
|
||||
.post("/login", loginDto, arktypeValidator("json", loginBodySchema), async (c) => {
|
||||
.post("/login", loginDto, validator("json", loginBodySchema), async (c) => {
|
||||
const body = c.req.valid("json");
|
||||
|
||||
try {
|
||||
@@ -76,4 +84,8 @@ export const authController = new Hono()
|
||||
return c.json({
|
||||
user: session.user,
|
||||
});
|
||||
})
|
||||
.get("/status", getStatusDto, async (c) => {
|
||||
const hasUsers = await authService.hasUsers();
|
||||
return c.json({ hasUsers });
|
||||
});
|
||||
|
||||
@@ -93,5 +93,25 @@ export const getMeDto = describeRoute({
|
||||
},
|
||||
});
|
||||
|
||||
const statusResponseSchema = type({
|
||||
hasUsers: "boolean",
|
||||
});
|
||||
|
||||
export const getStatusDto = describeRoute({
|
||||
description: "Get authentication system status",
|
||||
operationId: "getStatus",
|
||||
tags: ["Auth"],
|
||||
responses: {
|
||||
200: {
|
||||
description: "Authentication system status",
|
||||
content: {
|
||||
"application/json": {
|
||||
schema: resolver(statusResponseSchema),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
export type LoginBody = typeof loginBodySchema.infer;
|
||||
export type RegisterBody = typeof registerBodySchema.infer;
|
||||
|
||||
@@ -10,10 +10,10 @@ export class AuthService {
|
||||
* Register a new user with username and password
|
||||
*/
|
||||
async register(username: string, password: string) {
|
||||
const [existingUser] = await db.select().from(usersTable).where(eq(usersTable.username, username));
|
||||
const [existingUser] = await db.select().from(usersTable);
|
||||
|
||||
if (existingUser) {
|
||||
throw new Error("Username already exists");
|
||||
throw new Error("Admin user already exists");
|
||||
}
|
||||
|
||||
const passwordHash = await Bun.password.hash(password, {
|
||||
@@ -29,8 +29,16 @@ export class AuthService {
|
||||
}
|
||||
|
||||
logger.info(`User registered: ${username}`);
|
||||
const sessionId = crypto.randomUUID();
|
||||
const expiresAt = new Date(Date.now() + SESSION_DURATION);
|
||||
|
||||
return { user: { id: user.id, username: user.username, createdAt: user.createdAt } };
|
||||
await db.insert(sessionsTable).values({
|
||||
id: sessionId,
|
||||
userId: user.id,
|
||||
expiresAt,
|
||||
});
|
||||
|
||||
return { user: { id: user.id, username: user.username, createdAt: user.createdAt }, sessionId };
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -118,6 +126,14 @@ export class AuthService {
|
||||
logger.info(`Cleaned up ${result.length} expired sessions`);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if any users exist in the system
|
||||
*/
|
||||
async hasUsers(): Promise<boolean> {
|
||||
const [user] = await db.select({ id: usersTable.id }).from(usersTable).limit(1);
|
||||
return !!user;
|
||||
}
|
||||
}
|
||||
|
||||
export const authService = new AuthService();
|
||||
|
||||
Reference in New Issue
Block a user