import * as fs from "fs"; import * as https from "https"; import { WebSocketServer } from "ws"; import * as crypto from "crypto"; import type { AckMessage, IdResponseMessage, TextMessage, } from "./lib/ServerMessage"; import { isServerMessage, isTextMessage, MessageType, } from "./lib/ServerMessage"; const SALT = crypto.randomBytes(2048).toString("hex"); const port = 8085; const timeout = 15000; const httpsServer = https.createServer({ key: fs.readFileSync("./key.pem"), cert: fs.readFileSync("./cert.pem"), }); const webSocketServer = new WebSocketServer({ server: httpsServer }); console.log("listening on port: " + port); function hash(str: string) { return crypto.createHash("SHAKE256").update(str, "utf-8").digest("hex"); } async function handleTextMessage(message: TextMessage, from: string) { for (const to of webSocketServer.clients) { to.send( JSON.stringify( Object.assign({}, message, { author: from, }) ) ); } } async function handleCloseConnection(id: string) { activeConnections.delete(id); } const activeConnections = new Set(); let nextId = 0; webSocketServer.on("connection", function connection(socket) { const close = (reason: string, code: number = 1000) => { socket.send( JSON.stringify({ type: MessageType.ACK, date: Date.now(), __ctx: `closing connection. reason: ${reason}`, } as AckMessage) ); socket.close(code, `closing connection. reason: ${reason}`); handleCloseConnection(authorId); }; const authorId: string = hash(nextId++ + SALT); socket.on("message", function (rawMessage: string) { const message = JSON.parse(rawMessage); if (!isServerMessage(message)) { console.error(`Unexpected message received from client \`${message}\``); return; } if (isTextMessage(message)) { if (message.author === authorId) { handleTextMessage(message, authorId); } } clearTimeout(closeTimeout); closeTimeout = setTimeout(close, timeout); }); socket.on("close", function close() { console.log("closed a connection"); }); console.log("new client connected! ID:", authorId); socket.send( JSON.stringify({ type: MessageType.ID_RESPONSE, __ctx: "connected successfully", date: Date.now(), authorId, } as IdResponseMessage) ); activeConnections.add(authorId); let closeTimeout = setTimeout(close, timeout); }); httpsServer.listen(port);