add file checking
alex wennerberg alex@alexwennerberg.com
Sat, 24 Oct 2020 11:07:59 -0700
4 files changed,
39 insertions(+),
8 deletions(-)
M
flounder.toml
→
flounder.toml
@@ -6,5 +6,7 @@ # handles templates and static files
# everything in the static subfolder will be served at root TemplatesDirectory="./templates" DBFile="./flounder.db" +MaxFileSize=1000000 # 1 MB +OkExtensions=[".gmi", ".txt", ".jpg", ".jpeg", ".gif", ".png", ".svg", ".webp", ".midi", ".json", ".csv", ".gemini", ".mp3", ".css", ".ttf", ".otf", ".woff", ".woff2"] -# Log file +# log file
M
http.go
→
http.go
@@ -16,10 +16,9 @@ )
var t *template.Template -// TODO somewhat better error handling const InternalServerErrorMsg = "500: Internal Server Error" -func renderError(w http.ResponseWriter, errorMsg string, statusCode int) { // TODO think about pointers +func renderError(w http.ResponseWriter, errorMsg string, statusCode int) { data := struct{ ErrorMsg string }{errorMsg} err := t.ExecuteTemplate(w, "error.html", data) if err != nil { // shouldn't happen probably@@ -66,6 +65,12 @@ authUser := "alex"
fileName := filepath.Clean(r.URL.Path[len("/edit/"):]) filePath := path.Join(c.FilesDirectory, authUser, fileName) if r.Method == "GET" { + err := checkIfValidFile(filePath, nil) + if err != nil { + log.Println(err) + renderError(w, err.Error(), 400) + return + } f, err := os.OpenFile(filePath, os.O_RDONLY|os.O_CREATE, 0644) defer f.Close() fileBytes, err := ioutil.ReadAll(f)@@ -88,8 +93,14 @@ }
} else if r.Method == "POST" { // get post body r.ParseForm() - fileText := r.Form.Get("file_text") - err := ioutil.WriteFile(filePath, []byte(fileText), 0644) + fileBytes := []byte(r.Form.Get("file_text")) + err := checkIfValidFile(filePath, fileBytes) + if err != nil { + log.Println(err) + renderError(w, err.Error(), 400) + return + } + err = ioutil.WriteFile(filePath, fileBytes, 0644) if err != nil { log.Println(err) renderError(w, InternalServerErrorMsg, 500)@@ -104,7 +115,7 @@ authUser := "alex"
fileName := filepath.Clean(r.URL.Path[len("/delete/"):]) filePath := path.Join(c.FilesDirectory, authUser, fileName) if r.Method == "POST" { - os.Remove(filePath) + os.Remove(filePath) // suppress error http.Redirect(w, r, "/my_site", 302) } }@@ -203,7 +214,7 @@
func runHTTPServer() { log.Println("Running http server") var err error - t, err = template.ParseGlob("./templates/*.html") // TODO make template dir configruable + t, err = template.ParseGlob(path.Join(c.TemplatesDirectory, "*.html")) if err != nil { log.Fatal(err) }
M
main.go
→
main.go
@@ -2,11 +2,13 @@ package main
import ( "flag" + "fmt" "io/ioutil" "log" "os" "path" "path/filepath" + "strings" "sync" )@@ -27,7 +29,21 @@ return []string{"me", "other guy"}, nil
} /// Perform some checks to make sure the file is OK -func checkIfValidFile() { +func checkIfValidFile(filename string, fileBytes []byte) error { + ext := strings.ToLower(path.Ext(filename)) + found := false + for _, mimetype := range c.OkExtensions { + if ext == mimetype { + found = true + } + } + if !found { + return fmt.Errorf("Invalid file extension: %s", ext) + } + if len(fileBytes) > c.MaxFileSize { + return fmt.Errorf("File too large. File was %s bytes, Max file size is %s", len(fileBytes), c.MaxFileSize) + } + return nil } func getIndexFiles() ([]*File, error) { // cache this function