package service import ( "context" "github.com/Tencent/WeKnora/internal/accesspolicy" apperrors "github.com/Tencent/WeKnora/internal/errors" "github.com/Tencent/WeKnora/internal/types" ) func assetAdministrator(ctx context.Context) bool { return types.IsSystemAdminFromContext(ctx) || types.TenantRoleFromContext(ctx).HasPermission(types.TenantRoleAdmin) } func assetOwnedByCaller(ctx context.Context, tenant uint64, owner string) bool { current, ok := types.TenantIDFromContext(ctx) if !ok || current == 0 || current != tenant { return false } if assetAdministrator(ctx) { return true } user, ok := types.UserIDFromContext(ctx) return ok && user != "" && !types.IsSyntheticUserID(user) && owner != "" && owner == user } // CheckKnowledgeBaseCopyPermission is used before enqueueing and again by the // worker. Jobs without a human initiator retain their internal tenant scope. func CheckKnowledgeBaseCopyPermission(ctx context.Context, kb *types.KnowledgeBase) error { tenant, ok := types.TenantIDFromContext(ctx) if kb == nil || !ok || tenant == 0 || kb.TenantID != tenant { return apperrors.NewForbiddenError("没有此知识库的复制权限") } if assetAdministrator(ctx) { return nil } user, hasUser := types.UserIDFromContext(ctx) if _, apiKey := types.TenantAPIKeyScopeFromContext(ctx); apiKey { return types.AuthorizeTenantAPIKeyKnowledgeBases(ctx, kb.ID) } if !hasUser && accesspolicy.FromContext(ctx) == nil { return nil } if user == "" || types.IsSyntheticUserID(user) || user != kb.CreatorID { return apperrors.NewForbiddenError("共享知识库仅支持查看和使用,不能复制") } if snapshot := accesspolicy.FromContext(ctx); snapshot != nil && snapshot.NoExport["knowledge:"+kb.ID] { return apperrors.NewForbiddenError("此知识库不允许复制或导出") } return nil } func nativeAgentReadable(ctx context.Context, agent *types.CustomAgent) bool { if agent == nil { return false } agent.EnsureDefaults() tenant, ok := types.TenantIDFromContext(ctx) if !agent.Enabled && !assetOwnedByCaller(ctx, agent.TenantID, agent.CreatedBy) { return false } return ok && tenant != 0 && tenant == agent.TenantID && accesspolicy.Allowed(ctx, "agents.read") && accesspolicy.Readable(ctx, "agents", agent.ID, assetOwnedByCaller(ctx, tenant, agent.CreatedBy), agent.Visibility == "global" && agent.Enabled) } func nativeAgentExecutableDependency(ctx context.Context, agent *types.CustomAgent) bool { if agent == nil { return false } agent.EnsureDefaults() return agent.Enabled && accesspolicy.CanExecuteDependency(ctx, agent.TenantID, "agents", agent.ID, agent.CreatedBy) } func instructionSkillReadable(ctx context.Context, skill *types.TenantSkillCatalogEntity) bool { if skill == nil || !skill.InstructionOnly { return false } skill.EnsureInstructionDefaults() tenant, ok := types.TenantIDFromContext(ctx) if !skill.Enabled && !assetOwnedByCaller(ctx, skill.TenantID, skill.CreatedBy) { return false } return ok && tenant != 0 && tenant == skill.TenantID && accesspolicy.Allowed(ctx, "agents.read") && accesspolicy.Readable(ctx, "skills", skill.ID, assetOwnedByCaller(ctx, tenant, skill.CreatedBy), skill.Visibility == "global" && skill.Enabled) }