Patch for ISO and Map display (#45)

This commit is contained in:
Johann Richard 2018-02-09 20:41:30 +01:00 committed by Martin Polden
parent 9f839c5f36
commit c195bae4fb
5 changed files with 83 additions and 25 deletions

View File

@ -32,6 +32,9 @@ Country and city lookup:
$ http ifconfig.co/country $ http ifconfig.co/country
Elbonia Elbonia
$ http ifconfig.co/country-iso
EB
$ http ifconfig.co/city $ http ifconfig.co/city
Bornyasherk Bornyasherk
``` ```
@ -43,6 +46,7 @@ $ http --json ifconfig.co
{ {
"city": "Bornyasherk", "city": "Bornyasherk",
"country": "Elbonia", "country": "Elbonia",
"country_iso": "EB",
"ip": "127.0.0.1", "ip": "127.0.0.1",
"ip_decimal": 2130706433 "ip_decimal": 2130706433
} }

View File

@ -31,11 +31,12 @@ type API struct {
} }
type Response struct { type Response struct {
IP net.IP `json:"ip"` IP net.IP `json:"ip"`
IPDecimal *big.Int `json:"ip_decimal"` IPDecimal *big.Int `json:"ip_decimal"`
Country string `json:"country,omitempty"` Country string `json:"country,omitempty"`
City string `json:"city,omitempty"` CountryISO string `json:"country_iso,omitempty"`
Hostname string `json:"hostname,omitempty"` City string `json:"city,omitempty"`
Hostname string `json:"hostname,omitempty"`
} }
type PortResponse struct { type PortResponse struct {
@ -84,6 +85,10 @@ func (a *API) newResponse(r *http.Request) (Response, error) {
if err != nil { if err != nil {
a.log.Debug(err) a.log.Debug(err)
} }
countryISO, err := a.oracle.LookupCountryISO(ip)
if err != nil {
a.log.Debug(err)
}
city, err := a.oracle.LookupCity(ip) city, err := a.oracle.LookupCity(ip)
if err != nil { if err != nil {
a.log.Debug(err) a.log.Debug(err)
@ -93,11 +98,12 @@ func (a *API) newResponse(r *http.Request) (Response, error) {
a.log.Debug(err) a.log.Debug(err)
} }
return Response{ return Response{
IP: ip, IP: ip,
IPDecimal: ipDecimal, IPDecimal: ipDecimal,
Country: country, Country: country,
City: city, CountryISO: countryISO,
Hostname: strings.Join(hostnames, " "), City: city,
Hostname: strings.Join(hostnames, " "),
}, nil }, nil
} }
@ -140,6 +146,15 @@ func (a *API) CLICountryHandler(w http.ResponseWriter, r *http.Request) *appErro
return nil 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 { func (a *API) CLICityHandler(w http.ResponseWriter, r *http.Request) *appError {
response, err := a.newResponse(r) response, err := a.newResponse(r)
if err != nil { 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("/", appHandler(a.CLIHandler)).Methods("GET").Headers("Accept", textMediaType)
r.Handle("/ip", appHandler(a.CLIHandler)).Methods("GET") r.Handle("/ip", appHandler(a.CLIHandler)).Methods("GET")
r.Handle("/country", appHandler(a.CLICountryHandler)).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") r.Handle("/city", appHandler(a.CLICityHandler)).Methods("GET")
// Browser // Browser

View File

@ -12,14 +12,15 @@ import (
type mockOracle struct{} type mockOracle struct{}
func (r *mockOracle) LookupAddr(net.IP) ([]string, error) { return []string{"localhost"}, nil } 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) LookupCountry(net.IP) (string, error) { return "Elbonia", nil }
func (r *mockOracle) LookupCity(net.IP) (string, error) { return "Bornyasherk", nil } func (r *mockOracle) LookupCountryISO(net.IP) (string, error) { return "EB", nil }
func (r *mockOracle) LookupPort(net.IP, uint64) error { return nil } func (r *mockOracle) LookupCity(net.IP) (string, error) { return "Bornyasherk", nil }
func (r *mockOracle) IsLookupAddrEnabled() bool { return true } func (r *mockOracle) LookupPort(net.IP, uint64) error { return nil }
func (r *mockOracle) IsLookupCountryEnabled() bool { return true } func (r *mockOracle) IsLookupAddrEnabled() bool { return true }
func (r *mockOracle) IsLookupCityEnabled() bool { return true } func (r *mockOracle) IsLookupCountryEnabled() bool { return true }
func (r *mockOracle) IsLookupPortEnabled() bool { return true } func (r *mockOracle) IsLookupCityEnabled() bool { return true }
func (r *mockOracle) IsLookupPortEnabled() bool { return true }
func newTestAPI() *API { func newTestAPI() *API {
return &API{oracle: &mockOracle{}} 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, "127.0.0.1\n", 200, "foo/bar", textMediaType},
{s.URL + "/ip", "127.0.0.1\n", 200, "", ""}, {s.URL + "/ip", "127.0.0.1\n", 200, "", ""},
{s.URL + "/country", "Elbonia\n", 200, "", ""}, {s.URL + "/country", "Elbonia\n", 200, "", ""},
{s.URL + "/country-iso", "EB\n", 200, "", ""},
{s.URL + "/city", "Bornyasherk\n", 200, "", ""}, {s.URL + "/city", "Bornyasherk\n", 200, "", ""},
{s.URL + "/foo", "404 page not found", 404, "", ""}, {s.URL + "/foo", "404 page not found", 404, "", ""},
} }
@ -88,7 +90,7 @@ func TestJSONHandlers(t *testing.T) {
out string out string
status int 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/foo", `{"error":"404 page not found"}`, 404},
{s.URL + "/port/0", `{"error":"Invalid port: 0"}`, 400}, {s.URL + "/port/0", `{"error":"Invalid port: 0"}`, 400},
{s.URL + "/port/65356", `{"error":"Invalid port: 65356"}`, 400}, {s.URL + "/port/65356", `{"error":"Invalid port: 65356"}`, 400},

View File

@ -12,6 +12,7 @@ import (
type Oracle interface { type Oracle interface {
LookupAddr(net.IP) ([]string, error) LookupAddr(net.IP) ([]string, error)
LookupCountry(net.IP) (string, error) LookupCountry(net.IP) (string, error)
LookupCountryISO(net.IP) (string, error)
LookupCity(net.IP) (string, error) LookupCity(net.IP) (string, error)
LookupPort(net.IP, uint64) error LookupPort(net.IP, uint64) error
IsLookupAddrEnabled() bool IsLookupAddrEnabled() bool
@ -23,6 +24,7 @@ type Oracle interface {
type DefaultOracle struct { type DefaultOracle struct {
lookupAddr func(net.IP) ([]string, error) lookupAddr func(net.IP) ([]string, error)
lookupCountry func(net.IP) (string, error) lookupCountry func(net.IP) (string, error)
lookupCountryISO func(net.IP) (string, error)
lookupCity func(net.IP) (string, error) lookupCity func(net.IP) (string, error)
lookupPort func(net.IP, uint64) error lookupPort func(net.IP, uint64) error
lookupAddrEnabled bool lookupAddrEnabled bool
@ -33,10 +35,11 @@ type DefaultOracle struct {
func NewOracle() *DefaultOracle { func NewOracle() *DefaultOracle {
return &DefaultOracle{ return &DefaultOracle{
lookupAddr: func(net.IP) ([]string, error) { return nil, nil }, lookupAddr: func(net.IP) ([]string, error) { return nil, nil },
lookupCountry: func(net.IP) (string, error) { return "", nil }, lookupCountry: func(net.IP) (string, error) { return "", nil },
lookupCity: func(net.IP) (string, error) { return "", nil }, lookupCountryISO: func(net.IP) (string, error) { return "", nil },
lookupPort: func(net.IP, uint64) 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) 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) { func (r *DefaultOracle) LookupCity(ip net.IP) (string, error) {
return r.lookupCity(ip) return r.lookupCity(ip)
} }
@ -69,6 +76,9 @@ func (r *DefaultOracle) EnableLookupCountry(filepath string) error {
r.lookupCountry = func(ip net.IP) (string, error) { r.lookupCountry = func(ip net.IP) (string, error) {
return lookupCountry(db, ip) return lookupCountry(db, ip)
} }
r.lookupCountryISO = func(ip net.IP) (string, error) {
return lookupCountryISO(db, ip)
}
r.lookupCountryEnabled = true r.lookupCountryEnabled = true
return nil 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) 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) { func lookupCity(db *geoip2.Reader, ip net.IP) (string, error) {
record, err := db.City(ip) record, err := db.City(ip)
if err != nil { if err != nil {

View File

@ -63,6 +63,10 @@ $ bat -print=b {{ .Host }}/ip
<pre> <pre>
$ http {{ .Host }}/country $ http {{ .Host }}/country
{{ .Country }}</pre> {{ .Country }}</pre>
<h2>Short country code (ISO 3166-1 alpha-2) lookup:</h2>
<pre>
$ http {{ .Host }}/country-iso
{{ .CountryISO }}</pre>
{{ end }} {{ end }}
{{ if .IsLookupCityEnabled }} {{ if .IsLookupCityEnabled }}
<h2>City lookup:</h2> <h2>City lookup:</h2>
@ -76,8 +80,9 @@ $ http {{ .Host }}/city
<pre> <pre>
$ http {{ .Host }}/json $ http {{ .Host }}/json
{ {{ if .IsLookupCityEnabled }} { {{ if .IsLookupCityEnabled }}
"city": "{{ .City }}",{{ end }}{{ if .IsLookupCountryEnabled }} "city": "{{ .City }}",
"country": "{{ .Country }}",{{ end }}{{ if .IsLookupAddrEnabled }} "country": "{{ .Country }}",
"country_iso": "{{ .CountryISO }}",{{ end }}{{ if .IsLookupAddrEnabled }}
"hostname": "{{ .Hostname }}",{{ end }} "hostname": "{{ .Hostname }}",{{ end }}
"ip": "{{ .IP }}", "ip": "{{ .IP }}",
"ip_decimal": {{ .IPDecimal }} "ip_decimal": {{ .IPDecimal }}
@ -100,6 +105,13 @@ $ http {{ .Host }}/port/8080
}</pre> }</pre>
{{ end }} {{ end }}
</div> </div>
{{ if .IsLookupCountryEnabled }}{{ if ne .Country "Unknown"}}{{ if .IsLookupCityEnabled }}{{ if ne .City "Unknown"}}
<div class="pure-u-1 pure-u-md-1-1">
<h2>Map</h2>
<p><img src="https://maps.googleapis.com/maps/api/staticmap?size=600x200&amp;scale=2&amp;markers=color%3Aorange%7Clabel%3AS%7c{{ .City }},{{ .Country }}" width="600" height="200"/>
</p>
{{ end }}{{ end }}{{ end }}{{ end }}
</div>
<div class="pure-u-1 pure-u-md-1-1"> <div class="pure-u-1 pure-u-md-1-1">
<h2>FAQ</h2> <h2>FAQ</h2>
<h3>How do I force IPv4 or IPv6 lookup?</h3> <h3>How do I force IPv4 or IPv6 lookup?</h3>