Merge pull request #3418 from bluewave-labs/fix/middleware-typing
fix: middleware typing
This commit is contained in:
7 files changed
+44
-28
No files matched your search
@@ -37,6 +37,7 @@ export default [
|
||||
},
|
||||
},
|
||||
rules: {
|
||||
"@typescript-eslint/no-unused-vars": ["error", { argsIgnorePattern: "^_" }], // Ignore unused variables that start with '_'
|
||||
"@typescript-eslint/no-explicit-any": "warn", // Warn on 'any' types
|
||||
"mocha/max-top-level-suites": "warn", // Warn if there are too many top-level suites instead of failing
|
||||
},
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Schema, model, type Types } from "mongoose";
|
||||
import type { MaintenanceWindow, DurationUnit } from "@/types/maintenanceWindow.js";
|
||||
import type { MaintenanceWindow } from "@/types/maintenanceWindow.js";
|
||||
|
||||
type MaintenanceWindowDocumentBase = Omit<MaintenanceWindow, "id" | "monitorId" | "teamId" | "start" | "end" | "createdAt" | "updatedAt"> & {
|
||||
monitorId: Types.ObjectId;
|
||||
|
||||
@@ -1,15 +1,18 @@
|
||||
import type { NextFunction, Request, Response } from "express";
|
||||
import { logger } from "@/utils/logger.js";
|
||||
import { AppError } from "@/utils/AppError.js";
|
||||
|
||||
const handleErrors = (error: any, req: Request, res: Response, next: NextFunction) => {
|
||||
const status = error.status || 500;
|
||||
const message = error.message || "Server error";
|
||||
const service = error.service || "unknownService";
|
||||
const handleErrors = (error: unknown, req: Request, res: Response, _next: NextFunction) => {
|
||||
const status = error instanceof AppError ? error.status || 500 : 500;
|
||||
const message = error instanceof AppError ? error.message : "Server error";
|
||||
const service = error instanceof AppError ? error.service : "unknownService";
|
||||
const method = error instanceof AppError ? error.method : "unknownMethod";
|
||||
logger.error({
|
||||
message: message,
|
||||
service: service,
|
||||
method: error.method,
|
||||
stack: error.stack,
|
||||
method: method,
|
||||
stack: error instanceof AppError ? error.stack : undefined,
|
||||
details: error instanceof AppError ? error.details : undefined,
|
||||
});
|
||||
res.status(status).json({
|
||||
status,
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
import type { Request, Response, NextFunction } from "express";
|
||||
import DOMPurify from "isomorphic-dompurify";
|
||||
|
||||
export const sanitizeInput = (input: any, options = {}) => {
|
||||
export function sanitizeInput(input: string, options?: object): string;
|
||||
export function sanitizeInput(input: unknown, options?: object): unknown;
|
||||
export function sanitizeInput(input: unknown, options = {}): unknown {
|
||||
if (typeof input !== "string") {
|
||||
return input;
|
||||
}
|
||||
@@ -15,9 +17,9 @@ export const sanitizeInput = (input: any, options = {}) => {
|
||||
};
|
||||
|
||||
return DOMPurify.sanitize(input, defaultConfig);
|
||||
};
|
||||
}
|
||||
|
||||
export const sanitizeObject = (obj: Record<string, any>, options = {}): Record<string, any> => {
|
||||
export const sanitizeObject = (obj: unknown, options = {}): unknown => {
|
||||
if (typeof obj !== "object" || obj === null) {
|
||||
return obj;
|
||||
}
|
||||
@@ -26,7 +28,7 @@ export const sanitizeObject = (obj: Record<string, any>, options = {}): Record<s
|
||||
return obj.map((item) => sanitizeObject(item, options));
|
||||
}
|
||||
|
||||
const sanitized: Record<string, any> = {};
|
||||
const sanitized: Record<string, unknown> = {};
|
||||
for (const [key, value] of Object.entries(obj)) {
|
||||
if (typeof value === "string") {
|
||||
sanitized[key] = sanitizeInput(value, options);
|
||||
@@ -52,7 +54,12 @@ export const sanitizeBody = (options = {}): ((req: Request, res: Response, next:
|
||||
export const sanitizeQuery = (options = {}): ((req: Request, res: Response, next: NextFunction) => void) => {
|
||||
return (req: Request, res: Response, next: NextFunction) => {
|
||||
if (req.query && typeof req.query === "object") {
|
||||
req.query = sanitizeObject(req.query, options);
|
||||
for (const key of Object.keys(req.query)) {
|
||||
const value = req.query[key];
|
||||
if (typeof value === "string") {
|
||||
req.query[key] = sanitizeInput(value, options);
|
||||
}
|
||||
}
|
||||
}
|
||||
next();
|
||||
};
|
||||
|
||||
@@ -3,10 +3,15 @@ import { NextFunction, Request, Response } from "express";
|
||||
import jwt from "jsonwebtoken";
|
||||
import { AppError } from "@/utils/AppError.js";
|
||||
import { Settings } from "@/types/settings.js";
|
||||
import type { User } from "@/types/user.js";
|
||||
|
||||
const SERVICE_NAME = "verifyJWT";
|
||||
const TOKEN_PREFIX = "Bearer ";
|
||||
|
||||
const isUser = (payload: unknown): payload is User => {
|
||||
return typeof payload === "object" && payload !== null && "id" in payload && "teamId" in payload && "role" in payload;
|
||||
};
|
||||
|
||||
export const createVerifyJWT = (settingsService: { getSettings: () => Settings }) => {
|
||||
return (req: Request, res: Response, next: NextFunction) => {
|
||||
const token = req.headers["authorization"];
|
||||
@@ -31,21 +36,22 @@ export const createVerifyJWT = (settingsService: { getSettings: () => Settings }
|
||||
next(error);
|
||||
return;
|
||||
}
|
||||
jwt.verify(parsedToken, jwtSecret, (err: any, decoded: any) => {
|
||||
jwt.verify(parsedToken, jwtSecret, (err: jwt.VerifyErrors | null, decoded: jwt.JwtPayload | string | undefined) => {
|
||||
if (err) {
|
||||
const error = new AppError({
|
||||
message: "Failed to authenticate token",
|
||||
details: err,
|
||||
message: err instanceof Error ? err.message : "Failed to authenticate token",
|
||||
status: 401,
|
||||
service: SERVICE_NAME,
|
||||
details: err instanceof Error ? { error: err } : undefined,
|
||||
method: "verifyJWT",
|
||||
});
|
||||
next(error);
|
||||
return;
|
||||
} else {
|
||||
// Token is valid, carry on
|
||||
} else if (isUser(decoded)) {
|
||||
req.user = decoded;
|
||||
next();
|
||||
} else {
|
||||
next(new AppError({ message: "Invalid token payload", status: 401, service: SERVICE_NAME, method: "verifyJWT" }));
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
@@ -360,8 +360,7 @@ export class StatusService implements IStatusService {
|
||||
};
|
||||
} catch (error: unknown) {
|
||||
throw new AppError({
|
||||
message: `Failed to update monitor status: ${error instanceof Error ? error.message : "Unknown error"}`,
|
||||
details: `Error updating status for monitor with id ${check.metadata.monitorId}`,
|
||||
message: `Failed to update monitor with id ${check.metadata.monitorId} with status: ${error instanceof Error ? error.message : "Unknown error"}`,
|
||||
service: SERVICE_NAME,
|
||||
method: "updateMonitorStatus",
|
||||
});
|
||||
|
||||
@@ -1,18 +1,18 @@
|
||||
export interface AppErrorConfig {
|
||||
message: string;
|
||||
message?: string;
|
||||
status?: number;
|
||||
service?: string | null;
|
||||
method?: string | null;
|
||||
details?: unknown;
|
||||
service?: string;
|
||||
method?: string;
|
||||
details?: Record<string, unknown> | undefined;
|
||||
}
|
||||
|
||||
export class AppError extends Error {
|
||||
private status: number;
|
||||
private service: string | null;
|
||||
private method: string | null;
|
||||
private details: unknown;
|
||||
readonly status: number;
|
||||
readonly service: string;
|
||||
readonly method: string;
|
||||
readonly details: Record<string, unknown> | undefined;
|
||||
|
||||
constructor({ message, status = 500, service = null, method = null, details = null }: AppErrorConfig) {
|
||||
constructor({ message, status = 500, service = "unknownService", method = "unknownMethod", details = undefined }: AppErrorConfig) {
|
||||
super(message);
|
||||
this.status = status;
|
||||
this.service = service;
|
||||
|
||||
Reference in new issue
Block a user