package config import ( "crypto/ed25519" "encoding/hex" "fmt" "net" "strconv" "strings" ) type MailIngress struct { ID string `json:"id"` Enabled bool `json:"enabled"` Address string `json:"address"` Username string `json:"username"` Password string `json:"password"` Folder string `json:"folder"` Channel string `json:"channel"` PollSeconds int `json:"poll_seconds"` From []string `json:"from,omitempty"` To []string `json:"to,omitempty"` ImportExisting bool `json:"import_existing"` } type DiscordIngress struct { Enabled bool `json:"enabled"` PublicKey string `json:"public_key"` ApplicationID string `json:"application_id"` GuildIDs []string `json:"guild_ids"` ChannelIDs []string `json:"channel_ids"` Command string `json:"command"` } func validateIngress(c IngressConfig) error { seen := map[string]bool{} for _, m := range c.Mail { if m.ID == "" || seen[m.ID] { return fmt.Errorf("Mail-Eingang benötigt eindeutige ID") } seen[m.ID] = true if !m.Enabled { continue } host, port, err := net.SplitHostPort(m.Address) p, _ := strconv.Atoi(port) if err != nil || host == "" || p < 1 || p > 65535 || m.Username == "" || m.Password == "" || m.Channel == "" { return fmt.Errorf("Mail-Eingang %q: Adresse (Host:Port), Benutzer, Passwort und Kanal erforderlich", m.ID) } if m.PollSeconds < 10 || m.PollSeconds > 86400 { return fmt.Errorf("Mail-Abfrageintervall muss 10..86400 Sekunden sein") } } d := c.Discord if d.Enabled { for _, id := range append(append([]string{}, d.GuildIDs...), d.ChannelIDs...) { if strings.TrimSpace(id) == "" { return fmt.Errorf("Discord-Allowlists dürfen keine leeren IDs enthalten") } } key, err := hex.DecodeString(d.PublicKey) if err != nil || len(key) != ed25519.PublicKeySize || d.ApplicationID == "" || d.Command == "" || len(d.GuildIDs) == 0 || len(d.ChannelIDs) == 0 { return fmt.Errorf("Discord benötigt Public Key, Application-ID, Command und Guild-/Channel-Allowlist") } } return nil }