package entities import ( "regexp" "strings" "time" "go.mongodb.org/mongo-driver/v2/bson" ) var permissionTokenSanitizer = regexp.MustCompile(`[^a-z0-9_-]+`) // PermissionGroup represents a named group of permissions. type PermissionGroup struct { ID bson.ObjectID `bson:"_id,omitempty"` Name string `bson:"name"` NameKey string `bson:"name_key"` Description string `bson:"description,omitempty"` Permissions []string `bson:"permissions"` IsSystem bool `bson:"is_system"` CreatedAt time.Time `bson:"created_at"` UpdatedAt time.Time `bson:"updated_at"` } // NormalizePermission lowercases and trims a permission string. func NormalizePermission(permission string) string { return strings.ToLower(strings.TrimSpace(permission)) } // SpacePermissionToken converts a space name to a dot-safe permission token. func SpacePermissionToken(spaceName string) string { normalized := strings.ToLower(strings.TrimSpace(spaceName)) normalized = strings.ReplaceAll(normalized, " ", "_") normalized = permissionTokenSanitizer.ReplaceAllString(normalized, "_") normalized = strings.Trim(normalized, "_") if normalized == "" { return "space" } return normalized } // PermissionMatches reports whether a wildcard pattern matches a concrete permission. func PermissionMatches(pattern, permission string) bool { pattern = NormalizePermission(pattern) permission = NormalizePermission(permission) if pattern == "" || permission == "" { return false } if pattern == "*" || pattern == permission { return true } if !strings.Contains(pattern, "*") { return false } parts := strings.Split(pattern, "*") remaining := permission if parts[0] != "" { if !strings.HasPrefix(remaining, parts[0]) { return false } remaining = remaining[len(parts[0]):] } for i := 1; i < len(parts); i++ { part := parts[i] if part == "" { continue } idx := strings.Index(remaining, part) if idx < 0 { return false } remaining = remaining[idx+len(part):] } if parts[len(parts)-1] != "" { return strings.HasSuffix(permission, parts[len(parts)-1]) } return true }