import { describe, expect, test } from 'vitest'; import { getMigratedDocumentFileName } from '../../src/lib/server/storage/docstore-legacy'; describe('docstore filename safety', () => { const id = 'a'.repeat(64); // Simulate sha256 hex ID test('generates stable file names for short inputs', () => { const name = 'test-file.pdf'; const result = getMigratedDocumentFileName(id, name); expect(result).toBe(`${id}__test-file.pdf`); expect(result.length).toBeLessThanOrEqual(240); }); test('should truncate very long names', () => { const longName = 'a'.repeat(300); const result = getMigratedDocumentFileName(id, longName); expect(result.length).toBeLessThanOrEqual(240); expect(result).toContain('truncated-'); expect(result.startsWith(`${id}__`)).toBeTruthy(); }); test('should truncate names that become too long after encoding', () => { // Chinese characters take 9 chars each when encoded (%XX%XX%XX) const specialName = '特殊字符'.repeat(30); const result = getMigratedDocumentFileName(id, specialName); expect(result.length).toBeLessThanOrEqual(240); expect(result).toContain('truncated-'); // The implementation replaces the name with a hash, so it should NOT contain the original special chars // and might not contain % if the hash is hex. expect(result).toMatch(/truncated-[a-f0-9]{32}$/); expect(result.startsWith(`${id}__`)).toBeTruthy(); }); test('should handle edge case length exactly', () => { // Create a name that would result in exactly 241 chars to trigger truncation // Prefix is 64 + 2 = 66 chars. // Max allowed = 240. // Available for name = 240 - 66 = 174. // If we give 175 chars, it should truncate. const name = 'a'.repeat(175); const result = getMigratedDocumentFileName(id, name); expect(result).toContain('truncated-'); }); test('should not truncate if exactly at limit', () => { const name = 'a'.repeat(174); const result = getMigratedDocumentFileName(id, name); expect(result.length).toBe(240); expect(result).not.toContain('truncated-'); }); test('drops path traversal and null-byte fragments from migrated file names', () => { const dirtyName = '../nested/\u0000financial-report.pdf'; const result = getMigratedDocumentFileName(id, dirtyName); expect(result).toBe(`${id}__financial-report.pdf`); expect(result).not.toContain('..'); expect(result).not.toContain('\u0000'); }); });