package handlers import ( "bytes" "image" _ "image/jpeg" "image/png" "io" "net/http" "strings" "github.com/disintegration/imaging" "github.com/user/nanometrics/server/db" ) const maxIconSize = 128 func IconUploadHandler(database *db.DB) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { if r.Method != http.MethodPost { http.Error(w, "method not allowed", 405) return } parts := strings.Split(strings.Trim(r.URL.Path, "/"), "/") if len(parts) < 4 { http.Error(w, "invalid path", 400) return } agentID := parts[2] r.ParseMultipartForm(2 << 20) file, header, err := r.FormFile("icon") if err != nil { http.Error(w, "fichier manquant", 400) return } defer file.Close() mime := header.Header.Get("Content-Type") if mime == "" { mime = "image/png" } // SVG refusé (risque XSS) if strings.Contains(mime, "svg") { http.Error(w, "SVG non supporté — utilisez PNG, JPG ou WEBP", 400) return } // Limite de taille limited := io.LimitReader(file, 2<<20) img, _, err := image.Decode(limited) if err != nil { http.Error(w, "image invalide", 400) return } resized := imaging.Fit(img, maxIconSize, maxIconSize, imaging.Lanczos) var buf bytes.Buffer if err := png.Encode(&buf, resized); err != nil { http.Error(w, err.Error(), 500) return } if err := database.SaveIcon(agentID, buf.Bytes(), "image/png"); err != nil { http.Error(w, err.Error(), 500) return } w.WriteHeader(http.StatusNoContent) } } func IconGetHandler(database *db.DB) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { parts := strings.Split(strings.Trim(r.URL.Path, "/"), "/") if len(parts) < 4 { http.Error(w, "invalid path", 400) return } agentID := parts[2] data, mime, err := database.GetIcon(agentID) if err != nil { http.Error(w, "not found", 404) return } w.Header().Set("Content-Type", mime) w.Write(data) } }