yao/agent/assistant/search_auth_kb.go
Max e46645a986 Refactor Authorization Functions and Update Tests
- Renamed functions for consistency and clarity, changing `buildDBAuthWheres` to `BuildDBAuthWheres` and `filterKBCollectionsByAuth` to `FilterKBCollectionsByAuth`.
- Enhanced test cases to utilize the updated function names, ensuring proper authorization checks in the search functionality.
- Improved test environment initialization to streamline setup processes and ensure robust testing of authorization logic.
- Verified that search results adhere to authorization constraints, ensuring only accessible collections are queried based on user permissions.
2025-12-20 15:02:01 +08:00

123 lines
3 KiB
Go

package assistant
import (
"context"
agentContext "github.com/yaoapp/yao/agent/context"
"github.com/yaoapp/yao/kb"
oauthtypes "github.com/yaoapp/yao/openapi/oauth/types"
)
// FilterKBCollectionsByAuth filters collections based on user authorization.
// Returns only collections that the user has permission to access.
// Permission is determined by Collection's metadata (public, share, __yao_team_id, __yao_created_by).
func FilterKBCollectionsByAuth(ctx *agentContext.Context, collections []string) []string {
if ctx == nil || ctx.Authorized == nil {
return collections // No auth context, return all
}
authInfo := ctx.Authorized
// No constraints, return all collections
if !authInfo.Constraints.TeamOnly && !authInfo.Constraints.OwnerOnly {
return collections
}
// Check KB API
if kb.API == nil {
return collections // KB not initialized, return all
}
var allowed []string
bgCtx := context.Background()
for _, collectionID := range collections {
// Get collection metadata
collection, err := kb.API.GetCollection(bgCtx, collectionID)
if err != nil {
continue // Skip if can't get collection
}
if hasCollectionAccess(authInfo, collection) {
allowed = append(allowed, collectionID)
}
}
return allowed
}
// hasCollectionAccess checks if user has access to a collection based on its metadata.
func hasCollectionAccess(authInfo *oauthtypes.AuthorizedInfo, collection map[string]interface{}) bool {
if authInfo == nil {
return true
}
// No constraints, allow access
if !authInfo.Constraints.TeamOnly && !authInfo.Constraints.OwnerOnly {
return true
}
// Check public access (handle different types: bool, int, float64)
if isPublicValue(collection["public"]) {
return true
}
// Get metadata for permission fields
metadata, _ := collection["metadata"].(map[string]interface{})
if metadata == nil {
metadata = collection
}
// Team only check
if authInfo.Constraints.TeamOnly && authInfo.TeamID != "" {
teamID, _ := metadata["__yao_team_id"].(string)
if teamID == "" {
teamID, _ = collection["__yao_team_id"].(string)
}
if teamID == authInfo.TeamID {
createdBy, _ := metadata["__yao_created_by"].(string)
if createdBy == "" {
createdBy, _ = collection["__yao_created_by"].(string)
}
share, _ := metadata["share"].(string)
if share == "" {
share, _ = collection["share"].(string)
}
if createdBy == authInfo.UserID || share == "team" {
return true
}
}
}
// Owner only check
if authInfo.Constraints.OwnerOnly && authInfo.UserID != "" {
createdBy, _ := metadata["__yao_created_by"].(string)
if createdBy == "" {
createdBy, _ = collection["__yao_created_by"].(string)
}
if createdBy == authInfo.UserID {
return true
}
}
return false
}
// isPublicValue checks if a value represents "public" access
func isPublicValue(v interface{}) bool {
switch val := v.(type) {
case bool:
return val
case int:
return val == 1
case int64:
return val == 1
case float64:
return val == 1
case string:
return val == "true" || val == "1"
}
return false
}