From 9a942aa2ddbd4cb976ac11d80392539bcd6ff5b3 Mon Sep 17 00:00:00 2001 From: Lars van Vianen Date: Sun, 22 Dec 2024 08:57:10 +0100 Subject: [PATCH] Update LiveReloadServer.ts --- src/ts/core/LiveReloadServer.ts | 122 +++++++++++++++++++++++--------- 1 file changed, 90 insertions(+), 32 deletions(-) diff --git a/src/ts/core/LiveReloadServer.ts b/src/ts/core/LiveReloadServer.ts index 91b8d9a..0f4da78 100644 --- a/src/ts/core/LiveReloadServer.ts +++ b/src/ts/core/LiveReloadServer.ts @@ -5,10 +5,11 @@ // Import // ============================================================================ -import express, { Request, Response, NextFunction } from 'express'; -import path from 'path'; -import { Server } from 'http'; -import { WebSocketServer, WebSocket } from 'ws'; +import express, { Request, Response, NextFunction } from "express"; +import path from "path"; +import { Server } from "http"; +import { WebSocketServer, WebSocket } from "ws"; +import rateLimit from "express-rate-limit"; // ============================================================================ @@ -16,6 +17,7 @@ import { WebSocketServer, WebSocket } from 'ws'; // ============================================================================ export class LiveReloadServer { + private app = express(); private server: Server; private wss: WebSocketServer; @@ -43,20 +45,49 @@ export class LiveReloadServer { * Sets up WebSocket handlers to manage client connections. */ private setupWebSocketHandlers(): void { - this.wss.on('connection', (ws: WebSocket) => { - console.log('New WebSocket connection established.'); - this.clients.add(ws); - ws.on('close', () => { - console.log('WebSocket connection closed.'); - this.clients.delete(ws); - }); + this.wss.on( + "connection", + (ws: WebSocket) => { - ws.on('error', (error) => { - console.error('WebSocket encountered an error:', error); - this.clients.delete(ws); - }); - }); + console.log( + "New WebSocket connection established." + ); + this.clients.add(ws); + + ws.on( + "message", + (message) => { + console.log( + "WebSocket message received:", + message.toString() + ); + } + ); + + ws.on( + "close", + () => { + console.log( + "WebSocket connection closed.", + ); + this.clients.delete(ws); + } + ); + + ws.on( + "error", + (error) => { + console.error( + "WebSocket encountered an error:", + error + ); + this.clients.delete(ws); + } + ); + + } + ); } /** @@ -64,13 +95,27 @@ export class LiveReloadServer { * reload script into HTML files. */ private setupMiddleware(): void { - // Serve static files from the 'public' directory - this.app.use(express.static(path.join(__dirname, 'public'))); + // Serve static files from the "public" directory + // Securely resolve public directory + const publicPath = path.resolve( + __dirname, + "public" + ); + this.app.use(express.static(publicPath)); - // Middleware to inject live reload script into HTML responses - this.app.use(this.injectLiveReloadScript.bind(this)); + // Apply rate limiting to the live reload script injection middleware + const rateLimiter = rateLimit({ + windowMs: 15 * 60 * 1000, // 15 minutes + max: 100, // Limit each IP to 100 requests per `windowMs` + message: "Too many requests from this IP, please try again later.", + }); + + // Use rate limiter and inject middleware + this.app.use(rateLimiter, this.injectLiveReloadScript.bind(this)); } + + /** * Middleware function to inject the live reload script into HTML files. * @param req - The HTTP request object. @@ -82,17 +127,24 @@ export class LiveReloadServer { res: Response, next: NextFunction ): void { - if (req.url.endsWith('.html')) { - res.sendFile(path.join(__dirname, 'public', req.url), (err) => { + if (req.url.endsWith(".html")) { + const sanitizedPath = path.join( + path.resolve(__dirname, "public"), + // Prevent directory traversal + path.normalize(req.url).replace(/^(\.\.(\/|\\|$))+/g, "") + ); + + res.sendFile(sanitizedPath, (err) => { if (err) { + console.error("Error sending HTML file:", err); next(err); } else { res.write( `