flounder

A simple gemini site builder
Log | Files | Refs | README | LICENSE

commit 15ec4e13737ab222e225c5f93818bc51ce2cb9f2
parent 7068552cb491131c4b58a79149ac457333881ac5
Author: alex wennerberg <alex@alexwennerberg.com>
Date:   Sat, 24 Oct 2020 11:07:59 -0700

add file checking

Diffstat:
Mconfig.go | 2++
Mflounder.toml | 4+++-
Mhttp.go | 23+++++++++++++++++------
Mmain.go | 18+++++++++++++++++-
4 files changed, 39 insertions(+), 8 deletions(-)

diff --git a/config.go b/config.go @@ -13,6 +13,8 @@ type Config struct { SecretKey string DBFile string PasswdFile string // TODO remove + OkExtensions []string + MaxFileSize int } func getConfig(filename string) (Config, error) { diff --git a/flounder.toml b/flounder.toml @@ -6,5 +6,7 @@ FilesDirectory="./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 diff --git a/http.go b/http.go @@ -16,10 +16,9 @@ import ( 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 @@ func editFileHandler(w http.ResponseWriter, r *http.Request) { 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 @@ func editFileHandler(w http.ResponseWriter, r *http.Request) { } 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 @@ func deleteFileHandler(w http.ResponseWriter, r *http.Request) { 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 userFile(w http.ResponseWriter, r *http.Request) { 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) } diff --git a/main.go b/main.go @@ -2,11 +2,13 @@ package main import ( "flag" + "fmt" "io/ioutil" "log" "os" "path" "path/filepath" + "strings" "sync" ) @@ -27,7 +29,21 @@ func getUsers() ([]string, error) { } /// 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