From c195bae4fbc40fd1b3671d982fa3284da8eb0d89 Mon Sep 17 00:00:00 2001 From: Johann Richard Date: Fri, 9 Feb 2018 20:41:30 +0100 Subject: [PATCH] Patch for ISO and Map display (#45) --- README.md | 4 ++++ api/api.go | 36 ++++++++++++++++++++++++++---------- api/api_test.go | 20 +++++++++++--------- api/oracle.go | 32 ++++++++++++++++++++++++++++---- index.html | 16 ++++++++++++++-- 5 files changed, 83 insertions(+), 25 deletions(-) diff --git a/README.md b/README.md index 1a227f1..1a68089 100644 --- a/README.md +++ b/README.md @@ -32,6 +32,9 @@ Country and city lookup: $ http ifconfig.co/country Elbonia +$ http ifconfig.co/country-iso +EB + $ http ifconfig.co/city Bornyasherk ``` @@ -43,6 +46,7 @@ $ http --json ifconfig.co { "city": "Bornyasherk", "country": "Elbonia", + "country_iso": "EB", "ip": "127.0.0.1", "ip_decimal": 2130706433 } diff --git a/api/api.go b/api/api.go index ca3ce19..fbddf3f 100644 --- a/api/api.go +++ b/api/api.go @@ -31,11 +31,12 @@ type API struct { } type Response struct { - IP net.IP `json:"ip"` - IPDecimal *big.Int `json:"ip_decimal"` - Country string `json:"country,omitempty"` - City string `json:"city,omitempty"` - Hostname string `json:"hostname,omitempty"` + IP net.IP `json:"ip"` + IPDecimal *big.Int `json:"ip_decimal"` + Country string `json:"country,omitempty"` + CountryISO string `json:"country_iso,omitempty"` + City string `json:"city,omitempty"` + Hostname string `json:"hostname,omitempty"` } type PortResponse struct { @@ -84,6 +85,10 @@ func (a *API) newResponse(r *http.Request) (Response, error) { if err != nil { a.log.Debug(err) } + countryISO, err := a.oracle.LookupCountryISO(ip) + if err != nil { + a.log.Debug(err) + } city, err := a.oracle.LookupCity(ip) if err != nil { a.log.Debug(err) @@ -93,11 +98,12 @@ func (a *API) newResponse(r *http.Request) (Response, error) { a.log.Debug(err) } return Response{ - IP: ip, - IPDecimal: ipDecimal, - Country: country, - City: city, - Hostname: strings.Join(hostnames, " "), + IP: ip, + IPDecimal: ipDecimal, + Country: country, + CountryISO: countryISO, + City: city, + Hostname: strings.Join(hostnames, " "), }, nil } @@ -140,6 +146,15 @@ func (a *API) CLICountryHandler(w http.ResponseWriter, r *http.Request) *appErro return nil } +func (a *API) CLICountryISOHandler(w http.ResponseWriter, r *http.Request) *appError { + response, err := a.newResponse(r) + if err != nil { + return internalServerError(err) + } + fmt.Fprintln(w, response.CountryISO) + return nil +} + func (a *API) CLICityHandler(w http.ResponseWriter, r *http.Request) *appError { response, err := a.newResponse(r) if err != nil { @@ -250,6 +265,7 @@ func (a *API) Router() http.Handler { r.Handle("/", appHandler(a.CLIHandler)).Methods("GET").Headers("Accept", textMediaType) r.Handle("/ip", appHandler(a.CLIHandler)).Methods("GET") r.Handle("/country", appHandler(a.CLICountryHandler)).Methods("GET") + r.Handle("/country-iso", appHandler(a.CLICountryISOHandler)).Methods("GET") r.Handle("/city", appHandler(a.CLICityHandler)).Methods("GET") // Browser diff --git a/api/api_test.go b/api/api_test.go index fec6236..a4b0c61 100644 --- a/api/api_test.go +++ b/api/api_test.go @@ -12,14 +12,15 @@ import ( type mockOracle struct{} -func (r *mockOracle) LookupAddr(net.IP) ([]string, error) { return []string{"localhost"}, nil } -func (r *mockOracle) LookupCountry(net.IP) (string, error) { return "Elbonia", nil } -func (r *mockOracle) LookupCity(net.IP) (string, error) { return "Bornyasherk", nil } -func (r *mockOracle) LookupPort(net.IP, uint64) error { return nil } -func (r *mockOracle) IsLookupAddrEnabled() bool { return true } -func (r *mockOracle) IsLookupCountryEnabled() bool { return true } -func (r *mockOracle) IsLookupCityEnabled() bool { return true } -func (r *mockOracle) IsLookupPortEnabled() bool { return true } +func (r *mockOracle) LookupAddr(net.IP) ([]string, error) { return []string{"localhost"}, nil } +func (r *mockOracle) LookupCountry(net.IP) (string, error) { return "Elbonia", nil } +func (r *mockOracle) LookupCountryISO(net.IP) (string, error) { return "EB", nil } +func (r *mockOracle) LookupCity(net.IP) (string, error) { return "Bornyasherk", nil } +func (r *mockOracle) LookupPort(net.IP, uint64) error { return nil } +func (r *mockOracle) IsLookupAddrEnabled() bool { return true } +func (r *mockOracle) IsLookupCountryEnabled() bool { return true } +func (r *mockOracle) IsLookupCityEnabled() bool { return true } +func (r *mockOracle) IsLookupPortEnabled() bool { return true } func newTestAPI() *API { return &API{oracle: &mockOracle{}} @@ -61,6 +62,7 @@ func TestCLIHandlers(t *testing.T) { {s.URL, "127.0.0.1\n", 200, "foo/bar", textMediaType}, {s.URL + "/ip", "127.0.0.1\n", 200, "", ""}, {s.URL + "/country", "Elbonia\n", 200, "", ""}, + {s.URL + "/country-iso", "EB\n", 200, "", ""}, {s.URL + "/city", "Bornyasherk\n", 200, "", ""}, {s.URL + "/foo", "404 page not found", 404, "", ""}, } @@ -88,7 +90,7 @@ func TestJSONHandlers(t *testing.T) { out string status int }{ - {s.URL, `{"ip":"127.0.0.1","ip_decimal":2130706433,"country":"Elbonia","city":"Bornyasherk","hostname":"localhost"}`, 200}, + {s.URL, `{"ip":"127.0.0.1","ip_decimal":2130706433,"country":"Elbonia","country_iso":"EB","city":"Bornyasherk","hostname":"localhost"}`, 200}, {s.URL + "/port/foo", `{"error":"404 page not found"}`, 404}, {s.URL + "/port/0", `{"error":"Invalid port: 0"}`, 400}, {s.URL + "/port/65356", `{"error":"Invalid port: 65356"}`, 400}, diff --git a/api/oracle.go b/api/oracle.go index 7a750bc..1030241 100644 --- a/api/oracle.go +++ b/api/oracle.go @@ -12,6 +12,7 @@ import ( type Oracle interface { LookupAddr(net.IP) ([]string, error) LookupCountry(net.IP) (string, error) + LookupCountryISO(net.IP) (string, error) LookupCity(net.IP) (string, error) LookupPort(net.IP, uint64) error IsLookupAddrEnabled() bool @@ -23,6 +24,7 @@ type Oracle interface { type DefaultOracle struct { lookupAddr func(net.IP) ([]string, error) lookupCountry func(net.IP) (string, error) + lookupCountryISO func(net.IP) (string, error) lookupCity func(net.IP) (string, error) lookupPort func(net.IP, uint64) error lookupAddrEnabled bool @@ -33,10 +35,11 @@ type DefaultOracle struct { func NewOracle() *DefaultOracle { return &DefaultOracle{ - lookupAddr: func(net.IP) ([]string, error) { return nil, nil }, - lookupCountry: func(net.IP) (string, error) { return "", nil }, - lookupCity: func(net.IP) (string, error) { return "", nil }, - lookupPort: func(net.IP, uint64) error { return nil }, + lookupAddr: func(net.IP) ([]string, error) { return nil, nil }, + lookupCountry: func(net.IP) (string, error) { return "", nil }, + lookupCountryISO: func(net.IP) (string, error) { return "", nil }, + lookupCity: func(net.IP) (string, error) { return "", nil }, + lookupPort: func(net.IP, uint64) error { return nil }, } } @@ -48,6 +51,10 @@ func (r *DefaultOracle) LookupCountry(ip net.IP) (string, error) { return r.lookupCountry(ip) } +func (r *DefaultOracle) LookupCountryISO(ip net.IP) (string, error) { + return r.lookupCountryISO(ip) +} + func (r *DefaultOracle) LookupCity(ip net.IP) (string, error) { return r.lookupCity(ip) } @@ -69,6 +76,9 @@ func (r *DefaultOracle) EnableLookupCountry(filepath string) error { r.lookupCountry = func(ip net.IP) (string, error) { return lookupCountry(db, ip) } + r.lookupCountryISO = func(ip net.IP) (string, error) { + return lookupCountryISO(db, ip) + } r.lookupCountryEnabled = true return nil } @@ -127,6 +137,20 @@ func lookupCountry(db *geoip2.Reader, ip net.IP) (string, error) { return "Unknown", fmt.Errorf("could not determine country for IP: %s", ip) } +func lookupCountryISO(db *geoip2.Reader, ip net.IP) (string, error) { + record, err := db.City(ip) + if err != nil { + return "", err + } + if record.Country.IsoCode != "" { + return record.Country.IsoCode, nil + } + if record.RegisteredCountry.IsoCode != "" { + return record.RegisteredCountry.IsoCode, nil + } + return "Unknown", fmt.Errorf("could not determine country ISO Code for IP: %s", ip) +} + func lookupCity(db *geoip2.Reader, ip net.IP) (string, error) { record, err := db.City(ip) if err != nil { diff --git a/index.html b/index.html index 81052e5..1877217 100644 --- a/index.html +++ b/index.html @@ -63,6 +63,10 @@ $ bat -print=b {{ .Host }}/ip
 $ http {{ .Host }}/country
 {{ .Country }}
+

Short country code (ISO 3166-1 alpha-2) lookup:

+
+$ http {{ .Host }}/country-iso
+{{ .CountryISO }}
{{ end }} {{ if .IsLookupCityEnabled }}

City lookup:

@@ -76,8 +80,9 @@ $ http {{ .Host }}/city
 $ http {{ .Host }}/json
 { {{ if .IsLookupCityEnabled }}
-    "city": "{{ .City }}",{{ end }}{{ if .IsLookupCountryEnabled }}
-    "country": "{{ .Country }}",{{ end }}{{ if .IsLookupAddrEnabled }}
+    "city": "{{ .City }}",
+    "country": "{{ .Country }}",
+    "country_iso": "{{ .CountryISO }}",{{ end }}{{ if .IsLookupAddrEnabled }}
     "hostname": "{{ .Hostname }}",{{ end }}
     "ip": "{{ .IP }}",
     "ip_decimal": {{ .IPDecimal }}
@@ -100,6 +105,13 @@ $ http {{ .Host }}/port/8080
 }
{{ end }} +{{ if .IsLookupCountryEnabled }}{{ if ne .Country "Unknown"}}{{ if .IsLookupCityEnabled }}{{ if ne .City "Unknown"}} +
+

Map

+

+

+{{ end }}{{ end }}{{ end }}{{ end }} +

FAQ

How do I force IPv4 or IPv6 lookup?