1package main
2
3import (
4 "testing"
5)
6
7func TestSanitizeFilename(t *testing.T) {
8 tests := []struct {
9 name string
10 input string
11 expected string
12 }{
13 {"normal filename", "document.pdf", "document.pdf"},
14 {"filename with spaces", "my report.docx", "my report.docx"},
15 {"unix path traversal", "../../../etc/passwd", "passwd"},
16 {"windows path traversal", "..\\..\\..\\windows\\system32\\config", "config"},
17 {"mixed traversal", "../secret/key.pem", "key.pem"},
18 {"hidden file", ".bashrc", "attachment"},
19 {"dot only", ".", "attachment"},
20 {"dot dot", "..", "_"},
21 {"empty string", "", "attachment"},
22 {"absolute unix path", "/etc/shadow", "shadow"},
23 {"absolute windows path", "C:\\Users\\secret.txt", "secret.txt"},
24 {"double dot in middle", "file..name.txt", "file_name.txt"},
25 {"multiple slashes", "path/to/file.txt", "file.txt"},
26 {"null bytes removed", "file\x00name.txt", "file\x00name.txt"},
27 {"unicode filename", "日本語.txt", "日本語.txt"},
28 {"long traversal chain", "a/b/c/../../../d/e/f.txt", "f.txt"},
29 }
30
31 for _, tt := range tests {
32 t.Run(tt.name, func(t *testing.T) {
33 got := sanitizeFilename(tt.input)
34 if got != tt.expected {
35 t.Errorf("sanitizeFilename(%q) = %q, want %q", tt.input, got, tt.expected)
36 }
37 // Verify the sanitized name never allows escaping the download directory
38 if got == "" {
39 t.Error("sanitizeFilename returned empty string")
40 }
41 if got == "." || got == ".." {
42 t.Error("sanitizeFilename returned a dangerous name: " + got)
43 }
44 })
45 }
46}
47
48func TestSanitizeFilenameNoPathSeparators(t *testing.T) {
49 // Ensure no sanitized output contains path separators
50 dangerous := []string{
51 "a/b", "a\\b", "../a", "..\\a",
52 "/etc/passwd", "\\Windows\\System32",
53 "....//....//etc/passwd",
54 }
55 for _, input := range dangerous {
56 got := sanitizeFilename(input)
57 for _, ch := range got {
58 if ch == '/' || ch == '\\' {
59 t.Errorf("sanitizeFilename(%q) = %q contains path separator", input, got)
60 }
61 }
62 }
63}