fix: add try/catch around websocket message event handler #2529
@ -1,16 +1,11 @@
 | 
				
			|||||||
import { NextFunction, Request, Response } from "express";
 | 
					import { NextFunction, Request, Response } from "express";
 | 
				
			||||||
import { logger } from "@/src/utils/logger";
 | 
					import { logError } from "@/src/utils/logger";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const errorHandler = (err: Error, req: Request, res: Response, _next: NextFunction): void => {
 | 
					export const errorHandler = (err: Error, req: Request, res: Response, _next: NextFunction): void => {
 | 
				
			||||||
    if (err.message == "Invalid accountId-nonce pair") {
 | 
					    if (err.message == "Invalid accountId-nonce pair") {
 | 
				
			||||||
        res.status(400).send("Log-in expired");
 | 
					        res.status(400).send("Log-in expired");
 | 
				
			||||||
    } else if (err.stack) {
 | 
					 | 
				
			||||||
        const stackArr = err.stack.split("\n");
 | 
					 | 
				
			||||||
        stackArr[0] += ` while processing ${req.path} request`;
 | 
					 | 
				
			||||||
        logger.error(stackArr.join("\n"));
 | 
					 | 
				
			||||||
        res.status(500).end();
 | 
					 | 
				
			||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
        logger.error(`uncaught error while processing ${req.path} request: ${err.message}`);
 | 
					        logError(err, `processing ${req.path} request`);
 | 
				
			||||||
        res.status(500).end();
 | 
					        res.status(500).end();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
				
			|||||||
@ -5,6 +5,7 @@ import { Account } from "@/src/models/loginModel";
 | 
				
			|||||||
import { createAccount, createNonce, getUsernameFromEmail, isCorrectPassword } from "@/src/services/loginService";
 | 
					import { createAccount, createNonce, getUsernameFromEmail, isCorrectPassword } from "@/src/services/loginService";
 | 
				
			||||||
import { IDatabaseAccountJson } from "@/src/types/loginTypes";
 | 
					import { IDatabaseAccountJson } from "@/src/types/loginTypes";
 | 
				
			||||||
import { HydratedDocument } from "mongoose";
 | 
					import { HydratedDocument } from "mongoose";
 | 
				
			||||||
 | 
					import { logError } from "../utils/logger";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
let wsServer: ws.Server | undefined;
 | 
					let wsServer: ws.Server | undefined;
 | 
				
			||||||
let wssServer: ws.Server | undefined;
 | 
					let wssServer: ws.Server | undefined;
 | 
				
			||||||
@ -88,63 +89,67 @@ const wsOnConnect = (ws: ws, req: http.IncomingMessage): void => {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    // eslint-disable-next-line @typescript-eslint/no-misused-promises
 | 
					    // eslint-disable-next-line @typescript-eslint/no-misused-promises
 | 
				
			||||||
    ws.on("message", async msg => {
 | 
					    ws.on("message", async msg => {
 | 
				
			||||||
        const data = JSON.parse(String(msg)) as IWsMsgFromClient;
 | 
					        try {
 | 
				
			||||||
        if (data.auth) {
 | 
					            const data = JSON.parse(String(msg)) as IWsMsgFromClient;
 | 
				
			||||||
            let account: IDatabaseAccountJson | null = await Account.findOne({ email: data.auth.email });
 | 
					            if (data.auth) {
 | 
				
			||||||
            if (account) {
 | 
					                let account: IDatabaseAccountJson | null = await Account.findOne({ email: data.auth.email });
 | 
				
			||||||
                if (isCorrectPassword(data.auth.password, account.password)) {
 | 
					                if (account) {
 | 
				
			||||||
                    if (!account.Nonce) {
 | 
					                    if (isCorrectPassword(data.auth.password, account.password)) {
 | 
				
			||||||
                        account.ClientType = "webui";
 | 
					                        if (!account.Nonce) {
 | 
				
			||||||
                        account.Nonce = createNonce();
 | 
					                            account.ClientType = "webui";
 | 
				
			||||||
                        await (account as HydratedDocument<IDatabaseAccountJson>).save();
 | 
					                            account.Nonce = createNonce();
 | 
				
			||||||
 | 
					                            await (account as HydratedDocument<IDatabaseAccountJson>).save();
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    } else {
 | 
				
			||||||
 | 
					                        account = null;
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
 | 
					                } else if (data.auth.isRegister) {
 | 
				
			||||||
 | 
					                    const name = await getUsernameFromEmail(data.auth.email);
 | 
				
			||||||
 | 
					                    account = await createAccount({
 | 
				
			||||||
 | 
					                        email: data.auth.email,
 | 
				
			||||||
 | 
					                        password: data.auth.password,
 | 
				
			||||||
 | 
					                        ClientType: "webui",
 | 
				
			||||||
 | 
					                        LastLogin: new Date(),
 | 
				
			||||||
 | 
					                        DisplayName: name,
 | 
				
			||||||
 | 
					                        Nonce: createNonce()
 | 
				
			||||||
 | 
					                    });
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                if (account) {
 | 
				
			||||||
 | 
					                    (ws as IWsCustomData).accountId = account.id;
 | 
				
			||||||
 | 
					                    ws.send(
 | 
				
			||||||
 | 
					                        JSON.stringify({
 | 
				
			||||||
 | 
					                            auth_succ: {
 | 
				
			||||||
 | 
					                                id: account.id,
 | 
				
			||||||
 | 
					                                DisplayName: account.DisplayName,
 | 
				
			||||||
 | 
					                                Nonce: account.Nonce
 | 
				
			||||||
 | 
					                            }
 | 
				
			||||||
 | 
					                        } satisfies IWsMsgToClient)
 | 
				
			||||||
 | 
					                    );
 | 
				
			||||||
                } else {
 | 
					                } else {
 | 
				
			||||||
                    account = null;
 | 
					                    ws.send(
 | 
				
			||||||
 | 
					                        JSON.stringify({
 | 
				
			||||||
 | 
					                            auth_fail: {
 | 
				
			||||||
 | 
					                                isRegister: data.auth.isRegister
 | 
				
			||||||
 | 
					                            }
 | 
				
			||||||
 | 
					                        } satisfies IWsMsgToClient)
 | 
				
			||||||
 | 
					                    );
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            } else if (data.auth.isRegister) {
 | 
					 | 
				
			||||||
                const name = await getUsernameFromEmail(data.auth.email);
 | 
					 | 
				
			||||||
                account = await createAccount({
 | 
					 | 
				
			||||||
                    email: data.auth.email,
 | 
					 | 
				
			||||||
                    password: data.auth.password,
 | 
					 | 
				
			||||||
                    ClientType: "webui",
 | 
					 | 
				
			||||||
                    LastLogin: new Date(),
 | 
					 | 
				
			||||||
                    DisplayName: name,
 | 
					 | 
				
			||||||
                    Nonce: createNonce()
 | 
					 | 
				
			||||||
                });
 | 
					 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            if (account) {
 | 
					            if (data.logout) {
 | 
				
			||||||
                (ws as IWsCustomData).accountId = account.id;
 | 
					                const accountId = (ws as IWsCustomData).accountId;
 | 
				
			||||||
                ws.send(
 | 
					                (ws as IWsCustomData).accountId = undefined;
 | 
				
			||||||
                    JSON.stringify({
 | 
					                await Account.updateOne(
 | 
				
			||||||
                        auth_succ: {
 | 
					                    {
 | 
				
			||||||
                            id: account.id,
 | 
					                        _id: accountId,
 | 
				
			||||||
                            DisplayName: account.DisplayName,
 | 
					                        ClientType: "webui"
 | 
				
			||||||
                            Nonce: account.Nonce
 | 
					                    },
 | 
				
			||||||
                        }
 | 
					                    {
 | 
				
			||||||
                    } satisfies IWsMsgToClient)
 | 
					                        Nonce: 0
 | 
				
			||||||
                );
 | 
					                    }
 | 
				
			||||||
            } else {
 | 
					 | 
				
			||||||
                ws.send(
 | 
					 | 
				
			||||||
                    JSON.stringify({
 | 
					 | 
				
			||||||
                        auth_fail: {
 | 
					 | 
				
			||||||
                            isRegister: data.auth.isRegister
 | 
					 | 
				
			||||||
                        }
 | 
					 | 
				
			||||||
                    } satisfies IWsMsgToClient)
 | 
					 | 
				
			||||||
                );
 | 
					                );
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        } catch (e) {
 | 
				
			||||||
        if (data.logout) {
 | 
					            logError(e as Error, `processing websocket message`);
 | 
				
			||||||
            const accountId = (ws as IWsCustomData).accountId;
 | 
					 | 
				
			||||||
            (ws as IWsCustomData).accountId = undefined;
 | 
					 | 
				
			||||||
            await Account.updateOne(
 | 
					 | 
				
			||||||
                {
 | 
					 | 
				
			||||||
                    _id: accountId,
 | 
					 | 
				
			||||||
                    ClientType: "webui"
 | 
					 | 
				
			||||||
                },
 | 
					 | 
				
			||||||
                {
 | 
					 | 
				
			||||||
                    Nonce: 0
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
            );
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
				
			|||||||
@ -108,3 +108,13 @@ errorLog.on("new", filename => logger.info(`Using error log file: ${filename}`))
 | 
				
			|||||||
combinedLog.on("new", filename => logger.info(`Using combined log file: ${filename}`));
 | 
					combinedLog.on("new", filename => logger.info(`Using combined log file: ${filename}`));
 | 
				
			||||||
errorLog.on("rotate", filename => logger.info(`Rotated error log file: ${filename}`));
 | 
					errorLog.on("rotate", filename => logger.info(`Rotated error log file: ${filename}`));
 | 
				
			||||||
combinedLog.on("rotate", filename => logger.info(`Rotated combined log file: ${filename}`));
 | 
					combinedLog.on("rotate", filename => logger.info(`Rotated combined log file: ${filename}`));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const logError = (err: Error, context: string): void => {
 | 
				
			||||||
 | 
					    if (err.stack) {
 | 
				
			||||||
 | 
					        const stackArr = err.stack.split("\n");
 | 
				
			||||||
 | 
					        stackArr[0] += ` while ${context}`;
 | 
				
			||||||
 | 
					        logger.error(stackArr.join("\n"));
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        logger.error(`uncaught error while ${context}: ${err.message}`);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user