import express, { Request, Response } from 'express'; import http from 'http'; import { Server as SocketIOServer } from 'socket.io'; import cors from 'cors'; import cookieParser from 'cookie-parser'; import session from 'express-session'; import passport from 'passport'; import path from 'path'; import { setupSocketIO } from './socket'; import { db } from './database'; import { config } from './config'; import { securityHeaders, createRateLimit, requestLogger, sanitizeInput } from './middleware'; import { logger } from './logger'; import './auth'; const app = express(); app.set('trust proxy', 1); const server = http.createServer(app); const io = new SocketIOServer(server, { cors: { origin: config.security.corsOrigin, methods: ['GET', 'POST'], credentials: true }, transports: ['polling', 'websocket'] }); // Security middleware app.use(securityHeaders); app.use(requestLogger); app.use(sanitizeInput); // Cookie parsing app.use(cookieParser()); // Rate limiting app.use('/api', createRateLimit); // Session configuration const SQLiteStore = require('connect-sqlite3')(session); const sessionMiddleware = session({ store: new SQLiteStore({ db: 'sessions.db', dir: './data' }), secret: process.env.NEXTAUTH_SECRET || 'fallback-secret-change-in-production', resave: false, saveUninitialized: false, cookie: { secure: false, maxAge: 24 * 60 * 60 * 1000 } // 24 hours }); app.use(sessionMiddleware); // Passport initialization app.use(passport.initialize()); app.use(passport.session()); // Body parsing app.use(express.json({ limit: '10mb' })); app.use(express.urlencoded({ extended: true, limit: '10mb' })); // CORS with specific origin app.use(cors({ origin: config.server.nodeEnv === 'development' ? ['http://localhost:3000', 'http://localhost:5173'] : config.security.corsOrigin, credentials: true })); app.use(express.static(path.join(__dirname, '../client/dist'))); app.get('/health', (req, res) => { res.json({ status: 'ok', timestamp: new Date().toISOString() }); }); // Auth routes app.get('/auth/github', passport.authenticate('github')); app.get('/auth/github/callback', passport.authenticate('github', { failureRedirect: '/login' }), (req, res) => { res.redirect('/'); } ); app.get('/api/user', (req, res) => { if (req.user) { res.json(req.user); } else { res.status(401).json({ error: 'Not authenticated' }); } }); app.get('/api/socket-token', (req, res) => { if (req.user) { // Create a token containing user info const user = req.user as any; // Use any to bypass typing issues const token = Buffer.from(JSON.stringify({ userId: user.id, username: user.username, timestamp: Date.now() })).toString('base64'); res.json({ token, user: req.user }); } else { res.status(401).json({ error: 'Not authenticated' }); } }); // SPA catch-all route app.get('*', (req, res) => { res.sendFile(path.join(__dirname, '../client/dist/index.html')); }); io.use((socket: any, next: any) => { next(); }); setupSocketIO(io); const PORT = config.server.port; server.listen(PORT, () => { console.log(`Server running on port ${PORT}`); });