MCPcopy Create free account
hub / github.com/Hidden-Node/GooseRelayVPN-AndroidClient / LoadClient

Function LoadClient

internal/config/client.go:291–416  ·  view source on GitHub ↗

LoadClient reads and validates a client config file.

(path string)

Source from the content-addressed store, hash-verified

289
290// LoadClient reads and validates a client config file.
291func LoadClient(path string) (*Client, error) {
292 b, err := os.ReadFile(path)
293 if err != nil {
294 if errors.Is(err, fs.ErrNotExist) {
295 return nil, fmt.Errorf("config file %q not found.\n Fix: copy the example and edit it:\n cp client_config.example.json %s", path, path)
296 }
297 return nil, fmt.Errorf("cannot read config %q: %w", path, err)
298 }
299
300 var f clientFile
301 if err := json.Unmarshal(b, &f); err != nil {
302 return nil, fmt.Errorf("config %q is not valid JSON: %v\n Common causes: missing comma between fields, trailing comma after the last field, unclosed quote, or a typo in a field name", path, err)
303 }
304
305 listenHost := firstNonEmpty(f.SocksHost, "127.0.0.1")
306 listenPort := firstPositive(f.SocksPort)
307 if listenPort == 0 {
308 listenPort = 1080
309 }
310 if listenPort < 1 || listenPort > 65535 {
311 return nil, fmt.Errorf("socks_port %d is out of range (must be 1-65535)", listenPort)
312 }
313
314 relayURLs := make([]string, 0, len(f.RelayURLs))
315 for _, raw := range f.RelayURLs {
316 normalized, nerr := normalizeRelayURL(raw)
317 if nerr != nil {
318 return nil, nerr
319 }
320 if normalized != "" {
321 relayURLs = append(relayURLs, normalized)
322 }
323 }
324 relayURLs = dedupeStrings(relayURLs)
325
326 key := strings.TrimSpace(f.TunnelKey)
327 if key == "" || key == "REPLACE_WITH_64_HEX_CHARACTER_RANDOM_KEY" {
328 return nil, fmt.Errorf("tunnel_key is empty or still the placeholder text in %s.\n Fix: generate a key with 'openssl rand -hex 32' and paste the 64-character output into the tunnel_key field. The same value must be in server_config.json", path)
329 }
330 if len(key) != 64 {
331 return nil, fmt.Errorf("tunnel_key must be exactly 64 hex characters (got %d) in %s.\n Fix: generate a fresh key with 'openssl rand -hex 32' and paste the full output. Use the SAME value in client_config.json and server_config.json", len(key), path)
332 }
333 raw, err := hex.DecodeString(key)
334 if err != nil || len(raw) != 32 {
335 return nil, fmt.Errorf("tunnel_key in %s contains non-hex characters.\n Valid characters are 0-9 and a-f. Generate a fresh key with 'openssl rand -hex 32' and copy it carefully — no spaces, quotes, or extra newlines", path)
336 }
337
338 useFronting := len(relayURLs) == 0
339 scriptURLs := relayURLs
340 scriptAccounts := make([]string, len(relayURLs)) // direct relay_urls have no account labels
341 googleIP := ""
342 var sniHosts []string
343
344 if useFronting {
345 googleHost := firstNonEmpty(f.GoogleHost, "216.239.38.120")
346 googlePort := 443
347 googleIP = net.JoinHostPort(googleHost, strconv.Itoa(googlePort))
348 sniHosts = parseSNIHosts(f.SNI)

Callers 2

mainFunction · 0.92
StartClientFunction · 0.92

Calls 9

firstNonEmptyFunction · 0.85
firstPositiveFunction · 0.85
normalizeRelayURLFunction · 0.85
dedupeStringsFunction · 0.85
parseSNIHostsFunction · 0.85
parseScriptKeysFunction · 0.85
normalizeDeploymentIDFunction · 0.85
validateDeploymentIDFunction · 0.85
buildScriptURLFunction · 0.85

Tested by

no test coverage detected