Replace all `any` types with properly defined TypeScript interfaces and types throughout the codebase to improve type safety and eliminate type-related code quality issues. Changes: - Define ElectronSafeStorage interface for Electron's safeStorage API - Create LegacySettings interface for settings migration in main.ts - Define JSONValue, JSONRPCParams types for JSON-RPC protocol - Define JSONSchemaProperty for tool input schemas - Create YAMLValue type for frontmatter values - Define FrontmatterValue type for adapter interfaces - Update middleware to use proper Express NextFunction and JSONRPCResponse types - Fix tool registry to handle args with proper typing (with eslint-disable for dynamic dispatch) - Fix notifications to use proper types with eslint-disable where dynamic access is needed - Add proper null safety assertions where appropriate - Fix TFolder stat access with proper type extension All type errors resolved. TypeScript compilation passes with --skipLibCheck.
59 lines
2.1 KiB
TypeScript
59 lines
2.1 KiB
TypeScript
import { Express, Request, Response, NextFunction } from 'express';
|
|
import express from 'express';
|
|
import cors from 'cors';
|
|
import { MCPServerSettings } from '../types/settings-types';
|
|
import { ErrorCodes, JSONRPCResponse } from '../types/mcp-types';
|
|
|
|
export function setupMiddleware(app: Express, settings: MCPServerSettings, createErrorResponse: (id: string | number | null, code: number, message: string) => JSONRPCResponse): void {
|
|
// Parse JSON bodies
|
|
app.use(express.json());
|
|
|
|
// CORS configuration - Always enabled with fixed localhost-only policy
|
|
const corsOptions = {
|
|
origin: (origin: string | undefined, callback: (err: Error | null, allow?: boolean) => void) => {
|
|
// Allow requests with no origin (like CLI clients, curl, MCP SDKs)
|
|
if (!origin) {
|
|
return callback(null, true);
|
|
}
|
|
|
|
// Allow localhost and 127.0.0.1 on any port, both HTTP and HTTPS
|
|
const localhostRegex = /^https?:\/\/(localhost|127\.0\.0\.1)(:\d+)?$/;
|
|
if (localhostRegex.test(origin)) {
|
|
callback(null, true);
|
|
} else {
|
|
callback(new Error('Not allowed by CORS'));
|
|
}
|
|
},
|
|
credentials: true
|
|
};
|
|
app.use(cors(corsOptions));
|
|
|
|
// Authentication middleware - Always enabled
|
|
app.use((req: Request, res: Response, next: NextFunction) => {
|
|
// Defensive check: if no API key is set, reject all requests
|
|
if (!settings.apiKey || settings.apiKey.trim() === '') {
|
|
return res.status(500).json(createErrorResponse(null, ErrorCodes.InternalError, 'Server misconfigured: No API key set'));
|
|
}
|
|
|
|
const authHeader = req.headers.authorization;
|
|
const providedKey = authHeader?.replace('Bearer ', '');
|
|
|
|
if (providedKey !== settings.apiKey) {
|
|
return res.status(401).json(createErrorResponse(null, ErrorCodes.InvalidRequest, 'Unauthorized'));
|
|
}
|
|
next();
|
|
});
|
|
|
|
// Origin validation for security (DNS rebinding protection)
|
|
app.use((req: Request, res: Response, next: NextFunction) => {
|
|
const host = req.headers.host;
|
|
|
|
// Only allow localhost connections
|
|
if (host && !host.startsWith('localhost') && !host.startsWith('127.0.0.1')) {
|
|
return res.status(403).json(createErrorResponse(null, ErrorCodes.InvalidRequest, 'Only localhost connections allowed'));
|
|
}
|
|
|
|
next();
|
|
});
|
|
}
|