mirror of
https://gitea.tendokyu.moe/pinapelz/Mirage.git
synced 2026-10-04 20:58:06 +03:00
seperate routes and middleware into seperate files
This commit is contained in:
@@ -3,9 +3,9 @@ import { PrismaClient } from '@prisma/client';
|
||||
const prisma = new PrismaClient();
|
||||
|
||||
async function main() {
|
||||
await prisma.games.createMany({
|
||||
await prisma.game.createMany({
|
||||
data: [
|
||||
{ gameName: 'Dancerush' },
|
||||
{ name: 'Dancerush' },
|
||||
],
|
||||
});
|
||||
console.log('Initial seed data inserted');
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
import { PrismaClient } from '@prisma/client';
|
||||
|
||||
export const prisma = new PrismaClient();
|
||||
|
||||
process.on('beforeExit', async () => {
|
||||
await prisma.$disconnect();
|
||||
});
|
||||
|
||||
process.on('SIGINT', async () => {
|
||||
await prisma.$disconnect();
|
||||
process.exit(0);
|
||||
});
|
||||
|
||||
process.on('SIGTERM', async () => {
|
||||
await prisma.$disconnect();
|
||||
process.exit(0);
|
||||
});
|
||||
+12
-230
@@ -1,10 +1,13 @@
|
||||
import express from 'express';
|
||||
import cors from 'cors';
|
||||
import bcrypt from 'bcrypt';
|
||||
import crypto from 'crypto';
|
||||
import session from 'express-session';
|
||||
import cookieParser from 'cookie-parser';
|
||||
import { PrismaClient } from '@prisma/client';
|
||||
import { requireAuth } from './middleware/requireAuth';
|
||||
import { startSessionCleanup } from './utils/session';
|
||||
|
||||
// Routes
|
||||
import * as authRoutes from './routes/authRoutes';
|
||||
import * as userRoutes from './routes/userRoutes';
|
||||
|
||||
const app = express();
|
||||
const port = 5000;
|
||||
@@ -31,241 +34,20 @@ app.use(session({
|
||||
}
|
||||
}));
|
||||
|
||||
const prisma = new PrismaClient();
|
||||
|
||||
|
||||
declare module 'express-session' {
|
||||
interface SessionData {
|
||||
userId: number;
|
||||
}
|
||||
}
|
||||
|
||||
// Middleware to check if user is authenticated
|
||||
const requireAuth = async (req: express.Request, res: express.Response, next: express.NextFunction) => {
|
||||
if (!req.session.userId) {
|
||||
return res.status(401).json({ error: 'Authentication required' });
|
||||
}
|
||||
startSessionCleanup();
|
||||
|
||||
try {
|
||||
const user = await prisma.user.findUnique({
|
||||
where: { id: req.session.userId },
|
||||
select: { id: true, username: true, email: true }
|
||||
});
|
||||
app.post('/api/register', authRoutes.handleRegistration);
|
||||
app.post('/api/authenticate', authRoutes.handleAuthentication);
|
||||
app.post('/api/logout', requireAuth, authRoutes.handleLogout);
|
||||
|
||||
if (!user) {
|
||||
req.session.destroy((err) => {
|
||||
if (err) console.error('Session destroy error:', err);
|
||||
});
|
||||
return res.status(401).json({ error: 'Invalid session' });
|
||||
}
|
||||
|
||||
// Attach user to request object
|
||||
(req as any).user = user;
|
||||
next();
|
||||
} catch (error) {
|
||||
console.error('Auth middleware error:', error);
|
||||
res.status(500).json({ error: 'Internal server error' });
|
||||
}
|
||||
};
|
||||
|
||||
// Create session in database
|
||||
const createSession = async (userId: number): Promise<string> => {
|
||||
const sessionId = crypto.randomUUID();
|
||||
const expiresAt = new Date(Date.now() + 24 * 60 * 60 * 1000); // 24 hours
|
||||
|
||||
await prisma.session.create({
|
||||
data: {
|
||||
id: sessionId,
|
||||
userId,
|
||||
expiresAt
|
||||
}
|
||||
});
|
||||
|
||||
return sessionId;
|
||||
};
|
||||
|
||||
// Clean up expired sessions
|
||||
const cleanupExpiredSessions = async () => {
|
||||
try {
|
||||
await prisma.session.deleteMany({
|
||||
where: {
|
||||
expiresAt: {
|
||||
lt: new Date()
|
||||
}
|
||||
}
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('Session cleanup error:', error);
|
||||
}
|
||||
};
|
||||
|
||||
// Run cleanup every hour
|
||||
setInterval(cleanupExpiredSessions, 60 * 60 * 1000);
|
||||
|
||||
app.post('/api/register', async (req, res) => {
|
||||
try {
|
||||
const { username, password, email } = req.body;
|
||||
|
||||
if (!username || !password || !email) {
|
||||
return res.status(400).json({ error: 'All fields are required' });
|
||||
}
|
||||
|
||||
const existingUser = await prisma.user.findFirst({
|
||||
where: {
|
||||
OR: [
|
||||
{ username },
|
||||
{ email }
|
||||
]
|
||||
}
|
||||
});
|
||||
|
||||
if (existingUser) {
|
||||
return res.status(400).json({ error: 'Username or email already exists' });
|
||||
}
|
||||
|
||||
const salt = crypto.randomBytes(16).toString('hex');
|
||||
const hashedPassword = await bcrypt.hash(password + salt, 12);
|
||||
|
||||
const user = await prisma.user.create({
|
||||
data: {
|
||||
username,
|
||||
password: hashedPassword,
|
||||
salt,
|
||||
email,
|
||||
}
|
||||
});
|
||||
|
||||
// Create session for the new user
|
||||
req.session.userId = user.id;
|
||||
const sessionId = await createSession(user.id);
|
||||
|
||||
res.status(201).json({
|
||||
id: user.id,
|
||||
username: user.username,
|
||||
email: user.email,
|
||||
sessionId
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('Registration error:', error);
|
||||
res.status(500).json({ error: 'Internal server error' });
|
||||
}
|
||||
});
|
||||
|
||||
app.post('/api/authenticate', async (req, res) => {
|
||||
try {
|
||||
const { username, password } = req.body;
|
||||
|
||||
if (!username || !password) {
|
||||
return res.status(400).json({ error: 'Username and password are required' });
|
||||
}
|
||||
|
||||
const user = await prisma.user.findUnique({
|
||||
where: { username }
|
||||
});
|
||||
|
||||
if (!user) {
|
||||
return res.status(401).json({ error: 'Invalid credentials' });
|
||||
}
|
||||
|
||||
const isValidPassword = await bcrypt.compare(password + user.salt, user.password);
|
||||
if (!isValidPassword) {
|
||||
return res.status(401).json({ error: 'Invalid credentials' });
|
||||
}
|
||||
|
||||
// Create session
|
||||
req.session.userId = user.id;
|
||||
const sessionId = await createSession(user.id);
|
||||
|
||||
res.json({
|
||||
id: user.id,
|
||||
username: user.username,
|
||||
email: user.email,
|
||||
sessionId
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('Login error:', error);
|
||||
res.status(500).json({ error: 'Internal server error' });
|
||||
}
|
||||
});
|
||||
|
||||
app.post('/api/logout', requireAuth, async (req, res) => {
|
||||
try {
|
||||
const userId = req.session.userId;
|
||||
|
||||
// Remove all sessions for this user from database
|
||||
await prisma.session.deleteMany({
|
||||
where: { userId }
|
||||
});
|
||||
|
||||
// Destroy the session
|
||||
req.session.destroy((err) => {
|
||||
if (err) {
|
||||
console.error('Session destroy error:', err);
|
||||
return res.status(500).json({ error: 'Logout failed' });
|
||||
}
|
||||
|
||||
res.clearCookie('connect.sid'); // Clear the session cookie
|
||||
res.json({ message: 'Logged out successfully' });
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('Logout error:', error);
|
||||
res.status(500).json({ error: 'Internal server error' });
|
||||
}
|
||||
});
|
||||
|
||||
app.get('/api/me', requireAuth, async (req, res) => {
|
||||
try {
|
||||
const user = (req as any).user;
|
||||
res.json(user);
|
||||
} catch (error) {
|
||||
console.error('Me endpoint error:', error);
|
||||
res.status(500).json({ error: 'Internal server error' });
|
||||
}
|
||||
});
|
||||
|
||||
app.get('/api/users', async (req, res) => {
|
||||
try {
|
||||
const users = await prisma.user.findMany({
|
||||
select: {
|
||||
id: true,
|
||||
username: true,
|
||||
}
|
||||
});
|
||||
res.json(users);
|
||||
} catch (error) {
|
||||
console.error('Users endpoint error:', error);
|
||||
res.status(500).json({ error: 'Internal server error' });
|
||||
}
|
||||
});
|
||||
|
||||
// Check session status
|
||||
app.get('/api/session', async (req, res) => {
|
||||
try {
|
||||
if (!req.session.userId) {
|
||||
return res.json({ authenticated: false });
|
||||
}
|
||||
|
||||
const user = await prisma.user.findUnique({
|
||||
where: { id: req.session.userId },
|
||||
select: { id: true, username: true, email: true }
|
||||
});
|
||||
|
||||
if (!user) {
|
||||
req.session.destroy((err) => {
|
||||
if (err) console.error('Session destroy error:', err);
|
||||
});
|
||||
return res.json({ authenticated: false });
|
||||
}
|
||||
|
||||
res.json({
|
||||
authenticated: true,
|
||||
user
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('Session check error:', error);
|
||||
res.status(500).json({ error: 'Internal server error' });
|
||||
}
|
||||
});
|
||||
app.get('/api/me', userRoutes.handleMeRoute);
|
||||
app.get('/api/session', userRoutes.handleGetCurrentSession);
|
||||
|
||||
app.listen(port, () => {
|
||||
console.log(`Server listening on port ${port}`);
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
import express from 'express';
|
||||
import { prisma } from '../config/db';
|
||||
|
||||
export const requireAuth = async (req: express.Request, res: express.Response, next: express.NextFunction) => {
|
||||
if (!req.session.userId) {
|
||||
return res.status(401).json({ error: 'Authentication required' });
|
||||
}
|
||||
|
||||
try {
|
||||
const user = await prisma.user.findUnique({
|
||||
where: { id: req.session.userId },
|
||||
select: { id: true, username: true, email: true }
|
||||
});
|
||||
|
||||
if (!user) {
|
||||
req.session.destroy((err) => {
|
||||
if (err) console.error('Session destroy error:', err);
|
||||
});
|
||||
return res.status(401).json({ error: 'Invalid session' });
|
||||
}
|
||||
|
||||
(req as any).user = user;
|
||||
next();
|
||||
} catch (error) {
|
||||
console.error('Auth middleware error:', error);
|
||||
res.status(500).json({ error: 'Internal server error' });
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,116 @@
|
||||
import { prisma } from '../config/db';
|
||||
import express from 'express';
|
||||
import { createSession } from '../utils/session'
|
||||
import bcrypt from 'bcrypt';
|
||||
import crypto from 'crypto';
|
||||
|
||||
export const handleRegistration = async (req: express.Request, res: express.Response) => {
|
||||
try {
|
||||
const { username, password, email } = req.body;
|
||||
|
||||
if (!username || !password || !email) {
|
||||
return res.status(400).json({ error: 'All fields are required' });
|
||||
}
|
||||
|
||||
const existingUser = await prisma.user.findFirst({
|
||||
where: {
|
||||
OR: [
|
||||
{ username },
|
||||
{ email }
|
||||
]
|
||||
}
|
||||
});
|
||||
|
||||
if (existingUser) {
|
||||
return res.status(400).json({ error: 'Username or email already exists' });
|
||||
}
|
||||
|
||||
const salt = crypto.randomBytes(16).toString('hex');
|
||||
const hashedPassword = await bcrypt.hash(password + salt, 12);
|
||||
|
||||
const user = await prisma.user.create({
|
||||
data: {
|
||||
username,
|
||||
password: hashedPassword,
|
||||
salt,
|
||||
email,
|
||||
}
|
||||
});
|
||||
|
||||
// Create session for the new user
|
||||
req.session.userId = user.id;
|
||||
const sessionId = await createSession(user.id);
|
||||
|
||||
res.status(201).json({
|
||||
id: user.id,
|
||||
username: user.username,
|
||||
email: user.email,
|
||||
sessionId
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('Registration error:', error);
|
||||
res.status(500).json({ error: 'Internal server error' });
|
||||
}
|
||||
}
|
||||
|
||||
export const handleAuthentication = async (req: express.Request, res: express.Response) => {
|
||||
try {
|
||||
const { username, password } = req.body;
|
||||
|
||||
if (!username || !password) {
|
||||
return res.status(400).json({ error: 'Username and password are required' });
|
||||
}
|
||||
|
||||
const user = await prisma.user.findUnique({
|
||||
where: { username }
|
||||
});
|
||||
|
||||
if (!user) {
|
||||
return res.status(401).json({ error: 'Invalid credentials' });
|
||||
}
|
||||
|
||||
const isValidPassword = await bcrypt.compare(password + user.salt, user.password);
|
||||
if (!isValidPassword) {
|
||||
return res.status(401).json({ error: 'Invalid credentials' });
|
||||
}
|
||||
|
||||
// Create session
|
||||
req.session.userId = user.id;
|
||||
const sessionId = await createSession(user.id);
|
||||
|
||||
res.json({
|
||||
id: user.id,
|
||||
username: user.username,
|
||||
email: user.email,
|
||||
sessionId
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('Login error:', error);
|
||||
res.status(500).json({ error: 'Internal server error' });
|
||||
}
|
||||
}
|
||||
|
||||
export const handleLogout = async (req: express.Request, res: express.Response,) => {
|
||||
try {
|
||||
const userId = req.session.userId;
|
||||
|
||||
// Remove all sessions for this user from database
|
||||
await prisma.session.deleteMany({
|
||||
where: { userId }
|
||||
});
|
||||
|
||||
// Destroy the session
|
||||
req.session.destroy((err) => {
|
||||
if (err) {
|
||||
console.error('Session destroy error:', err);
|
||||
return res.status(500).json({ error: 'Logout failed' });
|
||||
}
|
||||
|
||||
res.clearCookie('connect.sid'); // Clear the session cookie
|
||||
res.json({ message: 'Logged out successfully' });
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('Logout error:', error);
|
||||
res.status(500).json({ error: 'Internal server error' });
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
// Routes about self (or users in general)
|
||||
import express from 'express';
|
||||
import { prisma } from '../config/db';
|
||||
|
||||
export const handleMeRoute = async (req: express.Request, res: express.Response) => {
|
||||
try {
|
||||
const user = (req as any).user;
|
||||
res.json(user);
|
||||
} catch (error) {
|
||||
console.error('Me endpoint error:', error);
|
||||
res.status(500).json({ error: 'Internal server error' });
|
||||
}
|
||||
}
|
||||
|
||||
export const handleGetCurrentSession = async (req: express.Request, res: express.Response) => {
|
||||
try {
|
||||
if (!req.session.userId) {
|
||||
return res.json({ authenticated: false });
|
||||
}
|
||||
|
||||
const user = await prisma.user.findUnique({
|
||||
where: { id: req.session.userId },
|
||||
select: { id: true, username: true, email: true }
|
||||
});
|
||||
|
||||
if (!user) {
|
||||
req.session.destroy((err) => {
|
||||
if (err) console.error('Session destroy error:', err);
|
||||
});
|
||||
return res.json({ authenticated: false });
|
||||
}
|
||||
|
||||
res.json({
|
||||
authenticated: true,
|
||||
user
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('Session check error:', error);
|
||||
res.status(500).json({ error: 'Internal server error' });
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
import crypto from 'crypto';
|
||||
import { prisma } from '../config/db';
|
||||
|
||||
export const createSession = async (userId: number): Promise<string> => {
|
||||
const sessionId = crypto.randomUUID();
|
||||
const expiresAt = new Date(Date.now() + 24 * 60 * 60 * 1000); // 24 hours
|
||||
|
||||
await prisma.session.create({
|
||||
data: {
|
||||
id: sessionId,
|
||||
userId,
|
||||
expiresAt
|
||||
}
|
||||
});
|
||||
|
||||
return sessionId;
|
||||
};
|
||||
|
||||
export const cleanupExpiredSessions = async () => {
|
||||
try {
|
||||
await prisma.session.deleteMany({
|
||||
where: {
|
||||
expiresAt: {
|
||||
lt: new Date()
|
||||
}
|
||||
}
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('Session cleanup error:', error);
|
||||
}
|
||||
};
|
||||
|
||||
export const startSessionCleanup = () => {
|
||||
setInterval(cleanupExpiredSessions, 60 * 60 * 1000);
|
||||
};
|
||||
Reference in New Issue
Block a user