Admin role added, dev side has hot reload again, characters AND groups tied to accounts now.

This commit is contained in:
2026-01-28 23:43:02 +00:00
parent 8e92c28272
commit 3cec7abee9
48 changed files with 6139 additions and 45 deletions

135
server/src/routes/auth.ts Normal file
View File

@@ -0,0 +1,135 @@
import { Hono } from 'hono';
import { prisma } from '../db';
import { hashPassword, verifyPassword } from '../utils/password';
import { createSession, destroySession, requireAuth } from '../middleware/session';
const auth = new Hono();
/**
* POST /api/register
* Create a new user account
*/
auth.post('/register', async (c) => {
const body = await c.req.json();
const { username, email, password } = body;
// Validation
if (!username || !email || !password) {
return c.json({ error: 'Username, email, and password are required' }, 400);
}
if (username.length < 3 || username.length > 30) {
return c.json({ error: 'Username must be 3-30 characters' }, 400);
}
if (password.length < 8) {
return c.json({ error: 'Password must be at least 8 characters' }, 400);
}
// Check if username or email already exists
const existingUser = await prisma.user.findFirst({
where: {
OR: [{ username }, { email }],
},
});
if (existingUser) {
if (existingUser.username === username) {
return c.json({ error: 'Username already taken' }, 400);
}
return c.json({ error: 'Email already registered' }, 400);
}
// Create user
const passwordHash = await hashPassword(password);
const user = await prisma.user.create({
data: {
username,
email,
passwordHash,
},
});
// Create session
await createSession(c, user.id);
return c.json({
username: user.username,
email: user.email,
role: user.role,
});
});
/**
* POST /api/login
* Authenticate and create session
*/
auth.post('/login', async (c) => {
const body = await c.req.json();
const { username, password } = body;
if (!username || !password) {
return c.json({ error: 'Username and password are required' }, 400);
}
// Find user by username or email
const user = await prisma.user.findFirst({
where: {
OR: [{ username }, { email: username }],
},
});
if (!user) {
return c.json({ error: 'Invalid username or password' }, 401);
}
// Verify password
const isValid = await verifyPassword(password, user.passwordHash);
if (!isValid) {
return c.json({ error: 'Invalid username or password' }, 401);
}
// Create session
await createSession(c, user.id);
return c.json({
username: user.username,
email: user.email,
role: user.role,
});
});
/**
* POST /api/logout
* Destroy session
*/
auth.post('/logout', async (c) => {
await destroySession(c);
return c.json({ success: true });
});
/**
* GET /api/auth/status
* Check if user is authenticated
*/
auth.get('/auth/status', (c) => {
const user = c.get('user');
return c.json({
authenticated: !!user,
});
});
/**
* GET /api/me
* Get current user info
*/
auth.get('/me', requireAuth, (c) => {
const user = c.get('user');
return c.json({
username: user!.username,
email: user!.email,
role: user!.role,
});
});
export default auth;