From ef6546c0e16bf294290c18e55cef60b2f1acee49 Mon Sep 17 00:00:00 2001 From: The-Best-Codes Date: Sat, 23 Nov 2024 19:52:39 -0600 Subject: [PATCH] Escape HTML in messages and usernames --- index.ts | 8 +++++--- src/constants.ts | 9 +++++++++ src/db/database.ts | 5 ++++- 3 files changed, 18 insertions(+), 4 deletions(-) diff --git a/index.ts b/index.ts index 5bb92a1..79d002e 100644 --- a/index.ts +++ b/index.ts @@ -5,7 +5,7 @@ import { getRecentMessages, type User, } from "./src/db/database"; -import { LIMITS, validateInput } from "./src/constants"; +import { LIMITS, validateInput, escapeHtml } from "./src/constants"; import crypto from "crypto"; const port = process.env.PORT || 5177; @@ -212,13 +212,15 @@ const server: any = Bun.serve({ data.content, LIMITS.MESSAGE_MAX_LENGTH ); - const msg = await createMessage(user.id, validatedContent); + // Escape HTML in the message + const safeContent = escapeHtml(validatedContent); + const msg = await createMessage(user.id, safeContent); server.publish( "chat", JSON.stringify({ type: "message", username: user.username, - content: validatedContent, + content: safeContent, timestamp: new Date().toISOString(), }) ); diff --git a/src/constants.ts b/src/constants.ts index 726623c..0fac109 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -4,6 +4,15 @@ export const LIMITS = { MESSAGE_MAX_LENGTH: 2000, } as const; +export function escapeHtml(unsafe: string): string { + return unsafe + .replace(/&/g, "&") + .replace(//g, ">") + .replace(/"/g, """) + .replace(/'/g, "'"); +} + export function validateInput(input: string, maxLength: number): string { if (!input || typeof input !== "string") { throw new Error("Invalid input"); diff --git a/src/db/database.ts b/src/db/database.ts index 217e686..54e590d 100644 --- a/src/db/database.ts +++ b/src/db/database.ts @@ -1,6 +1,6 @@ import { Database } from "bun:sqlite"; import * as bcrypt from "bcryptjs"; -import { LIMITS, validateInput } from "../constants"; +import { LIMITS, validateInput, escapeHtml } from "../constants"; const DB_PATH = process.env.DB_PATH || `${process.cwd()}/chat.db`; const SCHEMA_PATH = @@ -40,6 +40,9 @@ export const createUser = async ( username = validateInput(username, LIMITS.USERNAME_MAX_LENGTH); password = validateInput(password, LIMITS.PASSWORD_MAX_LENGTH); + // Escape HTML in username + username = escapeHtml(username); + const hashedPassword = await bcrypt.hash(password, 10); try { const stmt = db.prepare(