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:
jango-blockchained
2025-02-04 00:56:45 +01:00
parent 9a02bdaf11
commit bc1dc8278a
65 changed files with 7094 additions and 7675 deletions

View File

@@ -1,163 +1,203 @@
import { Request, Response } from 'express';
import { validateRequest, sanitizeInput, errorHandler } from '../index';
import { TokenManager } from '../../security/index';
import { jest } from '@jest/globals';
import { Request, Response } from "express";
import { validateRequest, sanitizeInput, errorHandler } from "../index";
import { TokenManager } from "../../security/index";
import { jest } from "@jest/globals";
const TEST_SECRET = 'test-secret-that-is-long-enough-for-testing-purposes';
const TEST_SECRET = "test-secret-that-is-long-enough-for-testing-purposes";
describe('Security Middleware', () => {
let mockRequest: Partial<Request>;
let mockResponse: Partial<Response>;
let nextFunction: jest.Mock;
describe("Security Middleware", () => {
let mockRequest: Partial<Request>;
let mockResponse: Partial<Response>;
let nextFunction: jest.Mock;
beforeEach(() => {
process.env.JWT_SECRET = TEST_SECRET;
mockRequest = {
method: 'POST',
headers: {},
body: {},
ip: '127.0.0.1'
};
beforeEach(() => {
process.env.JWT_SECRET = TEST_SECRET;
mockRequest = {
method: "POST",
headers: {},
body: {},
ip: "127.0.0.1",
};
const mockJson = jest.fn().mockReturnThis();
const mockStatus = jest.fn().mockReturnThis();
const mockSetHeader = jest.fn().mockReturnThis();
const mockRemoveHeader = jest.fn().mockReturnThis();
const mockJson = jest.fn().mockReturnThis();
const mockStatus = jest.fn().mockReturnThis();
const mockSetHeader = jest.fn().mockReturnThis();
const mockRemoveHeader = jest.fn().mockReturnThis();
mockResponse = {
status: mockStatus as any,
json: mockJson as any,
setHeader: mockSetHeader as any,
removeHeader: mockRemoveHeader as any
};
nextFunction = jest.fn();
mockResponse = {
status: mockStatus as any,
json: mockJson as any,
setHeader: mockSetHeader as any,
removeHeader: mockRemoveHeader as any,
};
nextFunction = jest.fn();
});
afterEach(() => {
delete process.env.JWT_SECRET;
jest.clearAllMocks();
});
describe("Request Validation", () => {
it("should pass valid requests", () => {
mockRequest.headers = {
authorization: "Bearer valid-token",
"content-type": "application/json",
};
jest
.spyOn(TokenManager, "validateToken")
.mockReturnValue({ valid: true });
validateRequest(
mockRequest as Request,
mockResponse as Response,
nextFunction,
);
expect(nextFunction).toHaveBeenCalled();
});
afterEach(() => {
delete process.env.JWT_SECRET;
jest.clearAllMocks();
it("should reject requests without authorization header", () => {
validateRequest(
mockRequest as Request,
mockResponse as Response,
nextFunction,
);
expect(mockResponse.status).toHaveBeenCalledWith(401);
expect(mockResponse.json).toHaveBeenCalledWith({
success: false,
message: "Unauthorized",
error: "Missing or invalid authorization header",
timestamp: expect.any(String),
});
});
describe('Request Validation', () => {
it('should pass valid requests', () => {
mockRequest.headers = {
'authorization': 'Bearer valid-token',
'content-type': 'application/json'
};
jest.spyOn(TokenManager, 'validateToken').mockReturnValue({ valid: true });
validateRequest(mockRequest as Request, mockResponse as Response, nextFunction);
expect(nextFunction).toHaveBeenCalled();
});
it('should reject requests without authorization header', () => {
validateRequest(mockRequest as Request, mockResponse as Response, nextFunction);
expect(mockResponse.status).toHaveBeenCalledWith(401);
expect(mockResponse.json).toHaveBeenCalledWith({
success: false,
message: 'Unauthorized',
error: 'Missing or invalid authorization header',
timestamp: expect.any(String)
});
});
it('should reject requests with invalid authorization format', () => {
mockRequest.headers = {
'authorization': 'invalid-format',
'content-type': 'application/json'
};
validateRequest(mockRequest as Request, mockResponse as Response, nextFunction);
expect(mockResponse.status).toHaveBeenCalledWith(401);
expect(mockResponse.json).toHaveBeenCalledWith({
success: false,
message: 'Unauthorized',
error: 'Missing or invalid authorization header',
timestamp: expect.any(String)
});
});
it('should reject oversized requests', () => {
mockRequest.headers = {
'authorization': 'Bearer valid-token',
'content-type': 'application/json',
'content-length': '1048577' // 1MB + 1 byte
};
validateRequest(mockRequest as Request, mockResponse as Response, nextFunction);
expect(mockResponse.status).toHaveBeenCalledWith(413);
expect(mockResponse.json).toHaveBeenCalledWith({
success: false,
message: 'Payload Too Large',
error: 'Request body must not exceed 1048576 bytes',
timestamp: expect.any(String)
});
});
it("should reject requests with invalid authorization format", () => {
mockRequest.headers = {
authorization: "invalid-format",
"content-type": "application/json",
};
validateRequest(
mockRequest as Request,
mockResponse as Response,
nextFunction,
);
expect(mockResponse.status).toHaveBeenCalledWith(401);
expect(mockResponse.json).toHaveBeenCalledWith({
success: false,
message: "Unauthorized",
error: "Missing or invalid authorization header",
timestamp: expect.any(String),
});
});
describe('Input Sanitization', () => {
it('should sanitize HTML in request body', () => {
mockRequest.body = {
text: 'Test <script>alert("xss")</script>',
nested: {
html: '<img src="x" onerror="alert(1)">World'
}
};
sanitizeInput(mockRequest as Request, mockResponse as Response, nextFunction);
expect(mockRequest.body.text).toBe('Test ');
expect(mockRequest.body.nested.html).toBe('World');
expect(nextFunction).toHaveBeenCalled();
});
it("should reject oversized requests", () => {
mockRequest.headers = {
authorization: "Bearer valid-token",
"content-type": "application/json",
"content-length": "1048577", // 1MB + 1 byte
};
validateRequest(
mockRequest as Request,
mockResponse as Response,
nextFunction,
);
expect(mockResponse.status).toHaveBeenCalledWith(413);
expect(mockResponse.json).toHaveBeenCalledWith({
success: false,
message: "Payload Too Large",
error: "Request body must not exceed 1048576 bytes",
timestamp: expect.any(String),
});
});
});
it('should handle non-object bodies', () => {
mockRequest.body = '<p>text</p>';
sanitizeInput(mockRequest as Request, mockResponse as Response, nextFunction);
expect(mockRequest.body).toBe('text');
expect(nextFunction).toHaveBeenCalled();
});
it('should preserve non-string values', () => {
mockRequest.body = {
number: 123,
boolean: true,
array: [1, 2, 3],
nested: { value: 456 }
};
sanitizeInput(mockRequest as Request, mockResponse as Response, nextFunction);
expect(mockRequest.body).toEqual({
number: 123,
boolean: true,
array: [1, 2, 3],
nested: { value: 456 }
});
expect(nextFunction).toHaveBeenCalled();
});
describe("Input Sanitization", () => {
it("should sanitize HTML in request body", () => {
mockRequest.body = {
text: 'Test <script>alert("xss")</script>',
nested: {
html: '<img src="x" onerror="alert(1)">World',
},
};
sanitizeInput(
mockRequest as Request,
mockResponse as Response,
nextFunction,
);
expect(mockRequest.body.text).toBe("Test ");
expect(mockRequest.body.nested.html).toBe("World");
expect(nextFunction).toHaveBeenCalled();
});
describe('Error Handler', () => {
it('should handle errors in production mode', () => {
process.env.NODE_ENV = 'production';
const error = new Error('Test error');
errorHandler(error, mockRequest as Request, mockResponse as Response, nextFunction);
expect(mockResponse.status).toHaveBeenCalledWith(500);
expect(mockResponse.json).toHaveBeenCalledWith({
success: false,
message: 'Internal Server Error',
error: 'An unexpected error occurred',
timestamp: expect.any(String)
});
});
it('should include error details in development mode', () => {
process.env.NODE_ENV = 'development';
const error = new Error('Test error');
errorHandler(error, mockRequest as Request, mockResponse as Response, nextFunction);
expect(mockResponse.status).toHaveBeenCalledWith(500);
expect(mockResponse.json).toHaveBeenCalledWith({
success: false,
message: 'Internal Server Error',
error: 'Test error',
stack: expect.any(String),
timestamp: expect.any(String)
});
});
it("should handle non-object bodies", () => {
mockRequest.body = "<p>text</p>";
sanitizeInput(
mockRequest as Request,
mockResponse as Response,
nextFunction,
);
expect(mockRequest.body).toBe("text");
expect(nextFunction).toHaveBeenCalled();
});
});
it("should preserve non-string values", () => {
mockRequest.body = {
number: 123,
boolean: true,
array: [1, 2, 3],
nested: { value: 456 },
};
sanitizeInput(
mockRequest as Request,
mockResponse as Response,
nextFunction,
);
expect(mockRequest.body).toEqual({
number: 123,
boolean: true,
array: [1, 2, 3],
nested: { value: 456 },
});
expect(nextFunction).toHaveBeenCalled();
});
});
describe("Error Handler", () => {
it("should handle errors in production mode", () => {
process.env.NODE_ENV = "production";
const error = new Error("Test error");
errorHandler(
error,
mockRequest as Request,
mockResponse as Response,
nextFunction,
);
expect(mockResponse.status).toHaveBeenCalledWith(500);
expect(mockResponse.json).toHaveBeenCalledWith({
success: false,
message: "Internal Server Error",
error: "An unexpected error occurred",
timestamp: expect.any(String),
});
});
it("should include error details in development mode", () => {
process.env.NODE_ENV = "development";
const error = new Error("Test error");
errorHandler(
error,
mockRequest as Request,
mockResponse as Response,
nextFunction,
);
expect(mockResponse.status).toHaveBeenCalledWith(500);
expect(mockResponse.json).toHaveBeenCalledWith({
success: false,
message: "Internal Server Error",
error: "Test error",
stack: expect.any(String),
timestamp: expect.any(String),
});
});
});
});