- Remove duplicate UploadBaseURL constant (identical to APIBaseURL)
- Pass parentFileID and customDomain into service constructors instead of
reading from config.GlobalConfig at call time, eliminating hidden global
state dependencies in the service layer
- Replace []interface{} response building in HandleList with a typed
imageResponse struct for compile-time safety
- Extract inline CORS closure from main.go into handler.CORSMiddleware(),
consistent with how AuthMiddleware is organized
- Remove narrating comments throughout; keep only the non-obvious one
explaining why DoRawPUT omits auth headers
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
79 lines
1.9 KiB
Go
79 lines
1.9 KiB
Go
package handler
|
|
|
|
import (
|
|
"crypto/subtle"
|
|
"net/http"
|
|
"strings"
|
|
|
|
"github.com/gin-gonic/gin"
|
|
"imagehost/internal/config"
|
|
"imagehost/static"
|
|
)
|
|
|
|
func CORSMiddleware() gin.HandlerFunc {
|
|
return func(c *gin.Context) {
|
|
c.Writer.Header().Set("Access-Control-Allow-Origin", "*")
|
|
c.Writer.Header().Set("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE")
|
|
c.Writer.Header().Set("Access-Control-Allow-Headers", "Content-Type, Authorization")
|
|
if c.Request.Method == "OPTIONS" {
|
|
c.AbortWithStatus(http.StatusNoContent)
|
|
return
|
|
}
|
|
c.Next()
|
|
}
|
|
}
|
|
|
|
func AuthMiddleware() gin.HandlerFunc {
|
|
return func(c *gin.Context) {
|
|
tokenCfg := config.GlobalConfig.APIToken
|
|
if tokenCfg == "" {
|
|
c.Next()
|
|
return
|
|
}
|
|
|
|
authHeader := c.GetHeader("Authorization")
|
|
queryToken := c.Query("token")
|
|
|
|
var clientToken string
|
|
if strings.HasPrefix(authHeader, "Bearer ") {
|
|
clientToken = strings.TrimPrefix(authHeader, "Bearer ")
|
|
} else if authHeader != "" {
|
|
clientToken = authHeader
|
|
} else {
|
|
clientToken = queryToken
|
|
}
|
|
|
|
// constant-time compare prevents timing-based token enumeration
|
|
if subtle.ConstantTimeCompare([]byte(clientToken), []byte(tokenCfg)) != 1 {
|
|
c.JSON(http.StatusForbidden, gin.H{
|
|
"code": 403,
|
|
"message": "未经授权访问:请提供正确的 api_token 以进行操作。",
|
|
})
|
|
c.Abort()
|
|
return
|
|
}
|
|
|
|
c.Next()
|
|
}
|
|
}
|
|
|
|
func ConfigureRoutes(r *gin.Engine, imgHandler *ImageHandler, upHandler *UploadHandler) {
|
|
api := r.Group("/api")
|
|
api.Use(AuthMiddleware())
|
|
{
|
|
api.POST("/upload", upHandler.HandleUpload)
|
|
api.GET("/images", imgHandler.HandleList)
|
|
api.DELETE("/images/:id", imgHandler.HandleDelete)
|
|
}
|
|
|
|
r.StaticFS("/static", http.FS(static.FS))
|
|
r.GET("/", func(c *gin.Context) {
|
|
htmlData, err := static.FS.ReadFile("index.html")
|
|
if err != nil {
|
|
c.String(http.StatusInternalServerError, "内置静态首页打包遗失")
|
|
return
|
|
}
|
|
c.Data(http.StatusOK, "text/html; charset=utf-8", htmlData)
|
|
})
|
|
}
|