@@ -63,3 +63,90 @@ func Test_LocalHandlePutRequest(t *testing.T) {
6363 require .NoError (t , err )
6464 require .Equal (t , fileContent , createdFileContent )
6565}
66+
67+ func Test_LocalHandlePutRequest_PathTraversal (t * testing.T ) {
68+ mockDir := t .TempDir ()
69+ mockURL := "http://localhost:8080"
70+ t .Setenv ("SERVER_URL" , mockURL )
71+ t .Setenv ("STORE_DIR" , mockDir )
72+
73+ mux := http .NewServeMux ()
74+ err := configureLocalHandlers (mux )
75+ require .NoError (t , err )
76+
77+ fileContent := []byte ("malicious content" )
78+ req := httptest .NewRequest (http .MethodPut , putURLPath + "/uploads/%2e%2e%2f%2e%2e%2fetc%2fpasswd" , bytes .NewReader (fileContent ))
79+
80+ rec := httptest .NewRecorder ()
81+ mux .ServeHTTP (rec , req )
82+
83+ require .Equal (t , http .StatusBadRequest , rec .Code )
84+
85+ _ , err = os .Stat (filepath .Join (mockDir , ".." , ".." , "etc" , "passwd" ))
86+ require .True (t , os .IsNotExist (err ), "traversal file should not exist" )
87+ }
88+
89+ func Test_LocalHandlePutRequest_DirTraversal (t * testing.T ) {
90+ mockDir := t .TempDir ()
91+ t .Setenv ("SERVER_URL" , "http://localhost:8080" )
92+ t .Setenv ("STORE_DIR" , mockDir )
93+
94+ l := & local {url : "http://localhost:8080" , dir : mockDir }
95+
96+ body := bytes .NewReader ([]byte ("bad" ))
97+ req := httptest .NewRequest (http .MethodPut , putURLPath + "/x/evil.txt" , body )
98+ req .SetPathValue ("dir" , "../../../tmp" )
99+ req .SetPathValue ("file" , "evil.txt" )
100+
101+ rec := httptest .NewRecorder ()
102+ l .handlePutRequest (rec , req )
103+
104+ require .Equal (t , http .StatusBadRequest , rec .Code )
105+
106+ _ , err := os .Stat (filepath .Join ("/tmp" , "evil.txt" ))
107+ require .True (t , os .IsNotExist (err ), "traversal file should not exist outside store dir" )
108+ }
109+
110+ func Test_LocalHandlePutRequest_DuplicateFile (t * testing.T ) {
111+ mockDir := t .TempDir ()
112+ t .Setenv ("SERVER_URL" , "http://localhost:8080" )
113+ t .Setenv ("STORE_DIR" , mockDir )
114+
115+ mux := http .NewServeMux ()
116+ err := configureLocalHandlers (mux )
117+ require .NoError (t , err )
118+
119+ req := httptest .NewRequest (http .MethodPut , putURLPath + "/dir/dup.txt" , bytes .NewReader ([]byte ("first" )))
120+ rec := httptest .NewRecorder ()
121+ mux .ServeHTTP (rec , req )
122+ require .Equal (t , http .StatusOK , rec .Code )
123+
124+ req = httptest .NewRequest (http .MethodPut , putURLPath + "/dir/dup.txt" , bytes .NewReader ([]byte ("second" )))
125+ rec = httptest .NewRecorder ()
126+ mux .ServeHTTP (rec , req )
127+ require .Equal (t , http .StatusConflict , rec .Code )
128+
129+ content , err := os .ReadFile (filepath .Join (mockDir , "dir" , "dup.txt" ))
130+ require .NoError (t , err )
131+ require .Equal (t , []byte ("first" ), content )
132+ }
133+
134+ func Test_LocalHandlePutRequest_BodyTooLarge (t * testing.T ) {
135+ mockDir := t .TempDir ()
136+ t .Setenv ("SERVER_URL" , "http://localhost:8080" )
137+ t .Setenv ("STORE_DIR" , mockDir )
138+
139+ mux := http .NewServeMux ()
140+ err := configureLocalHandlers (mux )
141+ require .NoError (t , err )
142+
143+ largeBody := make ([]byte , maxUploadSize + 1 )
144+ req := httptest .NewRequest (http .MethodPut , putURLPath + "/dir/big.txt" , bytes .NewReader (largeBody ))
145+ rec := httptest .NewRecorder ()
146+ mux .ServeHTTP (rec , req )
147+
148+ require .Equal (t , http .StatusRequestEntityTooLarge , rec .Code )
149+
150+ _ , err = os .Stat (filepath .Join (mockDir , "dir" , "big.txt" ))
151+ require .True (t , os .IsNotExist (err ))
152+ }
0 commit comments