package middleware import ( "bytes" "encoding/json" "io" "github.com/Tencent/WeKnora/internal/accesspolicy" apperrors "github.com/Tencent/WeKnora/internal/errors" "github.com/Tencent/WeKnora/internal/types" "github.com/gin-gonic/gin" ) // RequireKnowledgeVersionTransfer prevents stripping no-export provenance by // copying or moving protected material into an unrelated, exportable KB. func RequireKnowledgeVersionTransfer() gin.HandlerFunc { return func(c *gin.Context) { ctx := c.Request.Context() if types.IsSystemAdminFromContext(ctx) || types.TenantRoleFromContext(ctx).HasPermission(types.TenantRoleAdmin) { c.Next() return } if _, apiKey := types.TenantAPIKeyScopeFromContext(ctx); apiKey { c.Next() return } snapshot := accesspolicy.FromContext(ctx) if snapshot == nil { c.Next() return } body, err := io.ReadAll(io.LimitReader(c.Request.Body, (1<<20)+1)) if err != nil || len(body) > 1<<20 { _ = c.Error(apperrors.NewBadRequestError("复制或移动请求过大")) c.Abort() return } c.Request.Body = io.NopCloser(bytes.NewReader(body)) var request struct { SourceID string `json:"source_id"` SourceKBID string `json:"source_kb_id"` } if err = json.Unmarshal(body, &request); err != nil { _ = c.Error(apperrors.NewBadRequestError("无效的复制或移动请求")) c.Abort() return } for _, id := range []string{request.SourceID, request.SourceKBID} { if id != "" && (snapshot.NoExport["knowledge:"+id] || snapshot.Publications["knowledge:"+id]) { _ = c.Error(apperrors.NewForbiddenError("此知识库不可复制或移动到其他知识库;请在我的资源版本中创建独立个人版本")) c.Abort() return } } c.Next() } }