111 lines
3.1 KiB
Go
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
|
|
}
|