First pass
This commit is contained in:
58
src/lib/auth.ts
Normal file
58
src/lib/auth.ts
Normal file
@@ -0,0 +1,58 @@
|
||||
import { db } from '../db';
|
||||
import { users, sessions } from '../db/schema';
|
||||
import { eq } from 'drizzle-orm';
|
||||
import bcrypt from 'bcryptjs';
|
||||
import { nanoid } from 'nanoid';
|
||||
|
||||
const SESSION_DURATION = 1000 * 60 * 60 * 24 * 30; // 30 days
|
||||
|
||||
export async function createSession(userId: string) {
|
||||
const sessionId = nanoid();
|
||||
const expiresAt = new Date(Date.now() + SESSION_DURATION);
|
||||
|
||||
await db.insert(sessions).values({
|
||||
id: sessionId,
|
||||
userId,
|
||||
expiresAt,
|
||||
});
|
||||
|
||||
return { sessionId, expiresAt };
|
||||
}
|
||||
|
||||
export async function validateSession(sessionId: string) {
|
||||
const result = await db.select({
|
||||
user: users,
|
||||
session: sessions
|
||||
})
|
||||
.from(sessions)
|
||||
.innerJoin(users, eq(sessions.userId, users.id))
|
||||
.where(eq(sessions.id, sessionId))
|
||||
.get();
|
||||
|
||||
if (!result) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const { session, user } = result;
|
||||
|
||||
if (Date.now() >= session.expiresAt.getTime()) {
|
||||
await db.delete(sessions).where(eq(sessions.id, sessionId));
|
||||
return null;
|
||||
}
|
||||
|
||||
// Extend session if close to expiry (optional, skipping for simplicity)
|
||||
|
||||
return { session, user };
|
||||
}
|
||||
|
||||
export async function invalidateSession(sessionId: string) {
|
||||
await db.delete(sessions).where(eq(sessions.id, sessionId));
|
||||
}
|
||||
|
||||
export async function hashPassword(password: string) {
|
||||
return await bcrypt.hash(password, 10);
|
||||
}
|
||||
|
||||
export async function verifyPassword(password: string, hash: string) {
|
||||
return await bcrypt.compare(password, hash);
|
||||
}
|
||||
Reference in New Issue
Block a user