package handler import ( "crypto/sha256" "encoding/hex" "fmt" "io" "net/http" "os" "path/filepath" "strings" "time" ) func handleUpload(w http.ResponseWriter, r *http.Request) { if r.Method != http.MethodPost { writeErr(w, 405, "Method not allowed") return } if err := r.ParseMultipartForm(20 << 20); err != nil { writeErr(w, 400, "image too large (max 20MB)") return } file, _, err := r.FormFile("image") if err != nil { writeErr(w, 400, "missing image file") return } defer file.Close() data, err := io.ReadAll(file) if err != nil || len(data) == 0 { writeErr(w, 400, "failed to read image") return } ct := http.DetectContentType(data) if !strings.HasPrefix(ct, "image/") { writeErr(w, 400, "file is not an image") return } hash := sha256.Sum256(data) name := hex.EncodeToString(hash[:])[:16] + "_" + fmt.Sprintf("%d", time.Now().UnixNano()) dir := "static/images" os.MkdirAll(dir, 0755) // Determine extension from content type ext := ".jpg" switch { case strings.Contains(ct, "png"): ext = ".png" case strings.Contains(ct, "webp"): ext = ".webp" case strings.Contains(ct, "gif"): ext = ".gif" case strings.Contains(ct, "svg"): ext = ".svg" } filePath := filepath.Join(dir, name+ext) if err := os.WriteFile(filePath, data, 0644); err != nil { writeErr(w, 500, "failed to save image") return } url := "/static/images/" + name + ext writeJSON(w, 200, map[string]string{"url": url, "filename": name + ext}) }