package app import ( "encoding/json" "os" "strings" ) func resolveAutoloopLocationSpec(locFile, defaultLoc string) autoloopLocationSpec { raw := "" if data, err := os.ReadFile(locFile); err == nil { for _, ln := range strings.Split(string(data), "\n") { t := strings.TrimSpace(ln) if t != "" && !strings.HasPrefix(t, "#") { raw = t break } } } if raw == "" { raw = strings.TrimSpace(defaultLoc) } raw = strings.TrimSpace(raw) primary := raw iso := "" if p := strings.SplitN(raw, "|", 2); len(p) == 2 { primary = strings.TrimSpace(p[0]) iso = strings.ToUpper(strings.TrimSpace(p[1])) } if primary == "" { primary = strings.TrimSpace(defaultLoc) } if isISO2(primary) { iso = strings.ToUpper(primary) } if iso == "" { if tokens := strings.Fields(primary); len(tokens) > 0 && isISO2(tokens[0]) { iso = strings.ToUpper(tokens[0]) } } if iso == "" { iso = lookupISOFromLocationsCache(primary) } if iso == "" && isISO2(defaultLoc) { iso = strings.ToUpper(strings.TrimSpace(defaultLoc)) } return autoloopLocationSpec{ Primary: primary, ISO: iso, } } func isISO2(v string) bool { s := strings.TrimSpace(v) if len(s) != 2 { return false } for _, ch := range s { if (ch < 'A' || ch > 'Z') && (ch < 'a' || ch > 'z') { return false } } return true } func lookupISOFromLocationsCache(primary string) string { want := strings.ToLower(strings.TrimSpace(primary)) if want == "" { return "" } var disk struct { Locations []struct { ISO string `json:"iso"` Label string `json:"label"` Target string `json:"target"` } `json:"locations"` } data, err := os.ReadFile(vpnLocationsCachePath) if err != nil { return "" } if err := json.Unmarshal(data, &disk); err != nil { return "" } for _, it := range disk.Locations { iso := strings.ToUpper(strings.TrimSpace(it.ISO)) if !isISO2(iso) { continue } target := strings.ToLower(strings.TrimSpace(it.Target)) if target != "" && target == want { return iso } labelNorm := strings.ToLower(strings.TrimSpace(it.Label)) if labelNorm != "" { if inferVPNLocationTargetFromLabel(it.Label, iso) == primary { return iso } if strings.Contains(labelNorm, want) { return iso } } } return "" }