import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest' vi.mock('dns/promises', () => ({ lookup: vi.fn().mockResolvedValue([{ address: '93.184.216.34', family: 4 }]), })) describe('PDF source URL validation', () => { beforeEach(() => { vi.resetModules() vi.stubEnv('REDIS_ENABLED', 'false') }) afterEach(() => { vi.unstubAllEnvs() }) it('blocks plain http URLs by default', async () => { vi.stubEnv('NODE_ENV', 'production') vi.stubEnv('PDF_ALLOW_HTTP_URLS', 'false') const { validatePdfSourceUrl } = await import('@/lib/pdf/pdf-service') const result = await validatePdfSourceUrl('http://example.com/invoice') expect(result.valid).toBe(false) expect(result.reason).toContain('Only HTTPS URLs are allowed') }) it('allows http URLs only in non-production when explicitly enabled', async () => { vi.stubEnv('NODE_ENV', 'development') vi.stubEnv('PDF_ALLOW_HTTP_URLS', 'true') const { validatePdfSourceUrl } = await import('@/lib/pdf/pdf-service') const result = await validatePdfSourceUrl('http://8.8.8.8/test') expect(result.valid).toBe(true) }) it('blocks localhost targets', async () => { vi.stubEnv('NODE_ENV', 'production') const { validatePdfSourceUrl } = await import('@/lib/pdf/pdf-service') const result = await validatePdfSourceUrl('https://localhost/internal') expect(result.valid).toBe(false) expect(result.reason).toContain('Localhost is not allowed') }) it('blocks private IP targets', async () => { vi.stubEnv('NODE_ENV', 'production') const { validatePdfSourceUrl } = await import('@/lib/pdf/pdf-service') const result = await validatePdfSourceUrl('https://10.0.0.5/admin') expect(result.valid).toBe(false) expect(result.reason).toContain('Private or loopback') }) it('enforces PDF_ALLOWED_HOSTS allowlist', async () => { vi.stubEnv('NODE_ENV', 'production') vi.stubEnv('PDF_ALLOWED_HOSTS', 'example.com,.trusted.example') const { validatePdfSourceUrl } = await import('@/lib/pdf/pdf-service') const allowed = await validatePdfSourceUrl('https://example.com/a') const blocked = await validatePdfSourceUrl('https://not-allowed.example/a') expect(allowed.valid).toBe(true) expect(blocked.valid).toBe(false) expect(blocked.reason).toContain('allowlist') }) })