diff options
| author | Collin Williams <96917990+bluedragon1221@users.noreply.github.com> | 2026-04-29 15:20:57 -0500 |
|---|---|---|
| committer | Collin Williams <96917990+bluedragon1221@users.noreply.github.com> | 2026-04-29 15:20:57 -0500 |
| commit | 9c9a49a855951662da62bcdec45f69ddc0099e5c (patch) | |
| tree | 1f7852971693d9e49d16a77aff51b87d39940b1b /modules/services/nixos/ganyupload/main.go | |
| parent | 21de12cd6e63adf463674942f1a8f9b658f47945 (diff) | |
changes
Diffstat (limited to 'modules/services/nixos/ganyupload/main.go')
| -rw-r--r-- | modules/services/nixos/ganyupload/main.go | 104 |
1 files changed, 104 insertions, 0 deletions
diff --git a/modules/services/nixos/ganyupload/main.go b/modules/services/nixos/ganyupload/main.go new file mode 100644 index 0000000..6aa219e --- /dev/null +++ b/modules/services/nixos/ganyupload/main.go @@ -0,0 +1,104 @@ +package main + +import ( + _ "embed" + "io" + "log" + "net/http" + "os" + "path/filepath" + "strings" +) + +//go:embed README +var readme string + +var uploadDir = "." + +func handleRoot(w http.ResponseWriter, r *http.Request) { + if r.Method != http.MethodGet { + http.Error(w, "method not allowed", http.StatusMethodNotAllowed) + return + } + + w.Header().Set("Content-Type", "text/plain; charset=utf-8") + w.Write([]byte(readme)) +} + +func handleUpload(w http.ResponseWriter, r *http.Request) { + // Show README on GET / + if r.Method == http.MethodGet && r.URL.Path == "/" { + handleRoot(w, r) + return + } + + if r.Method != http.MethodPut { + http.Error(w, "method not allowed", http.StatusMethodNotAllowed) + return + } + + // Extract filename from URL path, preventing path traversal + filename := strings.TrimPrefix(r.URL.Path, "/") + if filename == "" { + http.Error(w, "filename required", http.StatusBadRequest) + return + } + + // Prevent path traversal + filename = filepath.Clean(filename) + if strings.HasPrefix(filename, "..") { + http.Error(w, "invalid filename", http.StatusBadRequest) + return + } + + fullPath := filepath.Join(uploadDir, filename) + + // Ensure the directory exists + dir := filepath.Dir(fullPath) + if err := os.MkdirAll(dir, 0755); err != nil { + log.Printf("failed to create directory: %v", err) + http.Error(w, "internal server error", http.StatusInternalServerError) + return + } + + // Create the file + f, err := os.Create(fullPath) + if err != nil { + log.Printf("failed to create file: %v", err) + http.Error(w, "internal server error", http.StatusInternalServerError) + return + } + defer f.Close() + + // Copy request body to file + written, err := io.Copy(f, r.Body) + if err != nil { + log.Printf("failed to write file: %v", err) + http.Error(w, "internal server error", http.StatusInternalServerError) + return + } + + w.Header().Set("Content-Type", "text/plain; charset=utf-8") + w.WriteHeader(http.StatusCreated) + w.Write([]byte("ok\n")) + + log.Printf("uploaded %s (%d bytes)", filename, written) +} + +func main() { + if envUploadDir := os.Getenv("UPLOAD_DIR"); envUploadDir != "" { + uploadDir = envUploadDir + } + + port := os.Getenv("PORT") + if port == "" { + port = "8080" + } + + http.HandleFunc("/", handleUpload) + + log.Printf("starting ganyupload on port %s, upload directory: %s", port, uploadDir) + if err := http.ListenAndServe(":"+port, nil); err != nil { + log.Fatalf("server error: %v", err) + } +} |
