main_test.go

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