Initial commit: CarrotAssistant backend (Go + Gin + SQLite, OpenAI-compatible agent runtime)
This commit is contained in:
71
internal/server/chat_middleware.go
Normal file
71
internal/server/chat_middleware.go
Normal file
@@ -0,0 +1,71 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"gorm.io/gorm"
|
||||
|
||||
"code.littlelan.cn/CarrotAssistant/backend/internal/security"
|
||||
"code.littlelan.cn/CarrotAssistant/backend/internal/store"
|
||||
)
|
||||
|
||||
// RequireAppToken guards the public /api/v1 chat routes. It expects an
|
||||
// X-App-Token header whose SHA-256 hash matches an App row. The matched App
|
||||
// is placed on the context as "app".
|
||||
func (d Deps) RequireAppToken() gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
raw := strings.TrimSpace(c.GetHeader("X-App-Token"))
|
||||
if raw == "" {
|
||||
c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{"error": "缺少 X-App-Token"})
|
||||
return
|
||||
}
|
||||
hash := security.HashToken(raw)
|
||||
var app store.App
|
||||
err := d.DB.Where("token_hash = ? AND status = ?", hash, "active").First(&app).Error
|
||||
if err != nil {
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{"error": "无效的 token"})
|
||||
return
|
||||
}
|
||||
c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{"error": "查询失败"})
|
||||
return
|
||||
}
|
||||
c.Set("app", &app)
|
||||
c.Next()
|
||||
}
|
||||
}
|
||||
|
||||
// appCtx returns the App placed by RequireAppToken.
|
||||
func appCtx(c *gin.Context) *store.App {
|
||||
v, _ := c.Get("app")
|
||||
if v == nil {
|
||||
return nil
|
||||
}
|
||||
return v.(*store.App)
|
||||
}
|
||||
|
||||
// createSession persists a new session row and returns it.
|
||||
func (d Deps) createSession(appID int64, title string) (*store.Session, error) {
|
||||
id, err := newUUID()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
s := &store.Session{ID: id, AppID: appID, Title: title}
|
||||
if err := d.DB.Create(s).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return s, nil
|
||||
}
|
||||
|
||||
// loadSessionOwnedBy returns a session only if it belongs to appID.
|
||||
func (d Deps) loadSessionOwnedBy(sessionID string, appID int64) (*store.Session, error) {
|
||||
var s store.Session
|
||||
err := d.DB.Where("id = ? AND app_id = ?", sessionID, appID).First(&s).Error
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &s, nil
|
||||
}
|
||||
Reference in New Issue
Block a user