feat: add session-based auth system
This commit is contained in:
@@ -0,0 +1,71 @@
|
|||||||
|
import { db } from './db';
|
||||||
|
import { users, sessions } from './schema';
|
||||||
|
import { eq, and, gt } from 'drizzle-orm';
|
||||||
|
import { generateSessionToken, hashSessionToken, verifyPassword } from './auth-utils';
|
||||||
|
|
||||||
|
const SESSION_DURATION_MS = 30 * 24 * 60 * 60 * 1000; // 30 days
|
||||||
|
|
||||||
|
export async function createSession(userId: number): Promise<string> {
|
||||||
|
const token = generateSessionToken();
|
||||||
|
const sessionId = hashSessionToken(token);
|
||||||
|
const expiresAt = new Date(Date.now() + SESSION_DURATION_MS);
|
||||||
|
|
||||||
|
await db.insert(sessions).values({ sessionId, userId, expiresAt });
|
||||||
|
return token;
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function validateSession(token: string) {
|
||||||
|
const sessionId = hashSessionToken(token);
|
||||||
|
|
||||||
|
const result = await db
|
||||||
|
.select({
|
||||||
|
session: sessions,
|
||||||
|
user: {
|
||||||
|
id: users.id,
|
||||||
|
email: users.email,
|
||||||
|
name: users.name,
|
||||||
|
role: users.role,
|
||||||
|
active: users.active,
|
||||||
|
mustChangePassword: users.mustChangePassword
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.from(sessions)
|
||||||
|
.innerJoin(users, eq(sessions.userId, users.id))
|
||||||
|
.where(
|
||||||
|
and(
|
||||||
|
eq(sessions.sessionId, sessionId),
|
||||||
|
gt(sessions.expiresAt, new Date())
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.limit(1);
|
||||||
|
|
||||||
|
if (result.length === 0) return null;
|
||||||
|
|
||||||
|
const { session, user } = result[0];
|
||||||
|
if (!user.active) return null;
|
||||||
|
|
||||||
|
return { session, user };
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function destroySession(token: string): Promise<void> {
|
||||||
|
const sessionId = hashSessionToken(token);
|
||||||
|
await db.delete(sessions).where(eq(sessions.sessionId, sessionId));
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function authenticateUser(email: string, password: string) {
|
||||||
|
const result = await db
|
||||||
|
.select()
|
||||||
|
.from(users)
|
||||||
|
.where(eq(users.email, email.toLowerCase()))
|
||||||
|
.limit(1);
|
||||||
|
|
||||||
|
if (result.length === 0) return null;
|
||||||
|
|
||||||
|
const user = result[0];
|
||||||
|
if (!user.active) return null;
|
||||||
|
|
||||||
|
const valid = await verifyPassword(user.passwordHash, password);
|
||||||
|
if (!valid) return null;
|
||||||
|
|
||||||
|
return user;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user