refactor: optimize configuration and tool implementations
- Standardized error handling across tool implementations - Improved return type consistency for tool execution results - Simplified configuration parsing and type definitions - Enhanced type safety for various configuration schemas - Cleaned up and normalized tool response structures - Updated SSE and event subscription tool implementations
This commit is contained in:
@@ -1,109 +1,143 @@
|
||||
import { Request, Response, NextFunction } from 'express';
|
||||
import { validateRequest, sanitizeInput } from '../../src/security/middleware';
|
||||
import { Request, Response, NextFunction } from "express";
|
||||
import { validateRequest, sanitizeInput } from "../../src/security/middleware";
|
||||
|
||||
type MockRequest = {
|
||||
headers: {
|
||||
'content-type'?: string;
|
||||
authorization?: string;
|
||||
};
|
||||
body?: any;
|
||||
is: jest.MockInstance<string | false | null, [type: string | string[]]>;
|
||||
headers: {
|
||||
"content-type"?: string;
|
||||
authorization?: string;
|
||||
};
|
||||
body?: any;
|
||||
is: jest.MockInstance<string | false | null, [type: string | string[]]>;
|
||||
};
|
||||
|
||||
type MockResponse = {
|
||||
status: jest.MockInstance<MockResponse, [code: number]>;
|
||||
json: jest.MockInstance<MockResponse, [body: any]>;
|
||||
setHeader: jest.MockInstance<MockResponse, [name: string, value: string]>;
|
||||
status: jest.MockInstance<MockResponse, [code: number]>;
|
||||
json: jest.MockInstance<MockResponse, [body: any]>;
|
||||
setHeader: jest.MockInstance<MockResponse, [name: string, value: string]>;
|
||||
};
|
||||
|
||||
describe('Security Middleware', () => {
|
||||
let mockRequest: MockRequest;
|
||||
let mockResponse: MockResponse;
|
||||
let nextFunction: jest.Mock;
|
||||
describe("Security Middleware", () => {
|
||||
let mockRequest: MockRequest;
|
||||
let mockResponse: MockResponse;
|
||||
let nextFunction: jest.Mock;
|
||||
|
||||
beforeEach(() => {
|
||||
mockRequest = {
|
||||
headers: {},
|
||||
body: {},
|
||||
is: jest.fn<string | false | null, [string | string[]]>().mockReturnValue('json')
|
||||
};
|
||||
beforeEach(() => {
|
||||
mockRequest = {
|
||||
headers: {},
|
||||
body: {},
|
||||
is: jest
|
||||
.fn<string | false | null, [string | string[]]>()
|
||||
.mockReturnValue("json"),
|
||||
};
|
||||
|
||||
mockResponse = {
|
||||
status: jest.fn<MockResponse, [number]>().mockReturnThis(),
|
||||
json: jest.fn<MockResponse, [any]>().mockReturnThis(),
|
||||
setHeader: jest.fn<MockResponse, [string, string]>().mockReturnThis()
|
||||
};
|
||||
mockResponse = {
|
||||
status: jest.fn<MockResponse, [number]>().mockReturnThis(),
|
||||
json: jest.fn<MockResponse, [any]>().mockReturnThis(),
|
||||
setHeader: jest.fn<MockResponse, [string, string]>().mockReturnThis(),
|
||||
};
|
||||
|
||||
nextFunction = jest.fn();
|
||||
nextFunction = jest.fn();
|
||||
});
|
||||
|
||||
describe("validateRequest", () => {
|
||||
it("should pass valid requests", () => {
|
||||
mockRequest.headers.authorization = "Bearer valid-token";
|
||||
validateRequest(
|
||||
mockRequest as unknown as Request,
|
||||
mockResponse as unknown as Response,
|
||||
nextFunction,
|
||||
);
|
||||
expect(nextFunction).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
describe('validateRequest', () => {
|
||||
it('should pass valid requests', () => {
|
||||
mockRequest.headers.authorization = 'Bearer valid-token';
|
||||
validateRequest(mockRequest as unknown as Request, mockResponse as unknown as Response, nextFunction);
|
||||
expect(nextFunction).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should reject requests without authorization header', () => {
|
||||
validateRequest(mockRequest as unknown as Request, mockResponse as unknown as Response, nextFunction);
|
||||
expect(mockResponse.status).toHaveBeenCalledWith(401);
|
||||
expect(mockResponse.json).toHaveBeenCalledWith(expect.objectContaining({
|
||||
error: expect.stringContaining('authorization')
|
||||
}));
|
||||
});
|
||||
|
||||
it('should reject requests with invalid authorization format', () => {
|
||||
mockRequest.headers.authorization = 'invalid-format';
|
||||
validateRequest(mockRequest as unknown as Request, mockResponse as unknown as Response, nextFunction);
|
||||
expect(mockResponse.status).toHaveBeenCalledWith(401);
|
||||
expect(mockResponse.json).toHaveBeenCalledWith(expect.objectContaining({
|
||||
error: expect.stringContaining('Bearer')
|
||||
}));
|
||||
});
|
||||
it("should reject requests without authorization header", () => {
|
||||
validateRequest(
|
||||
mockRequest as unknown as Request,
|
||||
mockResponse as unknown as Response,
|
||||
nextFunction,
|
||||
);
|
||||
expect(mockResponse.status).toHaveBeenCalledWith(401);
|
||||
expect(mockResponse.json).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
error: expect.stringContaining("authorization"),
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
describe('sanitizeInput', () => {
|
||||
it('should pass requests without body', () => {
|
||||
delete mockRequest.body;
|
||||
sanitizeInput(mockRequest as unknown as Request, mockResponse as unknown as Response, nextFunction);
|
||||
expect(nextFunction).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should sanitize HTML in request body', () => {
|
||||
mockRequest.body = {
|
||||
text: '<script>alert("xss")</script>Hello',
|
||||
nested: {
|
||||
html: '<img src="x" onerror="alert(1)">World'
|
||||
}
|
||||
};
|
||||
sanitizeInput(mockRequest as unknown as Request, mockResponse as unknown as Response, nextFunction);
|
||||
expect(mockRequest.body.text).toBe('Hello');
|
||||
expect(mockRequest.body.nested.html).toBe('World');
|
||||
expect(nextFunction).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should handle non-object bodies', () => {
|
||||
mockRequest.body = '<p>text</p>';
|
||||
sanitizeInput(mockRequest as unknown as Request, mockResponse as unknown as Response, nextFunction);
|
||||
expect(mockRequest.body).toBe('text');
|
||||
expect(nextFunction).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should preserve non-string values', () => {
|
||||
mockRequest.body = {
|
||||
number: 42,
|
||||
boolean: true,
|
||||
null: null,
|
||||
array: [1, 2, 3]
|
||||
};
|
||||
sanitizeInput(mockRequest as unknown as Request, mockResponse as unknown as Response, nextFunction);
|
||||
expect(mockRequest.body).toEqual({
|
||||
number: 42,
|
||||
boolean: true,
|
||||
null: null,
|
||||
array: [1, 2, 3]
|
||||
});
|
||||
expect(nextFunction).toHaveBeenCalled();
|
||||
});
|
||||
it("should reject requests with invalid authorization format", () => {
|
||||
mockRequest.headers.authorization = "invalid-format";
|
||||
validateRequest(
|
||||
mockRequest as unknown as Request,
|
||||
mockResponse as unknown as Response,
|
||||
nextFunction,
|
||||
);
|
||||
expect(mockResponse.status).toHaveBeenCalledWith(401);
|
||||
expect(mockResponse.json).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
error: expect.stringContaining("Bearer"),
|
||||
}),
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("sanitizeInput", () => {
|
||||
it("should pass requests without body", () => {
|
||||
delete mockRequest.body;
|
||||
sanitizeInput(
|
||||
mockRequest as unknown as Request,
|
||||
mockResponse as unknown as Response,
|
||||
nextFunction,
|
||||
);
|
||||
expect(nextFunction).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("should sanitize HTML in request body", () => {
|
||||
mockRequest.body = {
|
||||
text: '<script>alert("xss")</script>Hello',
|
||||
nested: {
|
||||
html: '<img src="x" onerror="alert(1)">World',
|
||||
},
|
||||
};
|
||||
sanitizeInput(
|
||||
mockRequest as unknown as Request,
|
||||
mockResponse as unknown as Response,
|
||||
nextFunction,
|
||||
);
|
||||
expect(mockRequest.body.text).toBe("Hello");
|
||||
expect(mockRequest.body.nested.html).toBe("World");
|
||||
expect(nextFunction).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("should handle non-object bodies", () => {
|
||||
mockRequest.body = "<p>text</p>";
|
||||
sanitizeInput(
|
||||
mockRequest as unknown as Request,
|
||||
mockResponse as unknown as Response,
|
||||
nextFunction,
|
||||
);
|
||||
expect(mockRequest.body).toBe("text");
|
||||
expect(nextFunction).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("should preserve non-string values", () => {
|
||||
mockRequest.body = {
|
||||
number: 42,
|
||||
boolean: true,
|
||||
null: null,
|
||||
array: [1, 2, 3],
|
||||
};
|
||||
sanitizeInput(
|
||||
mockRequest as unknown as Request,
|
||||
mockResponse as unknown as Response,
|
||||
nextFunction,
|
||||
);
|
||||
expect(mockRequest.body).toEqual({
|
||||
number: 42,
|
||||
boolean: true,
|
||||
null: null,
|
||||
array: [1, 2, 3],
|
||||
});
|
||||
expect(nextFunction).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user