Files
elmprodvpn/selective-vpn-api/app/vpn_locations_selection.go

165 lines
3.8 KiB
Go

package app
import (
"fmt"
"strings"
)
type vpnLocationChoice struct {
ISO string
Label string
RawTarget string
Name string
Connect string
}
func resolveVPNLocationSelection(
reqTarget string,
reqISO string,
reqLabel string,
locs []vpnLocationItem,
) (target string, iso string, label string, validated bool, err error) {
targetReq := strings.TrimSpace(reqTarget)
isoReq := strings.ToUpper(strings.TrimSpace(reqISO))
labelReq := strings.TrimSpace(reqLabel)
choices := buildVPNLocationChoices(locs)
if len(choices) == 0 {
if isISO2(isoReq) {
return isoReq, isoReq, "", false, nil
}
if isISO2(targetReq) {
t := strings.ToUpper(strings.TrimSpace(targetReq))
return t, t, "", false, nil
}
return "", "", "", false, fmt.Errorf("location catalog unavailable; use ISO code")
}
findBy := func(pred func(vpnLocationChoice) bool) *vpnLocationChoice {
for i := range choices {
if pred(choices[i]) {
return &choices[i]
}
}
return nil
}
var chosen *vpnLocationChoice
if labelReq != "" {
chosen = findBy(func(it vpnLocationChoice) bool {
return equalsFoldTrim(labelReq, it.Label)
})
}
if chosen == nil && targetReq != "" {
chosen = findBy(func(it vpnLocationChoice) bool {
return equalsFoldTrim(targetReq, it.Connect) ||
equalsFoldTrim(targetReq, it.Name) ||
equalsFoldTrim(targetReq, it.RawTarget) ||
equalsFoldTrim(targetReq, it.Label)
})
}
if chosen == nil && isISO2(isoReq) {
chosen = findBy(func(it vpnLocationChoice) bool {
return it.ISO == isoReq
})
}
if chosen == nil && isISO2(targetReq) {
isoByTarget := strings.ToUpper(strings.TrimSpace(targetReq))
chosen = findBy(func(it vpnLocationChoice) bool {
return it.ISO == isoByTarget
})
}
if chosen == nil {
return "", "", "", false, fmt.Errorf("location not recognized; current connection kept")
}
connectArg := strings.TrimSpace(chosen.Connect)
if connectArg == "" {
connectArg = chosen.ISO
}
isValidated := true
if targetReq != "" &&
!equalsFoldTrim(targetReq, connectArg) &&
!equalsFoldTrim(targetReq, chosen.ISO) &&
!equalsFoldTrim(targetReq, chosen.Name) &&
!equalsFoldTrim(targetReq, chosen.RawTarget) &&
!equalsFoldTrim(targetReq, chosen.Label) {
isValidated = false
}
return connectArg, chosen.ISO, chosen.Label, isValidated, nil
}
func buildVPNLocationChoices(locs []vpnLocationItem) []vpnLocationChoice {
choices := make([]vpnLocationChoice, 0, len(locs))
namesByISO := map[string][][]string{}
countByISO := map[string]int{}
for _, it := range locs {
iso := strings.ToUpper(strings.TrimSpace(it.ISO))
if !isISO2(iso) {
continue
}
label := strings.TrimSpace(it.Label)
rawTarget := strings.TrimSpace(it.Target)
name := inferVPNLocationTargetFromLabel(label, iso)
if name == "" {
name = rawTarget
}
if name == "" {
name = iso
}
namesByISO[iso] = append(namesByISO[iso], strings.Fields(name))
countByISO[iso]++
choices = append(choices, vpnLocationChoice{
ISO: iso,
Label: label,
RawTarget: rawTarget,
Name: name,
})
}
commonByISO := map[string][]string{}
for iso, names := range namesByISO {
if len(names) < 2 {
continue
}
pfx := commonPrefixTokens(names)
if len(pfx) > 0 {
commonByISO[iso] = pfx
}
}
for i := range choices {
iso := choices[i].ISO
if countByISO[iso] <= 1 {
choices[i].Connect = iso
continue
}
tokens := strings.Fields(choices[i].Name)
pfx := commonByISO[iso]
if len(pfx) > 0 && len(tokens) > len(pfx) {
choices[i].Connect = strings.TrimSpace(strings.Join(tokens[len(pfx):], " "))
} else if choices[i].Name != "" {
choices[i].Connect = choices[i].Name
}
if choices[i].Connect == "" {
choices[i].Connect = iso
}
}
return choices
}
func equalsFoldTrim(a, b string) bool {
return strings.EqualFold(strings.TrimSpace(a), strings.TrimSpace(b))
}