Auth implemented
This commit is contained in:
44
backend/src/api/auth.ts
Normal file
44
backend/src/api/auth.ts
Normal file
@@ -0,0 +1,44 @@
|
||||
// backend/src/api/auth.ts
|
||||
import express from 'express';
|
||||
import * as dotenv from 'dotenv';
|
||||
import * as path from 'path';
|
||||
import { AuthService } from '../services/AuthService';
|
||||
import { SessionService } from '../services/SessionService';
|
||||
import { AuthLogger } from '../services/AuthLogger';
|
||||
|
||||
dotenv.config({ path: path.resolve(__dirname, '../../.env') });
|
||||
|
||||
const SESSION_SECRET = process.env.SESSION_SECRET;
|
||||
const JWT_SECRET = process.env.JWT_SECRET;
|
||||
|
||||
if (!SESSION_SECRET) {
|
||||
throw new Error('SESSION_SECRET is not defined in the environment variables.');
|
||||
}
|
||||
|
||||
if (!JWT_SECRET) {
|
||||
throw new Error('JWT_SECRET is not defined in the environment variables.');
|
||||
}
|
||||
|
||||
const router = express.Router();
|
||||
|
||||
router.post('/passphrase', (req, res) => {
|
||||
const { passphrase } = req.body;
|
||||
const ipAddress = req.ip || ''; // Get IP address for logging, default to empty string if undefined
|
||||
|
||||
if (!passphrase) {
|
||||
AuthLogger.logAttempt('failure', ipAddress);
|
||||
return res.status(400).json({ message: 'Passphrase is required.' });
|
||||
}
|
||||
|
||||
if (AuthService.validatePassphrase(passphrase)) {
|
||||
const session = SessionService.createSession();
|
||||
SessionService.authenticateSession(session.id);
|
||||
AuthLogger.logAttempt('success', ipAddress);
|
||||
return res.status(200).json({ message: 'Authentication successful', sessionToken: session.id });
|
||||
} else {
|
||||
AuthLogger.logAttempt('failure', ipAddress);
|
||||
return res.status(401).json({ message: 'Invalid passphrase' });
|
||||
}
|
||||
});
|
||||
|
||||
export default router;
|
||||
@@ -5,7 +5,15 @@ import express from 'express';
|
||||
import http from 'http';
|
||||
import { createWebSocketServer } from './ws';
|
||||
import sessionsRouter from './routes/sessions';
|
||||
import authRouter from './api/auth';
|
||||
import { authMiddleware } from './middleware/authMiddleware'; // Import the middleware
|
||||
import cors from 'cors';
|
||||
import { v4 as uuidv4 } from 'uuid';
|
||||
import { sessions, SessionState } from './ws'; // Import sessions and SessionState from ws/index.ts
|
||||
|
||||
console.log('index.ts: AUTH_PASSPHRASE:', process.env.AUTH_PASSPHRASE);
|
||||
console.log('index.ts: SESSION_SECRET:', process.env.SESSION_SECRET);
|
||||
console.log('index.ts: JWT_SECRET:', process.env.JWT_SECRET);
|
||||
|
||||
const app = express();
|
||||
const server = http.createServer(app);
|
||||
@@ -14,8 +22,28 @@ const server = http.createServer(app);
|
||||
app.use(express.json());
|
||||
app.use(cors());
|
||||
|
||||
// API Routes
|
||||
app.use('/', sessionsRouter);
|
||||
// Public API Routes
|
||||
app.use('/api/auth', authRouter);
|
||||
|
||||
// Public route for creating a new session
|
||||
app.post('/sessions', (req, res) => {
|
||||
const sessionId = uuidv4();
|
||||
sessions.set(sessionId, {
|
||||
state: SessionState.SETUP,
|
||||
topic: null,
|
||||
description: null,
|
||||
expectedResponses: 0,
|
||||
submittedCount: 0,
|
||||
responses: new Map(),
|
||||
clients: new Map(),
|
||||
finalResult: null,
|
||||
});
|
||||
console.log(`New session created: ${sessionId}`);
|
||||
res.status(201).json({ sessionId });
|
||||
});
|
||||
|
||||
// Protected API Routes
|
||||
app.use('/sessions', authMiddleware, sessionsRouter);
|
||||
|
||||
// Create and attach WebSocket server
|
||||
createWebSocketServer(server);
|
||||
|
||||
21
backend/src/middleware/authMiddleware.ts
Normal file
21
backend/src/middleware/authMiddleware.ts
Normal file
@@ -0,0 +1,21 @@
|
||||
// backend/src/middleware/authMiddleware.ts
|
||||
import { Request, Response, NextFunction } from 'express';
|
||||
import { SessionService } from '../services/SessionService';
|
||||
|
||||
export const authMiddleware = (req: Request, res: Response, next: NextFunction) => {
|
||||
const sessionToken = req.headers['x-session-token'] as string; // Assuming token is sent in a header
|
||||
|
||||
if (!sessionToken) {
|
||||
return res.status(401).json({ message: 'No session token provided.' });
|
||||
}
|
||||
|
||||
const session = SessionService.getSession(sessionToken);
|
||||
|
||||
if (!session || !session.isAuthenticated) {
|
||||
return res.status(401).json({ message: 'Invalid or unauthenticated session.' });
|
||||
}
|
||||
|
||||
// Optionally, attach session to request for further use
|
||||
(req as any).session = session;
|
||||
next();
|
||||
};
|
||||
@@ -4,22 +4,6 @@ import { sessions, SessionState, broadcastToSession, handleWebSocketMessage } fr
|
||||
|
||||
const router = express.Router();
|
||||
|
||||
router.post('/sessions', (req, res) => {
|
||||
const sessionId = uuidv4();
|
||||
sessions.set(sessionId, {
|
||||
state: SessionState.SETUP,
|
||||
topic: null,
|
||||
description: null,
|
||||
expectedResponses: 0,
|
||||
submittedCount: 0,
|
||||
responses: new Map(),
|
||||
clients: new Map(),
|
||||
finalResult: null,
|
||||
});
|
||||
console.log(`New session created: ${sessionId}`);
|
||||
res.status(201).json({ sessionId });
|
||||
});
|
||||
|
||||
router.post('/sessions/:sessionId/responses', async (req, res) => {
|
||||
const { sessionId } = req.params;
|
||||
const { userId, wants, accepts, afraidToAsk } = req.body;
|
||||
|
||||
27
backend/src/services/AuthLogger.ts
Normal file
27
backend/src/services/AuthLogger.ts
Normal file
@@ -0,0 +1,27 @@
|
||||
// backend/src/services/AuthLogger.ts
|
||||
import * as fs from 'fs';
|
||||
import * as path from 'path';
|
||||
|
||||
const LOG_FILE_PATH = path.join(__dirname, '../../logs/auth.log');
|
||||
|
||||
export class AuthLogger {
|
||||
private static ensureLogFileExists() {
|
||||
const logDir = path.dirname(LOG_FILE_PATH);
|
||||
if (!fs.existsSync(logDir)) {
|
||||
fs.mkdirSync(logDir, { recursive: true });
|
||||
}
|
||||
if (!fs.existsSync(LOG_FILE_PATH)) {
|
||||
fs.writeFileSync(LOG_FILE_PATH, '', { encoding: 'utf8' });
|
||||
}
|
||||
}
|
||||
|
||||
public static logAttempt(
|
||||
type: 'success' | 'failure',
|
||||
ipAddress: string,
|
||||
timestamp: Date = new Date()
|
||||
): void {
|
||||
AuthLogger.ensureLogFileExists();
|
||||
const logEntry = `${timestamp.toISOString()} - ${type.toUpperCase()} - IP: ${ipAddress}\n`;
|
||||
fs.appendFileSync(LOG_FILE_PATH, logEntry, { encoding: 'utf8' });
|
||||
}
|
||||
}
|
||||
26
backend/src/services/AuthService.ts
Normal file
26
backend/src/services/AuthService.ts
Normal file
@@ -0,0 +1,26 @@
|
||||
// backend/src/services/AuthService.ts
|
||||
import * as dotenv from 'dotenv';
|
||||
import * as path from 'path';
|
||||
|
||||
dotenv.config({ path: path.resolve(__dirname, '../../.env') });
|
||||
|
||||
export class AuthService {
|
||||
private static passphrase: string | undefined = process.env.AUTH_PASSPHRASE;
|
||||
|
||||
public static getPassphrase(): string | undefined {
|
||||
return AuthService.passphrase;
|
||||
}
|
||||
|
||||
public static isAuthEnabled(): boolean {
|
||||
return !!AuthService.passphrase && AuthService.passphrase.trim() !== '';
|
||||
}
|
||||
|
||||
public static validatePassphrase(inputPassphrase: string): boolean {
|
||||
console.log('AuthService: AUTH_PASSPHRASE from process.env:', process.env.AUTH_PASSPHRASE);
|
||||
console.log('AuthService: Stored passphrase:', AuthService.passphrase);
|
||||
if (!AuthService.isAuthEnabled()) {
|
||||
return true; // If auth is not enabled, any passphrase is "valid"
|
||||
}
|
||||
return inputPassphrase === AuthService.passphrase;
|
||||
}
|
||||
}
|
||||
41
backend/src/services/SessionService.ts
Normal file
41
backend/src/services/SessionService.ts
Normal file
@@ -0,0 +1,41 @@
|
||||
// backend/src/services/SessionService.ts
|
||||
import { v4 as uuidv4 } from 'uuid';
|
||||
|
||||
interface Session {
|
||||
id: string;
|
||||
isAuthenticated: boolean;
|
||||
createdAt: Date;
|
||||
}
|
||||
|
||||
const sessions = new Map<string, Session>();
|
||||
|
||||
export class SessionService {
|
||||
public static createSession(): Session {
|
||||
const id = uuidv4();
|
||||
const newSession: Session = {
|
||||
id,
|
||||
isAuthenticated: false,
|
||||
createdAt: new Date(),
|
||||
};
|
||||
sessions.set(id, newSession);
|
||||
return newSession;
|
||||
}
|
||||
|
||||
public static getSession(id: string): Session | undefined {
|
||||
return sessions.get(id);
|
||||
}
|
||||
|
||||
public static authenticateSession(id: string): boolean {
|
||||
const session = sessions.get(id);
|
||||
if (session) {
|
||||
session.isAuthenticated = true;
|
||||
sessions.set(id, session);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static destroySession(id: string): void {
|
||||
sessions.delete(id);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user