mirror of
https://github.com/qdm12/gluetun.git
synced 2026-08-11 14:52:56 +02:00
147 lines
4.5 KiB
Go
147 lines
4.5 KiB
Go
package updater
|
|
|
|
import (
|
|
"fmt"
|
|
"strings"
|
|
|
|
"github.com/qdm12/gluetun/internal/models"
|
|
)
|
|
|
|
// generateCandidateHostnames generates multiple hostname candidates for a given location
|
|
// by trying different slug variations, number suffixes, and country aliases.
|
|
func generateCandidateHostnames(server models.Server) (hostnames []string, err error) {
|
|
country := strings.ToLower(server.Country)
|
|
city := strings.ToLower(server.City)
|
|
|
|
if strings.Contains(country, " (via ") {
|
|
destinationEndIndex := strings.Index(country, " (via ")
|
|
destination := strings.TrimSpace(country[:destinationEndIndex])
|
|
destination = strings.ReplaceAll(destination, " ", "")
|
|
|
|
sourceEndIndex := strings.Index(country[destinationEndIndex:], ")")
|
|
if sourceEndIndex == -1 {
|
|
return nil, fmt.Errorf("invalid location format, missing closing parenthesis for source: %q", country)
|
|
}
|
|
source := strings.TrimSpace(country[destinationEndIndex+len(" (via ") : destinationEndIndex+sourceEndIndex])
|
|
source = strings.ReplaceAll(source, " ", "")
|
|
|
|
sourceAliases := countryNameToAliases(source)
|
|
sources := make([]string, 0, 1+len(sourceAliases))
|
|
sources = append(sources, source)
|
|
sources = append(sources, sourceAliases...)
|
|
destinationAliases := countryNameToAliases(destination)
|
|
destinations := make([]string, 0, 1+len(destinationAliases))
|
|
destinations = append(destinations, destination)
|
|
destinations = append(destinations, destinationAliases...)
|
|
|
|
slugs := make([]string, 0, (1+len(sourceAliases))*(1+len(destinationAliases)))
|
|
for _, destination := range destinations {
|
|
for _, source := range sources {
|
|
slugs = append(slugs, destination+"-"+source)
|
|
}
|
|
}
|
|
|
|
if city != "" {
|
|
return nil, fmt.Errorf("city %q should be empty for multi-hop country: %s", city, country)
|
|
}
|
|
|
|
return makeNumberedCandidates(slugs, server.Number), nil
|
|
}
|
|
|
|
countrySlug := strings.ReplaceAll(strings.TrimSpace(country), " ", "")
|
|
countrySlugAliases := countryNameToAliases(countrySlug)
|
|
countrySlugs := make([]string, 0, 1+len(countrySlugAliases))
|
|
countrySlugs = append(countrySlugs, countrySlug)
|
|
countrySlugs = append(countrySlugs, countrySlugAliases...)
|
|
|
|
var citySlugs []string
|
|
if city != "" {
|
|
if strings.Contains(city, " ") {
|
|
citySlugs = append(citySlugs, strings.ReplaceAll(city, " ", ""))
|
|
citySlugs = append(citySlugs, strings.ReplaceAll(city, " ", "-"))
|
|
} else {
|
|
citySlugs = append(citySlugs, city)
|
|
}
|
|
}
|
|
|
|
var slugs []string
|
|
if len(citySlugs) == 0 {
|
|
slugs = countrySlugs
|
|
} else {
|
|
slugs = make([]string, 0, len(countrySlugs)*len(citySlugs))
|
|
for _, countrySlug := range countrySlugs {
|
|
for _, citySlug := range citySlugs {
|
|
slugs = append(slugs, countrySlug+"-"+citySlug)
|
|
}
|
|
}
|
|
}
|
|
|
|
return makeNumberedCandidates(slugs, server.Number), nil
|
|
}
|
|
|
|
func makeNumberedCandidates(baseSlugs []string, serverNumber uint16) (candidates []string) {
|
|
numbersToTry := []uint16{1, 2, 3, 4, 5}
|
|
if serverNumber > 0 {
|
|
numbersToTry = []uint16{serverNumber}
|
|
}
|
|
const candidateVariationsPerNumber = 2 // slugN and slug-N
|
|
candidateVariationsPerBase := 1 + len(numbersToTry)*candidateVariationsPerNumber // base + (slugN and slug-N for each number)
|
|
candidates = make([]string, 0, len(baseSlugs)*candidateVariationsPerBase)
|
|
for _, base := range baseSlugs {
|
|
candidates = append(candidates, base+hostnameSuffix)
|
|
for _, number := range numbersToTry {
|
|
candidates = append(candidates,
|
|
base+fmt.Sprintf("%d-ca-version-2.expressnetw.com", number),
|
|
base+fmt.Sprintf("-%d-ca-version-2.expressnetw.com", number))
|
|
}
|
|
}
|
|
return candidates
|
|
}
|
|
|
|
// hostnameSuffix is appended to all ExpressVPN hostnames.
|
|
const hostnameSuffix = "-ca-version-2.expressnetw.com"
|
|
|
|
// countryNameToAliases maps common country names to alternative names used in hostnames.
|
|
func countryNameToAliases(country string) (aliases []string) {
|
|
switch country {
|
|
case "usa":
|
|
return []string{"us"}
|
|
case "uk":
|
|
return []string{"gb"}
|
|
case "netherlands":
|
|
return []string{"nl"}
|
|
case "switzerland":
|
|
return []string{"ch"}
|
|
case "japan":
|
|
return []string{"jp"}
|
|
case "sweden":
|
|
return []string{"se"}
|
|
case "norway":
|
|
return []string{"no"}
|
|
case "denmark":
|
|
return []string{"dk"}
|
|
case "finland":
|
|
return []string{"fi"}
|
|
case "portugal":
|
|
return []string{"pt"}
|
|
case "spain":
|
|
return []string{"es"}
|
|
case "germany":
|
|
return []string{"de"}
|
|
case "italy":
|
|
return []string{"it"}
|
|
case "australia":
|
|
return []string{"au"}
|
|
case "singapore":
|
|
return []string{"sg"}
|
|
case "taiwan":
|
|
return []string{"tw"}
|
|
case "southkorea":
|
|
return []string{"kr"}
|
|
case "northmacedonia":
|
|
return []string{"macedonia"}
|
|
default:
|
|
return nil
|
|
}
|
|
}
|