feat: migrate to Better Auth for authentication, update environment variables, and enhance database schema with accounts and sessions
This commit is contained in:
@@ -1,134 +0,0 @@
|
||||
import { Router } from 'express';
|
||||
import { and, eq } from 'drizzle-orm';
|
||||
import { z } from 'zod';
|
||||
|
||||
import { db } from '../db/client';
|
||||
import { users } from '../db/schema';
|
||||
import { requireAuth } from '../middleware/auth';
|
||||
import { signAccessToken } from '../utils/jwt';
|
||||
import { hashPassword, verifyPassword } from '../utils/password';
|
||||
|
||||
const router = Router();
|
||||
|
||||
const registerSchema = z.object({
|
||||
email: z.email().trim().toLowerCase(),
|
||||
password: z.string().min(8),
|
||||
name: z.string().trim().min(1).max(255),
|
||||
});
|
||||
|
||||
const loginSchema = z.object({
|
||||
email: z.email().trim().toLowerCase(),
|
||||
password: z.string().min(1),
|
||||
});
|
||||
|
||||
router.post('/register', async (req, res) => {
|
||||
const parsed = registerSchema.safeParse(req.body);
|
||||
|
||||
if (!parsed.success) {
|
||||
res.status(400).json({ message: 'Invalid request body', errors: parsed.error.flatten() });
|
||||
return;
|
||||
}
|
||||
|
||||
const { email, password, name } = parsed.data;
|
||||
|
||||
const existingUser = await db.query.users.findFirst({
|
||||
where: eq(users.email, email),
|
||||
});
|
||||
|
||||
if (existingUser) {
|
||||
res.status(409).json({ message: 'Email already in use' });
|
||||
return;
|
||||
}
|
||||
|
||||
const passwordHash = await hashPassword(password);
|
||||
|
||||
const [newUser] = await db
|
||||
.insert(users)
|
||||
.values({
|
||||
email,
|
||||
name,
|
||||
passwordHash,
|
||||
})
|
||||
.returning({
|
||||
id: users.id,
|
||||
email: users.email,
|
||||
name: users.name,
|
||||
createdAt: users.createdAt,
|
||||
});
|
||||
|
||||
if (!newUser) {
|
||||
res.status(500).json({ message: 'Failed to create user' });
|
||||
return;
|
||||
}
|
||||
|
||||
const token = signAccessToken({ userId: newUser.id, email: newUser.email });
|
||||
|
||||
res.status(201).json({ token, user: newUser });
|
||||
});
|
||||
|
||||
router.post('/login', async (req, res) => {
|
||||
const parsed = loginSchema.safeParse(req.body);
|
||||
|
||||
if (!parsed.success) {
|
||||
res.status(400).json({ message: 'Invalid request body', errors: parsed.error.flatten() });
|
||||
return;
|
||||
}
|
||||
|
||||
const { email, password } = parsed.data;
|
||||
|
||||
const user = await db.query.users.findFirst({
|
||||
where: eq(users.email, email),
|
||||
});
|
||||
|
||||
if (!user) {
|
||||
res.status(401).json({ message: 'Invalid email or password' });
|
||||
return;
|
||||
}
|
||||
|
||||
const isPasswordValid = await verifyPassword(password, user.passwordHash);
|
||||
|
||||
if (!isPasswordValid) {
|
||||
res.status(401).json({ message: 'Invalid email or password' });
|
||||
return;
|
||||
}
|
||||
|
||||
const token = signAccessToken({ userId: user.id, email: user.email });
|
||||
|
||||
res.json({
|
||||
token,
|
||||
user: {
|
||||
id: user.id,
|
||||
email: user.email,
|
||||
name: user.name,
|
||||
createdAt: user.createdAt,
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
router.get('/me', requireAuth, async (req, res) => {
|
||||
const authenticatedUser = req.user;
|
||||
|
||||
if (!authenticatedUser) {
|
||||
res.status(401).json({ message: 'Unauthorized' });
|
||||
return;
|
||||
}
|
||||
|
||||
const user = await db.query.users.findFirst({
|
||||
where: and(eq(users.id, authenticatedUser.userId), eq(users.email, authenticatedUser.email)),
|
||||
columns: {
|
||||
id: true,
|
||||
email: true,
|
||||
name: true,
|
||||
createdAt: true,
|
||||
},
|
||||
});
|
||||
|
||||
if (!user) {
|
||||
res.status(404).json({ message: 'User not found' });
|
||||
return;
|
||||
}
|
||||
|
||||
res.json({ user });
|
||||
});
|
||||
|
||||
export default router;
|
||||
@@ -46,16 +46,16 @@ router.post('/upload-url', async (req, res) => {
|
||||
return;
|
||||
}
|
||||
|
||||
const user = req.user;
|
||||
const authSession = req.auth;
|
||||
|
||||
if (!user) {
|
||||
if (!authSession?.user) {
|
||||
res.status(401).json({ message: 'Unauthorized' });
|
||||
return;
|
||||
}
|
||||
|
||||
await ensureMinioBucket();
|
||||
|
||||
const objectKey = buildObjectKey(user.userId, parsed.data.fileName, parsed.data.prefix);
|
||||
const objectKey = buildObjectKey(authSession.user.id, parsed.data.fileName, parsed.data.prefix);
|
||||
const uploadUrl = await minioClient.presignedPutObject(minioBucket, objectKey, minioPresignedExpirySeconds);
|
||||
const now = new Date();
|
||||
const expiresAt = new Date(now.getTime() + minioPresignedExpirySeconds * 1000);
|
||||
@@ -63,7 +63,7 @@ router.post('/upload-url', async (req, res) => {
|
||||
const [videoRecord] = await db
|
||||
.insert(videos)
|
||||
.values({
|
||||
userId: user.userId,
|
||||
userId: authSession.user.id,
|
||||
objectKey,
|
||||
bucket: minioBucket,
|
||||
uploadUrl,
|
||||
|
||||
Reference in New Issue
Block a user