all repos — flounder @ 15ec4e13737ab222e225c5f93818bc51ce2cb9f2

A small site builder for the Gemini protocol

add file checking
alex wennerberg alex@alexwennerberg.com
Sat, 24 Oct 2020 11:07:59 -0700
commit

15ec4e13737ab222e225c5f93818bc51ce2cb9f2

parent

7068552cb491131c4b58a79149ac457333881ac5

4 files changed, 39 insertions(+), 8 deletions(-)

jump to
M config.goconfig.go

@@ -13,6 +13,8 @@ Debug bool

SecretKey string DBFile string PasswdFile string // TODO remove + OkExtensions []string + MaxFileSize int } func getConfig(filename string) (Config, error) {
M flounder.tomlflounder.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.gohttp.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.gomain.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