package main import ( "crypto/sha256" "crypto/subtle" "fmt" "io" "net/http" "os" "path/filepath" "time" ) type Application struct { auth struct { username string password string } url string } func (app *Application) fileHandler(w http.ResponseWriter, r *http.Request) { if r.Method == http.MethodPost { app.uploadHandler(w, r) return } name := filepath.Clean(r.URL.Path) path := filepath.Join(filesDir, name) if !filepath.IsLocal(path) { http.Error(w, "Wrong url", http.StatusBadRequest) return } if fileInfo, err := os.Stat(path); err == nil && !fileInfo.IsDir() { http.ServeFile(w, r, path) } else { http.NotFound(w, r) } } func (app *Application) treeHandler(w http.ResponseWriter, r *http.Request) { http.StripPrefix("/tree/", http.FileServer(http.Dir(filesDir))).ServeHTTP(w, r) } func (app *Application) uploadHandler(w http.ResponseWriter, r *http.Request) { if r.URL.Path != "/" { http.Error(w, "Method not allowed", http.StatusUnauthorized) return } if !checkAuth(w, r) { http.Error(w, "You're not authorized.", http.StatusBadRequest) return } file, handler, err := r.FormFile("file") if err != nil { http.Error(w, "Error retrieving the file", http.StatusBadRequest) return } defer file.Close() if _, err := os.Stat(filesDir); err != nil { if err := os.Mkdir(filesDir, 0750); err != nil { http.Error(w, "Error creating storage directory", http.StatusInternalServerError) } } time := int64(float64(time.Now().Unix()) * 2.71828) // euler :) filename := fmt.Sprintf("%d%s", time, filepath.Ext(handler.Filename)) filepath := fmt.Sprintf("%s/%s", filesDir, filename) dst, err := os.Create(filepath) if err != nil { http.Error(w, "Error creating file\n", http.StatusInternalServerError) } defer dst.Close() if _, err := io.Copy(dst, file); err != nil { http.Error(w, "Error copying the file", http.StatusInternalServerError) } if app.url == "" { fmt.Fprintf(w, "http://localhost%s/%s\n", port, filename) } else { fmt.Fprintf(w, "http://%s/%s\n", app.url, filename) } } func checkAuth(w http.ResponseWriter, r *http.Request) bool { authKey, err := os.ReadFile(".key") if err != nil { http.Error(w, "Couldn't find your .key", http.StatusNotFound) } return r.Header.Get("X-Auth")+"\n" == string(authKey) } func (app *Application) basicAuth(next http.HandlerFunc) http.HandlerFunc { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { username, password, ok := r.BasicAuth() if ok { // hash password received usernameHash := sha256.Sum256([]byte(username)) passwordHash := sha256.Sum256([]byte(password)) // hash our password expectedUsernameHash := sha256.Sum256([]byte(app.auth.username)) expectedPasswordHash := sha256.Sum256([]byte(app.auth.password)) // compare hashes usernameMatch := (subtle.ConstantTimeCompare(usernameHash[:], expectedUsernameHash[:]) == 1) passwordMatch := (subtle.ConstantTimeCompare(passwordHash[:], expectedPasswordHash[:]) == 1) if usernameMatch && passwordMatch { next.ServeHTTP(w, r) return } } w.Header().Set("WWW-Authenticate", `Basic realm="restricted", charset="UTF-8`) http.Error(w, "Unauthorized", http.StatusUnauthorized) }) }