package license import ( "fmt" "regexp" "strings" ) // Ein DNS-Label: 1–63 Zeichen, a–z, 0–9 und Bindestrich, nicht am Rand. // Internationalisierte Domains werden in Punycode (xn--…) angegeben. var labelRe = regexp.MustCompile(`^[a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?$`) // splitHost normalisiert host (klein, ohne Punkt am Ende) und prüft, dass er // aus mindestens zwei gültigen Labels besteht. func splitHost(host string) (string, bool) { h := strings.TrimSuffix(strings.ToLower(strings.TrimSpace(host)), ".") if len(h) > 253 { return "", false } labels := strings.Split(h, ".") if len(labels) < 2 { return "", false } for _, l := range labels { if !labelRe.MatchString(l) { return "", false } } return h, true } // normalizePattern prüft einen Eintrag aus allowed_domains: entweder eine // Domain ("shop.de") oder eine Wildcard ganz vorne ("*.firma.de"). Eine // Wildcard direkt auf einer TLD ("*.de") ist nicht erlaubt. func normalizePattern(p string) (string, error) { p = strings.TrimSpace(p) rest, wildcard := strings.CutPrefix(p, "*.") h, ok := splitHost(rest) if !ok { return "", fmt.Errorf("%w: ungültiges Domain-Muster %q", ErrInvalid, p) } if wildcard { return "*." + h, nil } return h, nil } // AllowsDomain meldet, ob host durch allowed_domains gedeckt ist: // - "shop.de" deckt genau shop.de (keine Subdomains), // - "*.firma.de" deckt jede Subdomain beliebiger Tiefe, nicht firma.de selbst. // // Groß-/Kleinschreibung und ein Punkt am Ende werden ignoriert. func (l License) AllowsDomain(host string) bool { h, ok := splitHost(host) if !ok { return false } for _, p := range l.AllowedDomains { if base, wildcard := strings.CutPrefix(p, "*."); wildcard { if strings.HasSuffix(h, "."+base) { return true } } else if h == p { return true } } return false } // NormalizeDomain prüft und normalisiert einen Eintrag für allowed_domains // (klein, ohne Punkt am Ende; Wildcard nur vorne, nicht auf einer TLD). func NormalizeDomain(p string) (string, error) { return normalizePattern(p) }