Files
helix-proxy/internal/store/source_validate.go
T
s1d3sw1ped 1cc94f2c99
Format / gofmt (push) Failing after 27s
CI / Build (push) Successful in 51s
CI / Go Tests (push) Failing after 21s
initial commit
2026-06-06 07:54:44 -05:00

111 lines
3.1 KiB
Go

package store
import (
"errors"
"fmt"
"strings"
"helix-proxy/internal/models"
)
var (
ErrDuplicateProxySource = errors.New("duplicate proxy host source domain")
ErrDuplicateRedirectionSource = errors.New("duplicate redirection host source domain")
ErrDuplicateDeadSource = errors.New("duplicate dead host source domain")
ErrDuplicateStreamPort = errors.New("duplicate stream incoming port")
)
func IsConflictError(err error) bool {
return errors.Is(err, ErrDuplicateProxySource) ||
errors.Is(err, ErrDuplicateRedirectionSource) ||
errors.Is(err, ErrDuplicateDeadSource) ||
errors.Is(err, ErrDuplicateStreamPort)
}
type domainRecord struct {
ID int
DomainNames []string
}
func normalizeSourceDomain(d string) (normalized, display string, ok bool) {
display = strings.TrimSpace(d)
if display == "" {
return "", "", false
}
return strings.ToLower(display), display, true
}
func validateUniqueDomains(domainNames []string, selfID int, existing []domainRecord, errSentinel error) error {
own := make(map[string]string)
for _, d := range domainNames {
norm, display, ok := normalizeSourceDomain(d)
if !ok {
continue
}
if prev, dup := own[norm]; dup {
return fmt.Errorf("%w: duplicate source domain: %s", errSentinel, prev)
}
own[norm] = display
}
used := make(map[string]struct{})
for _, rec := range existing {
if rec.ID == selfID {
continue
}
for _, d := range rec.DomainNames {
norm, _, ok := normalizeSourceDomain(d)
if !ok {
continue
}
used[norm] = struct{}{}
}
}
for norm, display := range own {
if _, conflict := used[norm]; conflict {
return fmt.Errorf("%w: source domain already in use: %s", errSentinel, display)
}
}
return nil
}
func validateProxyHostSources(hosts []models.ProxyHost, h models.ProxyHost) error {
existing := make([]domainRecord, len(hosts))
for i, host := range hosts {
existing[i] = domainRecord{ID: host.ID, DomainNames: host.DomainNames}
}
return validateUniqueDomains(h.DomainNames, h.ID, existing, ErrDuplicateProxySource)
}
func validateRedirectionHostSources(hosts []models.RedirectionHost, h models.RedirectionHost) error {
existing := make([]domainRecord, len(hosts))
for i, host := range hosts {
existing[i] = domainRecord{ID: host.ID, DomainNames: host.DomainNames}
}
return validateUniqueDomains(h.DomainNames, h.ID, existing, ErrDuplicateRedirectionSource)
}
func validateDeadHostSources(hosts []models.DeadHost, h models.DeadHost) error {
existing := make([]domainRecord, len(hosts))
for i, host := range hosts {
existing[i] = domainRecord{ID: host.ID, DomainNames: host.DomainNames}
}
return validateUniqueDomains(h.DomainNames, h.ID, existing, ErrDuplicateDeadSource)
}
func validateStreamIncomingPort(st models.Stream, streams []models.Stream) error {
if st.IncomingPort <= 0 {
return nil
}
for _, other := range streams {
if other.ID == st.ID {
continue
}
if other.IncomingPort == st.IncomingPort {
return fmt.Errorf("%w: incoming port already in use: %d", ErrDuplicateStreamPort, st.IncomingPort)
}
}
return nil
}