all repos — flounder @ 99e089d9871ab2102787730f0eb5cfcfc54ba470

A small site builder for the Gemini protocol

Cleanup and add file size limits
alex wennerberg alex@alexwennerberg.com
Sat, 05 Dec 2020 17:19:36 -0800
commit

99e089d9871ab2102787730f0eb5cfcfc54ba470

parent

f0ec25f3b1de5cba69cf8ed647c9391c9b7ea81d

3 files changed, 52 insertions(+), 14 deletions(-)

jump to
M config.goconfig.go

@@ -18,7 +18,8 @@ LogFile string

GeminiCertStore string CookieStoreKey string OkExtensions []string - MaxFileSize int + MaxFileBytes int + MaxUserBytes int64 TLSCertFile string TLSKeyFile string }
M http.gohttp.go

@@ -47,9 +47,15 @@ func rootHandler(w http.ResponseWriter, r *http.Request) {

// serve everything inside static directory if r.URL.Path != "/" { fileName := path.Join(c.TemplatesDirectory, "static", filepath.Clean(r.URL.Path)) - http.ServeFile(w, r, fileName) + _, err := os.Stat(fileName) + if err != nil { + renderDefaultError(w, http.StatusNotFound) + return + } + http.ServeFile(w, r, fileName) // TODO better error handling return } + authd, _, isAdmin := getAuthUser(r) indexFiles, err := getIndexFiles() if err != nil {

@@ -80,16 +86,14 @@ }

} func editFileHandler(w http.ResponseWriter, r *http.Request) { - session, _ := SessionStore.Get(r, "cookie-session") - authUser, ok := session.Values["auth_user"].(string) + ok, authUser, _ := getAuthUser(r) if !ok { renderDefaultError(w, http.StatusForbidden) return } fileName := filepath.Clean(r.URL.Path[len("/edit/"):]) - isText := strings.HasPrefix(mime.TypeByExtension(path.Ext(fileName)), "text") - if !isText { - renderError(w, "Bad Request: Not a text file, cannot be edited here", http.StatusBadRequest) // correct status code? + if !strings.HasPrefix(mime.TypeByExtension(path.Ext(fileName)), "text") { + renderError(w, "Bad Request: Not a text file, cannot be edited here", http.StatusBadRequest) return } filePath := path.Join(c.FilesDirectory, authUser, fileName)

@@ -101,7 +105,7 @@ log.Println(err)

renderError(w, err.Error(), http.StatusBadRequest) return } - // create directories if dne + // Create directories if dne f, err := os.OpenFile(filePath, os.O_RDONLY, 0644) var fileBytes []byte if os.IsNotExist(err) {

@@ -141,7 +145,12 @@ return

} // create directories if dne os.MkdirAll(path.Dir(filePath), os.ModePerm) - err = ioutil.WriteFile(filePath, fileBytes, 0644) + if userHasSpace(authUser, len(fileBytes)) { + err = ioutil.WriteFile(filePath, fileBytes, 0644) + } else { + renderError(w, fmt.Sprintf("Bad Request: Out of file space. Max space: %d.", c.MaxUserBytes), http.StatusBadRequest) + return + } if err != nil { log.Println(err) renderDefaultError(w, http.StatusInternalServerError)

@@ -196,12 +205,16 @@ renderDefaultError(w, http.StatusInternalServerError)

return } defer f.Close() - io.Copy(f, bytes.NewReader(dest)) + if userHasSpace(authUser, c.MaxFileBytes) { // Not quite right + io.Copy(f, bytes.NewReader(dest)) + } else { + renderError(w, fmt.Sprintf("Bad Request: Out of file space. Max space: %d.", c.MaxUserBytes), http.StatusBadRequest) + return + } } http.Redirect(w, r, "/my_site", http.StatusSeeOther) } -// bool whether auth'd, string is auth user func getAuthUser(r *http.Request) (bool, string, bool) { session, _ := SessionStore.Get(r, "cookie-session") user, ok := session.Values["auth_user"].(string)

@@ -477,7 +490,7 @@ PageTitle string

}{template.HTML(htmlString), favicon, userName + p} t.ExecuteTemplate(w, "user_page.html", data) } else { - http.ServeFile(w, r, fileName) // TODO make errors pretty + http.ServeFile(w, r, fileName) } }
M utils.goutils.go

@@ -40,6 +40,29 @@ return fmt.Sprintf("%d days ago", days)

} } +func userHasSpace(user string, newBytes int) bool { + userPath := path.Join(c.FilesDirectory, user) + size, err := dirSize(userPath) + if err != nil || size+int64(newBytes) > c.MaxUserBytes { + return false + } + return true +} + +func dirSize(path string) (int64, error) { + var size int64 + err := filepath.Walk(path, func(_ string, info os.FileInfo, err error) error { + if err != nil { + return err + } + if !info.IsDir() { + size += info.Size() + } + return err + }) + return size, err +} + /// Perform some checks to make sure the file is OK func checkIfValidFile(filename string, fileBytes []byte) error { if len(filename) == 0 {

@@ -58,9 +81,10 @@ }

if !found { return fmt.Errorf("Invalid file extension: %s", ext) } - if len(fileBytes) > c.MaxFileSize { - return fmt.Errorf("File too large. File was %d bytes, Max file size is %d", len(fileBytes), c.MaxFileSize) + if len(fileBytes) > c.MaxFileBytes { + return fmt.Errorf("File too large. File was %d bytes, Max file size is %d", len(fileBytes), c.MaxFileBytes) } + // return nil }