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" 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" ) 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, PermissionMCPServerRead, PermissionMCPServerManage, PermissionSkillRead, PermissionSkillManage, PermissionDigitalEmployeeRead, PermissionDigitalEmployeeManage, PermissionMarketplaceRead, PermissionMarketplaceManage, }, "auditor": {PermissionProviderRead, PermissionAPIKeyRead, PermissionAuditRead, PermissionUsageRead, PermissionOutboxRead, PermissionContentPolicyRead, PermissionPricingRead, PermissionPromptRead, PermissionKnowledgeRead, PermissionToolRead, PermissionApplicationRead, PermissionNotificationRead, PermissionMCPServerRead, PermissionSkillRead, PermissionDigitalEmployeeRead, PermissionMarketplaceRead}, "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) }