From 47538884029c6343d0849a8f7046f1f6380f510d Mon Sep 17 00:00:00 2001 From: AJ ONeal Date: Mon, 20 Apr 2026 16:53:17 -0600 Subject: [PATCH] refactor(geoip): ParseConf takes a string, not a file path The old ParseConf opened the file itself, which the name did not convey. Now it parses the config text directly, matching encoding/json.Unmarshal-style conventions: callers read the file (or source the string however they like) and pass it in. Also introduce errors.ErrMissingCredentials for the credential-missing case so callers can branch on it. --- cmd/check-ip/main.go | 6 +++++- net/geoip/cmd/geoip-update/main.go | 7 ++++++- net/geoip/conf.go | 23 ++++++++++------------- net/geoip/geoip_integration_test.go | 4 ++-- 4 files changed, 23 insertions(+), 17 deletions(-) diff --git a/cmd/check-ip/main.go b/cmd/check-ip/main.go index c8a9b57..f75b5e5 100644 --- a/cmd/check-ip/main.go +++ b/cmd/check-ip/main.go @@ -104,7 +104,11 @@ func main() { } } if cfg.GeoIPConfPath != "" { - conf, err := geoip.ParseConf(cfg.GeoIPConfPath) + data, err := os.ReadFile(cfg.GeoIPConfPath) + if err != nil { + log.Fatalf("geoip-conf: %v", err) + } + conf, err := geoip.ParseConf(string(data)) if err != nil { log.Fatalf("geoip-conf: %v", err) } diff --git a/net/geoip/cmd/geoip-update/main.go b/net/geoip/cmd/geoip-update/main.go index 5d3fae2..f4617c2 100644 --- a/net/geoip/cmd/geoip-update/main.go +++ b/net/geoip/cmd/geoip-update/main.go @@ -17,7 +17,12 @@ func main() { freshDays := flag.Int("fresh-days", 3, "skip download if file is younger than N days") flag.Parse() - cfg, err := geoip.ParseConf(*configPath) + data, err := os.ReadFile(*configPath) + if err != nil { + fmt.Fprintf(os.Stderr, "error: %v\n", err) + os.Exit(1) + } + cfg, err := geoip.ParseConf(string(data)) if err != nil { fmt.Fprintf(os.Stderr, "error: %v\n", err) os.Exit(1) diff --git a/net/geoip/conf.go b/net/geoip/conf.go index 7c1aaf0..581612b 100644 --- a/net/geoip/conf.go +++ b/net/geoip/conf.go @@ -2,8 +2,7 @@ package geoip import ( "bufio" - "fmt" - "os" + "errors" "strings" ) @@ -15,18 +14,16 @@ type Conf struct { DatabaseDirectory string } -// ParseConf reads a geoipupdate-style config file (whitespace-separated -// key/value pairs, # comments). Compatible with GeoIP.conf files used by -// the official geoipupdate tool. -func ParseConf(path string) (*Conf, error) { - f, err := os.Open(path) - if err != nil { - return nil, err - } - defer f.Close() +// ErrMissingCredentials is returned by ParseConf when AccountID or LicenseKey +// is absent from the input. +var ErrMissingCredentials = errors.New("AccountID and LicenseKey are required") +// ParseConf parses a geoipupdate-style config (whitespace-separated key/value +// pairs, # comments). Compatible with GeoIP.conf files used by the official +// geoipupdate tool. +func ParseConf(s string) (*Conf, error) { kv := make(map[string]string) - scanner := bufio.NewScanner(f) + scanner := bufio.NewScanner(strings.NewReader(s)) for scanner.Scan() { line := strings.TrimSpace(scanner.Text()) if line == "" || strings.HasPrefix(line, "#") { @@ -45,7 +42,7 @@ func ParseConf(path string) (*Conf, error) { DatabaseDirectory: kv["DatabaseDirectory"], } if c.AccountID == "" || c.LicenseKey == "" { - return nil, fmt.Errorf("AccountID and LicenseKey are required in %s", path) + return nil, ErrMissingCredentials } if ids := kv["EditionIDs"]; ids != "" { c.EditionIDs = strings.Fields(ids) diff --git a/net/geoip/geoip_integration_test.go b/net/geoip/geoip_integration_test.go index 8db9e6d..b9b90d6 100644 --- a/net/geoip/geoip_integration_test.go +++ b/net/geoip/geoip_integration_test.go @@ -31,8 +31,8 @@ func geoipConf(t *testing.T) *geoip.Conf { dir, _ := filepath.Abs(".") for { p := filepath.Join(dir, "GeoIP.conf") - if _, err := os.Stat(p); err == nil { - cfg, err := geoip.ParseConf(p) + if data, err := os.ReadFile(p); err == nil { + cfg, err := geoip.ParseConf(string(data)) if err != nil { t.Fatalf("GeoIP.conf: %v", err) }