mirror of
https://github.com/bluewave-labs/Checkmate.git
synced 2026-05-19 07:58:46 -05:00
sanitization ts
This commit is contained in:
Generated
+20
@@ -51,6 +51,7 @@
|
||||
"@types/gamedig": "^5.0.3",
|
||||
"@types/jest": "^30.0.0",
|
||||
"@types/jmespath": "^0.15.2",
|
||||
"@types/jsdom": "^27.0.0",
|
||||
"@types/jsonwebtoken": "9.0.10",
|
||||
"@types/mjml": "^4.7.4",
|
||||
"@types/multer": "^2.0.0",
|
||||
@@ -4453,6 +4454,18 @@
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@types/jsdom": {
|
||||
"version": "27.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/jsdom/-/jsdom-27.0.0.tgz",
|
||||
"integrity": "sha512-NZyFl/PViwKzdEkQg96gtnB8wm+1ljhdDay9ahn4hgb+SfVtPCbm3TlmDUFXTA+MGN3CijicnMhG18SI5H3rFw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/node": "*",
|
||||
"@types/tough-cookie": "*",
|
||||
"parse5": "^7.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/json-schema": {
|
||||
"version": "7.0.15",
|
||||
"resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz",
|
||||
@@ -4637,6 +4650,13 @@
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@types/tough-cookie": {
|
||||
"version": "4.0.5",
|
||||
"resolved": "https://registry.npmjs.org/@types/tough-cookie/-/tough-cookie-4.0.5.tgz",
|
||||
"integrity": "sha512-/Ad8+nIOV7Rl++6f1BdKxFSMgmoqEoYbHRpPcx3JEfv8VRsQe9Z4mCXeJBzxs7mbHY/XOZZuXlRNfhpVPbs6ZA==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@types/triple-beam": {
|
||||
"version": "1.3.5",
|
||||
"resolved": "https://registry.npmjs.org/@types/triple-beam/-/triple-beam-1.3.5.tgz",
|
||||
|
||||
@@ -63,6 +63,7 @@
|
||||
"@types/gamedig": "^5.0.3",
|
||||
"@types/jest": "^30.0.0",
|
||||
"@types/jmespath": "^0.15.2",
|
||||
"@types/jsdom": "^27.0.0",
|
||||
"@types/jsonwebtoken": "9.0.10",
|
||||
"@types/mjml": "^4.7.4",
|
||||
"@types/multer": "^2.0.0",
|
||||
|
||||
@@ -41,13 +41,6 @@ class MonitorController {
|
||||
return MonitorController.SERVICE_NAME;
|
||||
}
|
||||
|
||||
async verifyTeamAccess(teamId: string, monitorId: string) {
|
||||
const monitor = await this.monitorService.getMonitorById({ teamId, monitorId });
|
||||
if (monitor.teamId !== teamId) {
|
||||
throw new AppError({ message: "Access denied", status: 403 });
|
||||
}
|
||||
}
|
||||
|
||||
getMonitorCertificate = async (req: Request, res: Response, next: NextFunction) => {
|
||||
try {
|
||||
await getCertificateParamValidation.validateAsync(req.params);
|
||||
|
||||
@@ -1,85 +0,0 @@
|
||||
import { JSDOM } from "jsdom";
|
||||
import DOMPurify from "isomorphic-dompurify";
|
||||
|
||||
// Initialize DOMPurify with jsdom
|
||||
const window = new JSDOM("").window;
|
||||
const purify = DOMPurify(window);
|
||||
|
||||
/**
|
||||
* Sanitizes user input to prevent XSS attacks
|
||||
* @param {string} input - The input string to sanitize
|
||||
* @param {Object} options - Sanitization options
|
||||
* @returns {string} The sanitized string
|
||||
*/
|
||||
export const sanitizeInput = (input, options = {}) => {
|
||||
if (typeof input !== "string") {
|
||||
return input;
|
||||
}
|
||||
|
||||
// Default configuration - remove all HTML tags and attributes
|
||||
const defaultConfig = {
|
||||
ALLOWED_TAGS: [],
|
||||
ALLOWED_ATTR: [],
|
||||
KEEP_CONTENT: true,
|
||||
...options,
|
||||
};
|
||||
|
||||
return purify.sanitize(input, defaultConfig);
|
||||
};
|
||||
|
||||
/**
|
||||
* Sanitizes an object recursively
|
||||
* @param {Object} obj - The object to sanitize
|
||||
* @param {Object} options - Sanitization options
|
||||
* @returns {Object} The sanitized object
|
||||
*/
|
||||
export const sanitizeObject = (obj, options = {}) => {
|
||||
if (typeof obj !== "object" || obj === null) {
|
||||
return obj;
|
||||
}
|
||||
|
||||
if (Array.isArray(obj)) {
|
||||
return obj.map((item) => sanitizeObject(item, options));
|
||||
}
|
||||
|
||||
const sanitized = {};
|
||||
for (const [key, value] of Object.entries(obj)) {
|
||||
if (typeof value === "string") {
|
||||
sanitized[key] = sanitizeInput(value, options);
|
||||
} else if (typeof value === "object" && value !== null) {
|
||||
sanitized[key] = sanitizeObject(value, options);
|
||||
} else {
|
||||
sanitized[key] = value;
|
||||
}
|
||||
}
|
||||
|
||||
return sanitized;
|
||||
};
|
||||
|
||||
/**
|
||||
* Express middleware for sanitizing request body
|
||||
* @param {Object} options - Sanitization options
|
||||
* @returns {Function} Express middleware function
|
||||
*/
|
||||
export const sanitizeBody = (options = {}) => {
|
||||
return (req, res, next) => {
|
||||
if (req.body && typeof req.body === "object") {
|
||||
req.body = sanitizeObject(req.body, options);
|
||||
}
|
||||
next();
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Express middleware for sanitizing query parameters
|
||||
* @param {Object} options - Sanitization options
|
||||
* @returns {Function} Express middleware function
|
||||
*/
|
||||
export const sanitizeQuery = (options = {}) => {
|
||||
return (req, res, next) => {
|
||||
if (req.query && typeof req.query === "object") {
|
||||
req.query = sanitizeObject(req.query, options);
|
||||
}
|
||||
next();
|
||||
};
|
||||
};
|
||||
@@ -0,0 +1,59 @@
|
||||
import type { Request, Response, NextFunction } from "express";
|
||||
import DOMPurify from "isomorphic-dompurify";
|
||||
|
||||
export const sanitizeInput = (input: any, options = {}) => {
|
||||
if (typeof input !== "string") {
|
||||
return input;
|
||||
}
|
||||
|
||||
// Default configuration - remove all HTML tags and attributes
|
||||
const defaultConfig = {
|
||||
ALLOWED_TAGS: [] as string[],
|
||||
ALLOWED_ATTR: [] as string[],
|
||||
KEEP_CONTENT: true,
|
||||
...options,
|
||||
};
|
||||
|
||||
return DOMPurify.sanitize(input, defaultConfig);
|
||||
};
|
||||
|
||||
export const sanitizeObject = (obj: Record<string, any>, options = {}): Record<string, any> => {
|
||||
if (typeof obj !== "object" || obj === null) {
|
||||
return obj;
|
||||
}
|
||||
|
||||
if (Array.isArray(obj)) {
|
||||
return obj.map((item) => sanitizeObject(item, options));
|
||||
}
|
||||
|
||||
const sanitized: Record<string, any> = {};
|
||||
for (const [key, value] of Object.entries(obj)) {
|
||||
if (typeof value === "string") {
|
||||
sanitized[key] = sanitizeInput(value, options);
|
||||
} else if (typeof value === "object" && value !== null) {
|
||||
sanitized[key] = sanitizeObject(value, options);
|
||||
} else {
|
||||
sanitized[key] = value;
|
||||
}
|
||||
}
|
||||
|
||||
return sanitized;
|
||||
};
|
||||
|
||||
export const sanitizeBody = (options = {}): ((req: Request, res: Response, next: NextFunction) => void) => {
|
||||
return (req: Request, res: Response, next: NextFunction) => {
|
||||
if (req.body && typeof req.body === "object") {
|
||||
req.body = sanitizeObject(req.body, options);
|
||||
}
|
||||
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);
|
||||
}
|
||||
next();
|
||||
};
|
||||
};
|
||||
@@ -1,38 +0,0 @@
|
||||
const SERVICE_NAME = "verifyTeamAccess";
|
||||
|
||||
const verifyTeamAccess = (Model, paramName) => {
|
||||
return async (req, res, next) => {
|
||||
try {
|
||||
const documentId = req.params[paramName];
|
||||
const doc = await Model.findById(documentId);
|
||||
|
||||
if (!doc) {
|
||||
const error = new Error("Document not found");
|
||||
error.status = 404;
|
||||
throw error;
|
||||
}
|
||||
|
||||
if (!req?.user?.teamId || !doc.teamId) {
|
||||
const error = new Error("Missing team information");
|
||||
error.status = 400;
|
||||
throw error;
|
||||
}
|
||||
|
||||
if (req.user.teamId.toString() === doc.teamId.toString()) {
|
||||
next();
|
||||
return;
|
||||
}
|
||||
|
||||
const error = new Error("Unauthorized");
|
||||
error.status = 403;
|
||||
throw error;
|
||||
} catch (error) {
|
||||
error.service = SERVICE_NAME;
|
||||
error.method = "verifyTeamAccess";
|
||||
next(error);
|
||||
return;
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
export { verifyTeamAccess };
|
||||
@@ -1,63 +0,0 @@
|
||||
const SERVICE_NAME = "ServiceRegistry";
|
||||
|
||||
class ServiceRegistry {
|
||||
static SERVICE_NAME = SERVICE_NAME;
|
||||
|
||||
constructor({ logger }) {
|
||||
this.services = {};
|
||||
this.logger = logger;
|
||||
}
|
||||
|
||||
get serviceName() {
|
||||
return ServiceRegistry.SERVICE_NAME;
|
||||
}
|
||||
|
||||
// Instance methods
|
||||
register(name, service) {
|
||||
this.logger.info({
|
||||
message: `Registering service ${name}`,
|
||||
service: SERVICE_NAME,
|
||||
method: "register",
|
||||
});
|
||||
this.services[name] = service;
|
||||
}
|
||||
|
||||
get(name) {
|
||||
if (!this.services[name]) {
|
||||
this.logger.error({
|
||||
message: `Service ${name} is not registered`,
|
||||
service: SERVICE_NAME,
|
||||
method: "get",
|
||||
});
|
||||
throw new Error(`Service ${name} is not registered`);
|
||||
}
|
||||
return this.services[name];
|
||||
}
|
||||
|
||||
listServices() {
|
||||
return Object.keys(this.services);
|
||||
}
|
||||
|
||||
static get(name) {
|
||||
if (!ServiceRegistry.instance) {
|
||||
throw new Error("ServiceRegistry not initialized");
|
||||
}
|
||||
return ServiceRegistry.instance.get(name);
|
||||
}
|
||||
|
||||
static register(name, service) {
|
||||
if (!ServiceRegistry.instance) {
|
||||
throw new Error("ServiceRegistry not initialized");
|
||||
}
|
||||
return ServiceRegistry.instance.register(name, service);
|
||||
}
|
||||
|
||||
static listServices() {
|
||||
if (!ServiceRegistry.instance) {
|
||||
throw new Error("ServiceRegistry not initialized");
|
||||
}
|
||||
return ServiceRegistry.instance.listServices();
|
||||
}
|
||||
}
|
||||
|
||||
export default ServiceRegistry;
|
||||
Reference in New Issue
Block a user