fix: add field whitelist to site update, fix HTTP status codes in site handlers

- SiteService.Update: whitelist updatable fields to prevent injection of
  id, created_at, deleted_at, login_status, upload_bytes, download_bytes
- createSiteHandler: return 201 Created (was 200 OK)
- siteSearchHandler: return 500 for infra errors (was 400)

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
This commit is contained in:
soldosluka857
2026-05-30 02:22:27 +00:00
committed by Shuke
parent 2c45fa596a
commit 0572612833
2 changed files with 42 additions and 9 deletions
+2 -2
View File
@@ -102,7 +102,7 @@ func createSiteHandler(svc *service.Container) gin.HandlerFunc {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
c.JSON(http.StatusOK, site)
c.JSON(http.StatusCreated, site)
}
}
@@ -156,7 +156,7 @@ func siteSearchHandler(svc *service.Container) gin.HandlerFunc {
}
results, err := svc.Site.Search(c.Request.Context(), keyword)
if err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
c.JSON(http.StatusOK, gin.H{"items": results, "total": len(results)})
+40 -7
View File
@@ -213,20 +213,53 @@ func (s *SiteService) FindByID(ctx context.Context, id string) (*model.Site, err
return &site, err
}
// siteUpdatableFields is the whitelist of columns that may be patched via
// the update endpoint. Fields like id, created_at, deleted_at, login_status,
// upload_bytes, download_bytes are excluded to prevent injection.
var siteUpdatableFields = map[string]bool{
"name": true,
"url": true,
"type": true,
"auth_type": true,
"api_key": true,
"cookie": true,
"auth_header": true,
"user_agent": true,
"rss_url": true,
"timeout": true,
"priority": true,
"use_proxy": true,
"rate_limit": true,
"browser_emulation": true,
"downloader": true,
"enabled": true,
"is_default": true,
"extra": true,
}
// Update applies a partial patch to an existing site.
func (s *SiteService) Update(ctx context.Context, id string, updates map[string]any) error {
if id == "" {
return errors.New("site id required")
}
if raw, ok := updates["url"].(string); ok {
updates["url"] = strings.TrimRight(strings.TrimSpace(raw), "/")
}
for _, key := range []string{"api_key", "cookie", "auth_header"} {
if raw, ok := updates[key].(string); ok && strings.TrimSpace(raw) == "" {
delete(updates, key)
filtered := make(map[string]any, len(updates))
for k, v := range updates {
if siteUpdatableFields[k] {
filtered[k] = v
}
}
return s.repo.DB.WithContext(ctx).Model(&model.Site{}).Where("id = ?", id).Updates(updates).Error
if len(filtered) == 0 {
return errors.New("no valid fields to update")
}
if raw, ok := filtered["url"].(string); ok {
filtered["url"] = strings.TrimRight(strings.TrimSpace(raw), "/")
}
for _, key := range []string{"api_key", "cookie", "auth_header"} {
if raw, ok := filtered[key].(string); ok && strings.TrimSpace(raw) == "" {
delete(filtered, key)
}
}
return s.repo.DB.WithContext(ctx).Model(&model.Site{}).Where("id = ?", id).Updates(filtered).Error
}
// Delete removes a site.