mirror of
https://github.com/qdm12/gluetun.git
synced 2026-08-11 14:52:56 +02:00
expressvpn wip
This commit is contained in:
@@ -0,0 +1,146 @@
|
||||
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
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user