package aether import "strings" // MatchNamespacePattern checks if a namespace matches a pattern. // Patterns follow NATS subject matching conventions where tokens are separated by dots: // - "*" matches exactly one token (any sequence without ".") // - ">" matches one or more tokens (only valid at the end of a pattern) // - Exact strings match exactly // // Examples: // - "tenant-a" matches "tenant-a" (exact match) // - "*" matches any single-token namespace like "tenant-a" or "production" // - ">" matches any namespace with one or more tokens // - "prod.*" matches "prod.tenant", "prod.orders" (but not "prod.tenant.orders") // - "prod.>" matches "prod.tenant", "prod.tenant.orders", "prod.a.b.c" // - "*.tenant.*" matches "prod.tenant.orders", "staging.tenant.events" // // Security Considerations: // Wildcard subscriptions provide cross-namespace visibility. Use with caution: // - "*" or ">" patterns receive events from ALL matching namespaces // - This bypasses namespace isolation for the subscriber // - Only grant wildcard subscription access to trusted system components // - Consider auditing wildcard subscription usage // - For multi-tenant systems, wildcard access should be restricted to admin/ops // - Use the most specific pattern possible to minimize exposure func MatchNamespacePattern(pattern, namespace string) bool { // Empty pattern matches nothing if pattern == "" { return false } // ">" matches everything when used alone if pattern == ">" { return namespace != "" } patternTokens := strings.Split(pattern, ".") namespaceTokens := strings.Split(namespace, ".") return matchTokens(patternTokens, namespaceTokens) } // matchTokens recursively matches pattern tokens against namespace tokens func matchTokens(patternTokens, namespaceTokens []string) bool { // If pattern is exhausted, namespace must also be exhausted if len(patternTokens) == 0 { return len(namespaceTokens) == 0 } patternToken := patternTokens[0] // ">" matches one or more remaining tokens (must be last pattern token) if patternToken == ">" { // ">" requires at least one token to match return len(namespaceTokens) >= 1 } // If namespace is exhausted but pattern has more tokens, no match if len(namespaceTokens) == 0 { return false } namespaceToken := namespaceTokens[0] // "*" matches exactly one token if patternToken == "*" { return matchTokens(patternTokens[1:], namespaceTokens[1:]) } // Exact match required if patternToken == namespaceToken { return matchTokens(patternTokens[1:], namespaceTokens[1:]) } return false } // IsWildcardPattern returns true if the pattern contains wildcards (* or >). // Wildcard patterns can match multiple namespaces and bypass namespace isolation. func IsWildcardPattern(pattern string) bool { return strings.Contains(pattern, "*") || strings.Contains(pattern, ">") }