Files
techircd/validation.go

135 lines
3.2 KiB
Go

package main
import (
"fmt"
"strings"
)
// ValidateConfig performs comprehensive validation of the server configuration
func (c *Config) Validate() error {
// Validate server settings
if c.Server.Name == "" {
return fmt.Errorf("server name cannot be empty")
}
if c.Server.Network == "" {
return fmt.Errorf("network name cannot be empty")
}
if c.Server.Listen.Host == "" {
c.Server.Listen.Host = "localhost" // Default fallback
}
if c.Server.Listen.Port <= 0 || c.Server.Listen.Port > 65535 {
return fmt.Errorf("invalid port number: %d", c.Server.Listen.Port)
}
if c.Server.Listen.EnableSSL && (c.Server.Listen.SSLPort <= 0 || c.Server.Listen.SSLPort > 65535) {
return fmt.Errorf("invalid SSL port number: %d", c.Server.Listen.SSLPort)
}
// Validate limits
if c.Limits.MaxClients <= 0 {
c.Limits.MaxClients = 1000 // Default
}
if c.Limits.MaxChannels <= 0 {
c.Limits.MaxChannels = 100 // Default
}
if c.Limits.MaxNickLength <= 0 || c.Limits.MaxNickLength > 50 {
c.Limits.MaxNickLength = 30 // Default
}
if c.Limits.PingTimeout <= 0 {
c.Limits.PingTimeout = 300 // Default 5 minutes
}
if c.Limits.FloodLines <= 0 {
c.Limits.FloodLines = 10 // Default
}
if c.Limits.FloodSeconds <= 0 {
c.Limits.FloodSeconds = 60 // Default
}
// Validate channels
for _, channelName := range c.Channels.AutoJoin {
if !isChannelName(channelName) {
return fmt.Errorf("invalid channel name in auto_join: %s", channelName)
}
}
// Validate default modes
validChannelModes := "mntisp"
for _, mode := range c.Channels.DefaultModes {
if mode != '+' && !strings.ContainsRune(validChannelModes, mode) {
return fmt.Errorf("invalid default channel mode: %c", mode)
}
}
// Validate founder mode
validFounderModes := []string{"q", "a", "o", "h", "v"}
foundValidMode := false
for _, validMode := range validFounderModes {
if c.Channels.FounderMode == validMode {
foundValidMode = true
break
}
}
if !foundValidMode {
return fmt.Errorf("invalid founder_mode '%s', must be one of: q (owner), a (admin), o (operator), h (halfop), v (voice)", c.Channels.FounderMode)
}
// Validate operators
for i, oper := range c.Opers {
if oper.Name == "" {
return fmt.Errorf("operator %d: name cannot be empty", i)
}
if oper.Password == "" {
return fmt.Errorf("operator %s: password cannot be empty", oper.Name)
}
if oper.Host == "" {
return fmt.Errorf("operator %s: host cannot be empty", oper.Name)
}
}
return nil
}
// SanitizeConfig applies safe defaults and sanitizes configuration values
func (c *Config) SanitizeConfig() {
// Ensure reasonable limits
if c.Limits.MaxClients > 10000 {
c.Limits.MaxClients = 10000
}
if c.Limits.MaxChannels > 1000 {
c.Limits.MaxChannels = 1000
}
// Set default founder mode if empty or invalid
if c.Channels.FounderMode == "" {
c.Channels.FounderMode = "o" // Default to operator
}
// Ensure reasonable string lengths
if c.Limits.MaxTopicLength > 2048 {
c.Limits.MaxTopicLength = 2048
}
if c.Limits.MaxKickLength > 2048 {
c.Limits.MaxKickLength = 2048
}
// Ensure MOTD isn't too long
if len(c.MOTD) > 50 {
c.MOTD = c.MOTD[:50]
}
// Sanitize channel modes
if c.Channels.DefaultModes == "" {
c.Channels.DefaultModes = "+nt"
}
}