main_test.go

 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}