/** * Security Fixes Integration Test Suite * * 测试最近修复的安全问题: * 1. XSS 防护 - sanitizeProviderData * 2. 路径遍历防护 - 路径验证逻辑 * 3. 文件锁超时机制 * 4. 健康检查方法调用 */ import { describe, test, expect } from '@jest/globals'; import { fetch } from 'undici'; const TEST_SERVER_BASE_URL = process.env.TEST_SERVER_BASE_URL || 'http://localhost:3000'; const TEST_API_KEY = process.env.TEST_API_KEY || '123456'; describe('Security Fixes Integration Tests', () => { describe('XSS Protection', () => { test('should remove script tags from customName', async () => { const maliciousName = 'TestProvider'; const response = await fetch(`${TEST_SERVER_BASE_URL}/api/providers`, { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${TEST_API_KEY}` }, body: JSON.stringify({ providerType: 'openai-custom', providerConfig: { customName: maliciousName, OPENAI_CUSTOM_BASE_URL: 'https://api.example.com', OPENAI_CUSTOM_API_KEY: 'test-key' } }) }); const data = await response.json(); expect(data.provider.customName).not.toContain(''); expect(data.provider.customName).toContain('TestProvider'); }); test('should reject javascript: protocol', async () => { const maliciousName = 'javascript:alert("XSS")'; const response = await fetch(`${TEST_SERVER_BASE_URL}/api/providers`, { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${TEST_API_KEY}` }, body: JSON.stringify({ providerType: 'openai-custom', providerConfig: { customName: maliciousName, OPENAI_CUSTOM_BASE_URL: 'https://api.example.com', OPENAI_CUSTOM_API_KEY: 'test-key' } }) }); const data = await response.json(); expect(data.provider.customName).toBe(''); }); test('should reject data: protocol', async () => { const maliciousName = 'data:text/html,'; const response = await fetch(`${TEST_SERVER_BASE_URL}/api/providers`, { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${TEST_API_KEY}` }, body: JSON.stringify({ providerType: 'openai-custom', providerConfig: { customName: maliciousName, OPENAI_CUSTOM_BASE_URL: 'https://api.example.com', OPENAI_CUSTOM_API_KEY: 'test-key' } }) }); const data = await response.json(); expect(data.provider.customName).toBe(''); }); test('should remove HTML event handlers', async () => { const maliciousName = ''; const response = await fetch(`${TEST_SERVER_BASE_URL}/api/providers`, { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${TEST_API_KEY}` }, body: JSON.stringify({ providerType: 'openai-custom', providerConfig: { customName: maliciousName, OPENAI_CUSTOM_BASE_URL: 'https://api.example.com', OPENAI_CUSTOM_API_KEY: 'test-key' } }) }); const data = await response.json(); expect(data.provider.customName).not.toContain('onerror'); expect(data.provider.customName).not.toContain(' { const maliciousName = '<script>alert(1)</script>'; const response = await fetch(`${TEST_SERVER_BASE_URL}/api/providers`, { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${TEST_API_KEY}` }, body: JSON.stringify({ providerType: 'openai-custom', providerConfig: { customName: maliciousName, OPENAI_CUSTOM_BASE_URL: 'https://api.example.com', OPENAI_CUSTOM_API_KEY: 'test-key' } }) }); const data = await response.json(); expect(data.provider.customName).not.toContain('<'); expect(data.provider.customName).not.toContain('>'); }); test('should preserve normal text', async () => { const normalName = 'My Test Provider 123'; const response = await fetch(`${TEST_SERVER_BASE_URL}/api/providers`, { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${TEST_API_KEY}` }, body: JSON.stringify({ providerType: 'openai-custom', providerConfig: { customName: normalName, OPENAI_CUSTOM_BASE_URL: 'https://api.example.com', OPENAI_CUSTOM_API_KEY: 'test-key' } }) }); const data = await response.json(); expect(data.provider.customName).toBe(normalName); }); }); describe('Path Traversal Protection', () => { test('should reject paths with ..', async () => { const maliciousPath = '../../../etc/passwd'; const response = await fetch(`${TEST_SERVER_BASE_URL}/api/config`, { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${TEST_API_KEY}` }, body: JSON.stringify({ SYSTEM_PROMPT_FILE_PATH: maliciousPath }) }); expect(response.status).toBe(200); const getResponse = await fetch(`${TEST_SERVER_BASE_URL}/api/config`, { headers: { 'Authorization': `Bearer ${TEST_API_KEY}` } }); const config = await getResponse.json(); expect(config.SYSTEM_PROMPT_FILE_PATH).not.toBe(maliciousPath); }); test('should accept valid paths within working directory', async () => { const validPath = 'configs/my_prompt.txt'; const response = await fetch(`${TEST_SERVER_BASE_URL}/api/config`, { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${TEST_API_KEY}` }, body: JSON.stringify({ SYSTEM_PROMPT_FILE_PATH: validPath }) }); expect(response.status).toBe(200); const getResponse = await fetch(`${TEST_SERVER_BASE_URL}/api/config`, { headers: { 'Authorization': `Bearer ${TEST_API_KEY}` } }); const config = await getResponse.json(); expect(config.SYSTEM_PROMPT_FILE_PATH).toBe(validPath); }); }); describe('Health Check Configuration', () => { test('should save scheduled health check settings', async () => { const response = await fetch(`${TEST_SERVER_BASE_URL}/api/config`, { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${TEST_API_KEY}` }, body: JSON.stringify({ SCHEDULED_HEALTH_CHECK: { enabled: true, startupRun: true, interval: 300000, providerTypes: ['openai-custom'] } }) }); expect(response.status).toBe(200); const getResponse = await fetch(`${TEST_SERVER_BASE_URL}/api/config`, { headers: { 'Authorization': `Bearer ${TEST_API_KEY}` } }); const config = await getResponse.json(); expect(config.SCHEDULED_HEALTH_CHECK).toBeDefined(); expect(config.SCHEDULED_HEALTH_CHECK.enabled).toBe(true); expect(config.SCHEDULED_HEALTH_CHECK.interval).toBe(300000); }); test('should enforce minimum interval', async () => { const response = await fetch(`${TEST_SERVER_BASE_URL}/api/config`, { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${TEST_API_KEY}` }, body: JSON.stringify({ SCHEDULED_HEALTH_CHECK: { enabled: true, interval: 30000 } }) }); expect(response.status).toBe(200); const getResponse = await fetch(`${TEST_SERVER_BASE_URL}/api/config`, { headers: { 'Authorization': `Bearer ${TEST_API_KEY}` } }); const config = await getResponse.json(); expect(config.SCHEDULED_HEALTH_CHECK.interval).toBeGreaterThanOrEqual(60000); }); }); describe('Configuration Validation', () => { test('should reject invalid port numbers', async () => { const response = await fetch(`${TEST_SERVER_BASE_URL}/api/config`, { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${TEST_API_KEY}` }, body: JSON.stringify({ SERVER_PORT: 99999 }) }); expect(response.status).toBe(200); const getResponse = await fetch(`${TEST_SERVER_BASE_URL}/api/config`, { headers: { 'Authorization': `Bearer ${TEST_API_KEY}` } }); const config = await getResponse.json(); expect(config.SERVER_PORT).not.toBe(99999); }); test('should reject excessive retry counts', async () => { const response = await fetch(`${TEST_SERVER_BASE_URL}/api/config`, { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${TEST_API_KEY}` }, body: JSON.stringify({ REQUEST_MAX_RETRIES: 999 }) }); expect(response.status).toBe(200); const getResponse = await fetch(`${TEST_SERVER_BASE_URL}/api/config`, { headers: { 'Authorization': `Bearer ${TEST_API_KEY}` } }); const config = await getResponse.json(); expect(config.REQUEST_MAX_RETRIES).toBeLessThanOrEqual(100); }); test('should mask API key in response', async () => { const response = await fetch(`${TEST_SERVER_BASE_URL}/api/config`, { headers: { 'Authorization': `Bearer ${TEST_API_KEY}` } }); const config = await response.json(); if (config.REQUIRED_API_KEY) { expect(config.REQUIRED_API_KEY).toContain('*'); } }); }); });