Extract the Central networking functionality from wild-cloud/api into a standalone service. Wild Central manages DNS (dnsmasq), gateway (HAProxy), firewall (nftables), VPN (WireGuard), TLS (certbot), security (CrowdSec), and DDNS — all the network appliance concerns. All Cloud-specific code (instances, clusters, nodes, apps, backups, operations, kubectl/talosctl tooling) has been removed. The API struct and route registration contain only Central endpoints. Tests updated to match the new API signature. Builds and all tests pass. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
81 lines
2.6 KiB
Go
81 lines
2.6 KiB
Go
package v1
|
|
|
|
import (
|
|
"fmt"
|
|
"regexp"
|
|
"strings"
|
|
)
|
|
|
|
const (
|
|
maxInstanceNameLength = 63 // Kubernetes DNS label limit (RFC 1123)
|
|
maxNodeIdentifierLength = 253 // RFC 1035 hostname limit
|
|
)
|
|
|
|
// validNamePattern matches valid resource names.
|
|
// Names must:
|
|
// - Start and end with a lowercase letter or number
|
|
// - Contain only lowercase letters, numbers, and hyphens
|
|
// - Be between 1 and 63 characters
|
|
// This follows Kubernetes naming conventions for consistency.
|
|
var validNamePattern = regexp.MustCompile(`^[a-z0-9]([a-z0-9-]*[a-z0-9])?$`)
|
|
|
|
// ValidateName validates a resource name (instance, app, node, etc.).
|
|
// Returns an error if the name is invalid.
|
|
func ValidateName(name string) error {
|
|
if name == "" {
|
|
return fmt.Errorf("name is required")
|
|
}
|
|
if len(name) > maxInstanceNameLength {
|
|
return fmt.Errorf("name must be %d characters or less", maxInstanceNameLength)
|
|
}
|
|
if !validNamePattern.MatchString(name) {
|
|
return fmt.Errorf("name must contain only lowercase letters, numbers, and hyphens, and must start and end with a letter or number")
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// ValidateInstanceName validates an instance name with a user-friendly error message.
|
|
func ValidateInstanceName(name string) error {
|
|
if err := ValidateName(name); err != nil {
|
|
return fmt.Errorf("invalid instance name: %w", err)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// ValidateAppName validates an app name with a user-friendly error message.
|
|
func ValidateAppName(name string) error {
|
|
if err := ValidateName(name); err != nil {
|
|
return fmt.Errorf("invalid app name: %w", err)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// ValidateServiceName validates a service name with a user-friendly error message.
|
|
func ValidateServiceName(name string) error {
|
|
if err := ValidateName(name); err != nil {
|
|
return fmt.Errorf("invalid service name: %w", err)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// ValidateNodeIdentifier validates a node identifier (hostname or IP).
|
|
// Node identifiers have slightly relaxed rules since they can be IPs.
|
|
func ValidateNodeIdentifier(identifier string) error {
|
|
if identifier == "" {
|
|
return fmt.Errorf("node identifier is required")
|
|
}
|
|
if len(identifier) > maxNodeIdentifierLength {
|
|
return fmt.Errorf("node identifier must be %d characters or less", maxNodeIdentifierLength)
|
|
}
|
|
// Basic check for path traversal
|
|
if containsPathTraversal(identifier) {
|
|
return fmt.Errorf("invalid node identifier: contains invalid characters")
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// containsPathTraversal checks if a string contains path traversal patterns.
|
|
func containsPathTraversal(s string) bool {
|
|
return strings.ContainsAny(s, "/\\") || strings.Contains(s, "..") || strings.ContainsRune(s, '\x00')
|
|
}
|