58535fda7b
安全: - 渠道 webhook 入站强制令牌鉴权(恒定时间比较+统一文案),企微签名官方算法; - 报表/概览/systemInfo 端点按 usage:read/audit:read/system:manage 授权; - sso_error 固定错误码;个人渠道令牌仅请求头;工具出站 Dialer.Control 消除 DNS rebinding TOCTOU;新增 channel:read/manage 权限;限流倍数上限 10。 并发/一致性: - 任务上报单条条件 UPDATE 防重放双提交;认领回收过期 claimed 任务; - 审批改先开通后落记录(幂等,无嵌套事务);聊天消息单事务落库; - 会话列表校验 AuthVersion;吊销先 Del 后 SRem;删工具保护调用历史; - rejected 冷却 24h;限流被拒补偿;maintenance 清理限流窗口。 前端/菜单: - 修复 gatewayChildren late-append 导致 reports/tenants/channels 菜单不可见; - 聊天改名 PUT 对齐;渠道编辑清空凭据防串写+启用开关; - 聊天响应防串扰;报表本地时区日期。
148 lines
5.5 KiB
Go
148 lines
5.5 KiB
Go
package identity
|
|
|
|
import (
|
|
"errors"
|
|
"sort"
|
|
"time"
|
|
)
|
|
|
|
var (
|
|
ErrNotFound = errors.New("identity not found")
|
|
ErrUnavailable = errors.New("identity service unavailable")
|
|
)
|
|
|
|
type Kind string
|
|
|
|
const (
|
|
KindAdmin Kind = "admin"
|
|
KindPortal Kind = "portal"
|
|
)
|
|
|
|
type Account struct {
|
|
ID string
|
|
Kind Kind
|
|
Login string
|
|
DisplayName string
|
|
Role string
|
|
Permissions []string
|
|
PasswordHash string
|
|
AuthSource string
|
|
Active bool
|
|
FailedLogins int
|
|
LockedUntil *time.Time
|
|
TOTPEnabled bool
|
|
EncryptedTOTPSecret []byte
|
|
TOTPKekVersion *int
|
|
TOTPLastStep *int64
|
|
TOTPBackupCodes []byte
|
|
DepartmentID *string
|
|
DepartmentName string
|
|
CreatedAt time.Time
|
|
UpdatedAt time.Time
|
|
}
|
|
|
|
const (
|
|
PermissionIdentityManage = "identity:manage"
|
|
PermissionProviderRead = "provider:read"
|
|
PermissionProviderManage = "provider:manage"
|
|
PermissionAPIKeyRead = "api_key:read"
|
|
PermissionAPIKeyManage = "api_key:manage"
|
|
PermissionAuditRead = "audit:read"
|
|
PermissionUsageRead = "usage:read"
|
|
PermissionOutboxRead = "outbox:read"
|
|
PermissionOutboxManage = "outbox:manage"
|
|
PermissionContentPolicyRead = "content_policy:read"
|
|
PermissionContentPolicyManage = "content_policy:manage"
|
|
PermissionPricingRead = "pricing:read"
|
|
PermissionPricingManage = "pricing:manage"
|
|
PermissionPromptRead = "prompt:read"
|
|
PermissionPromptManage = "prompt:manage"
|
|
PermissionKnowledgeRead = "knowledge:read"
|
|
PermissionKnowledgeManage = "knowledge:manage"
|
|
PermissionToolRead = "tool:read"
|
|
PermissionToolManage = "tool:manage"
|
|
PermissionApplicationRead = "application:read"
|
|
PermissionApplicationManage = "application:manage"
|
|
PermissionNotificationRead = "notification:read"
|
|
PermissionNotificationManage = "notification:manage"
|
|
PermissionChannelRead = "channel:read"
|
|
PermissionChannelManage = "channel:manage"
|
|
PermissionMCPServerRead = "mcp_server:read"
|
|
PermissionMCPServerManage = "mcp_server:manage"
|
|
PermissionSkillRead = "skill:read"
|
|
PermissionSkillManage = "skill:manage"
|
|
PermissionDigitalEmployeeRead = "digital_employee:read"
|
|
PermissionDigitalEmployeeManage = "digital_employee:manage"
|
|
PermissionMarketplaceRead = "marketplace:read"
|
|
PermissionMarketplaceManage = "marketplace:manage"
|
|
PermissionFileRead = "file:read"
|
|
PermissionFileManage = "file:manage"
|
|
PermissionInboxRead = "inbox:read"
|
|
PermissionInboxManage = "inbox:manage"
|
|
PermissionScheduledTaskRead = "scheduled_task:read"
|
|
PermissionScheduledTaskManage = "scheduled_task:manage"
|
|
PermissionTraceRead = "trace:read"
|
|
PermissionAgentNodeRead = "agent_node:read"
|
|
PermissionAgentNodeManage = "agent_node:manage"
|
|
PermissionSystemManage = "system:manage"
|
|
)
|
|
|
|
var rolePermissions = map[string][]string{
|
|
"superadmin": {"*"},
|
|
"operator": {
|
|
PermissionProviderRead, PermissionProviderManage,
|
|
PermissionAPIKeyRead, PermissionAPIKeyManage,
|
|
PermissionUsageRead,
|
|
PermissionOutboxRead, PermissionOutboxManage,
|
|
PermissionContentPolicyRead, PermissionContentPolicyManage,
|
|
PermissionPricingRead, PermissionPricingManage,
|
|
PermissionPromptRead, PermissionPromptManage,
|
|
PermissionKnowledgeRead, PermissionKnowledgeManage,
|
|
PermissionToolRead, PermissionToolManage,
|
|
PermissionApplicationRead, PermissionApplicationManage,
|
|
PermissionNotificationRead, PermissionNotificationManage,
|
|
PermissionChannelRead, PermissionChannelManage,
|
|
PermissionMCPServerRead, PermissionMCPServerManage,
|
|
PermissionSkillRead, PermissionSkillManage,
|
|
PermissionDigitalEmployeeRead, PermissionDigitalEmployeeManage,
|
|
PermissionMarketplaceRead, PermissionMarketplaceManage,
|
|
PermissionFileRead, PermissionFileManage,
|
|
PermissionInboxRead, PermissionInboxManage,
|
|
PermissionScheduledTaskRead, PermissionScheduledTaskManage,
|
|
PermissionTraceRead,
|
|
PermissionAgentNodeRead, PermissionAgentNodeManage,
|
|
PermissionSystemManage,
|
|
},
|
|
"auditor": {PermissionProviderRead, PermissionAPIKeyRead, PermissionAuditRead, PermissionUsageRead, PermissionOutboxRead, PermissionContentPolicyRead, PermissionPricingRead, PermissionPromptRead, PermissionKnowledgeRead, PermissionToolRead, PermissionApplicationRead, PermissionNotificationRead, PermissionChannelRead, PermissionMCPServerRead, PermissionSkillRead, PermissionDigitalEmployeeRead, PermissionMarketplaceRead, PermissionFileRead, PermissionInboxRead, PermissionScheduledTaskRead, PermissionTraceRead, PermissionAgentNodeRead},
|
|
"member": {},
|
|
}
|
|
|
|
func EffectivePermissions(account Account) []string {
|
|
seen := make(map[string]struct{})
|
|
result := make([]string, 0, len(account.Permissions)+4)
|
|
for _, permissions := range [][]string{rolePermissions[account.Role], account.Permissions} {
|
|
for _, permission := range permissions {
|
|
if _, exists := seen[permission]; exists {
|
|
continue
|
|
}
|
|
seen[permission] = struct{}{}
|
|
result = append(result, permission)
|
|
}
|
|
}
|
|
sort.Strings(result)
|
|
return result
|
|
}
|
|
|
|
func HasPermission(account Account, required string) bool {
|
|
for _, permission := range EffectivePermissions(account) {
|
|
if permission == "*" || permission == required {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
func (a Account) Locked(now time.Time) bool {
|
|
return a.LockedUntil != nil && a.LockedUntil.After(now)
|
|
}
|