mirror of
				https://github.com/dcarrillo/whatismyip.git
				synced 2025-11-04 05:49:09 +00:00 
			
		
		
		
	Make geo database usage optional (#39)
This commit is contained in:
		@@ -7,7 +7,6 @@ import (
 | 
			
		||||
	"strings"
 | 
			
		||||
 | 
			
		||||
	validator "github.com/dcarrillo/whatismyip/internal/validator/uuid"
 | 
			
		||||
	"github.com/dcarrillo/whatismyip/service"
 | 
			
		||||
	"github.com/gin-gonic/gin"
 | 
			
		||||
	"github.com/google/uuid"
 | 
			
		||||
	"github.com/patrickmn/go-cache"
 | 
			
		||||
@@ -16,10 +15,14 @@ import (
 | 
			
		||||
type DNSJSONResponse struct {
 | 
			
		||||
	DNS dnsData `json:"dns"`
 | 
			
		||||
}
 | 
			
		||||
type dnsGeoData struct {
 | 
			
		||||
	Country         string `json:"country,omitempty"`
 | 
			
		||||
	AsnOrganization string `json:"provider,omitempty"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type dnsData struct {
 | 
			
		||||
	IP              string `json:"ip"`
 | 
			
		||||
	Country         string `json:"country"`
 | 
			
		||||
	AsnOrganization string `json:"provider"`
 | 
			
		||||
	IP string `json:"ip"`
 | 
			
		||||
	dnsGeoData
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// TODO
 | 
			
		||||
@@ -67,12 +70,21 @@ func handleDNS(ctx *gin.Context, store *cache.Cache) {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	geo := service.Geo{IP: ip}
 | 
			
		||||
	geoResp := dnsGeoData{}
 | 
			
		||||
	if geoSvc != nil {
 | 
			
		||||
		cityRecord := geoSvc.LookUpCity(ip)
 | 
			
		||||
		asnRecord := geoSvc.LookUpASN(ip)
 | 
			
		||||
 | 
			
		||||
		geoResp = dnsGeoData{
 | 
			
		||||
			Country:         cityRecord.Country.Names["en"],
 | 
			
		||||
			AsnOrganization: asnRecord.AutonomousSystemOrganization,
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	j := DNSJSONResponse{
 | 
			
		||||
		DNS: dnsData{
 | 
			
		||||
			IP:              ipStr,
 | 
			
		||||
			Country:         geo.LookUpCity().Country.Names["en"],
 | 
			
		||||
			AsnOrganization: geo.LookUpASN().AutonomousSystemOrganization,
 | 
			
		||||
			IP:         ipStr,
 | 
			
		||||
			dnsGeoData: geoResp,
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -7,25 +7,28 @@ import (
 | 
			
		||||
 | 
			
		||||
	"github.com/dcarrillo/whatismyip/internal/httputils"
 | 
			
		||||
	"github.com/dcarrillo/whatismyip/internal/setting"
 | 
			
		||||
	"github.com/dcarrillo/whatismyip/service"
 | 
			
		||||
	"github.com/gin-gonic/gin"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type GeoResponse struct {
 | 
			
		||||
	Country         string  `json:"country,omitempty"`
 | 
			
		||||
	CountryCode     string  `json:"country_code,omitempty"`
 | 
			
		||||
	City            string  `json:"city,omitempty"`
 | 
			
		||||
	Latitude        float64 `json:"latitude,omitempty"`
 | 
			
		||||
	Longitude       float64 `json:"longitude,omitempty"`
 | 
			
		||||
	PostalCode      string  `json:"postal_code,omitempty"`
 | 
			
		||||
	TimeZone        string  `json:"time_zone,omitempty"`
 | 
			
		||||
	ASN             uint    `json:"asn,omitempty"`
 | 
			
		||||
	ASNOrganization string  `json:"asn_organization,omitempty"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type JSONResponse struct {
 | 
			
		||||
	IP              string      `json:"ip"`
 | 
			
		||||
	IPVersion       byte        `json:"ip_version"`
 | 
			
		||||
	ClientPort      string      `json:"client_port"`
 | 
			
		||||
	Country         string      `json:"country"`
 | 
			
		||||
	CountryCode     string      `json:"country_code"`
 | 
			
		||||
	City            string      `json:"city"`
 | 
			
		||||
	Latitude        float64     `json:"latitude"`
 | 
			
		||||
	Longitude       float64     `json:"longitude"`
 | 
			
		||||
	PostalCode      string      `json:"postal_code"`
 | 
			
		||||
	TimeZone        string      `json:"time_zone"`
 | 
			
		||||
	ASN             uint        `json:"asn"`
 | 
			
		||||
	ASNOrganization string      `json:"asn_organization"`
 | 
			
		||||
	Host            string      `json:"host"`
 | 
			
		||||
	Headers         http.Header `json:"headers"`
 | 
			
		||||
	IP         string      `json:"ip"`
 | 
			
		||||
	IPVersion  byte        `json:"ip_version"`
 | 
			
		||||
	ClientPort string      `json:"client_port"`
 | 
			
		||||
	Host       string      `json:"host"`
 | 
			
		||||
	Headers    http.Header `json:"headers"`
 | 
			
		||||
	GeoResponse
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func getRoot(ctx *gin.Context) {
 | 
			
		||||
@@ -66,16 +69,14 @@ func getClientPortAsString(ctx *gin.Context) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func getAllAsString(ctx *gin.Context) {
 | 
			
		||||
	output := "IP: " + ctx.ClientIP() + "\n"
 | 
			
		||||
	ip := net.ParseIP(ctx.ClientIP())
 | 
			
		||||
 | 
			
		||||
	output := "IP: " + ip.String() + "\n"
 | 
			
		||||
	output += "Client Port: " + getClientPort(ctx) + "\n"
 | 
			
		||||
 | 
			
		||||
	r := service.Geo{IP: net.ParseIP(ctx.ClientIP())}
 | 
			
		||||
	if record := r.LookUpCity(); record != nil {
 | 
			
		||||
		output += geoCityRecordToString(record) + "\n"
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if record := r.LookUpASN(); record != nil {
 | 
			
		||||
		output += geoASNRecordToString(record) + "\n"
 | 
			
		||||
	if geoSvc != nil {
 | 
			
		||||
		output += geoCityRecordToString(geoSvc.LookUpCity(ip)) + "\n"
 | 
			
		||||
		output += geoASNRecordToString(geoSvc.LookUpASN(ip)) + "\n"
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	h := httputils.GetHeadersWithoutTrustedHeaders(ctx)
 | 
			
		||||
@@ -90,28 +91,37 @@ func getJSON(ctx *gin.Context) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func jsonOutput(ctx *gin.Context) JSONResponse {
 | 
			
		||||
	ip := service.Geo{IP: net.ParseIP(ctx.ClientIP())}
 | 
			
		||||
	asnRecord := ip.LookUpASN()
 | 
			
		||||
	cityRecord := ip.LookUpCity()
 | 
			
		||||
	ip := net.ParseIP(ctx.ClientIP())
 | 
			
		||||
 | 
			
		||||
	var version byte = 4
 | 
			
		||||
	if p := net.ParseIP(ctx.ClientIP()).To4(); p == nil {
 | 
			
		||||
	if p := ip.To4(); p == nil {
 | 
			
		||||
		version = 6
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	geoResp := GeoResponse{}
 | 
			
		||||
	if geoSvc != nil {
 | 
			
		||||
		cityRecord := geoSvc.LookUpCity(ip)
 | 
			
		||||
		asnRecord := geoSvc.LookUpASN(ip)
 | 
			
		||||
 | 
			
		||||
		geoResp = GeoResponse{
 | 
			
		||||
			Country:         cityRecord.Country.Names["en"],
 | 
			
		||||
			CountryCode:     cityRecord.Country.ISOCode,
 | 
			
		||||
			City:            cityRecord.City.Names["en"],
 | 
			
		||||
			Latitude:        cityRecord.Location.Latitude,
 | 
			
		||||
			Longitude:       cityRecord.Location.Longitude,
 | 
			
		||||
			PostalCode:      cityRecord.Postal.Code,
 | 
			
		||||
			TimeZone:        cityRecord.Location.TimeZone,
 | 
			
		||||
			ASN:             asnRecord.AutonomousSystemNumber,
 | 
			
		||||
			ASNOrganization: asnRecord.AutonomousSystemOrganization,
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return JSONResponse{
 | 
			
		||||
		IP:              ctx.ClientIP(),
 | 
			
		||||
		IPVersion:       version,
 | 
			
		||||
		ClientPort:      getClientPort(ctx),
 | 
			
		||||
		Country:         cityRecord.Country.Names["en"],
 | 
			
		||||
		CountryCode:     cityRecord.Country.ISOCode,
 | 
			
		||||
		City:            cityRecord.City.Names["en"],
 | 
			
		||||
		Latitude:        cityRecord.Location.Latitude,
 | 
			
		||||
		Longitude:       cityRecord.Location.Longitude,
 | 
			
		||||
		PostalCode:      cityRecord.Postal.Code,
 | 
			
		||||
		TimeZone:        cityRecord.Location.TimeZone,
 | 
			
		||||
		ASN:             asnRecord.AutonomousSystemNumber,
 | 
			
		||||
		ASNOrganization: asnRecord.AutonomousSystemOrganization,
 | 
			
		||||
		Host:            ctx.Request.Host,
 | 
			
		||||
		Headers:         httputils.GetHeadersWithoutTrustedHeaders(ctx),
 | 
			
		||||
		IP:          ip.String(),
 | 
			
		||||
		IPVersion:   version,
 | 
			
		||||
		ClientPort:  getClientPort(ctx),
 | 
			
		||||
		Host:        ctx.Request.Host,
 | 
			
		||||
		Headers:     httputils.GetHeadersWithoutTrustedHeaders(ctx),
 | 
			
		||||
		GeoResponse: geoResp,
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -8,7 +8,6 @@ import (
 | 
			
		||||
	"strings"
 | 
			
		||||
 | 
			
		||||
	"github.com/dcarrillo/whatismyip/models"
 | 
			
		||||
	"github.com/dcarrillo/whatismyip/service"
 | 
			
		||||
	"github.com/gin-gonic/gin"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
@@ -83,10 +82,13 @@ var asnOutput = map[string]asnDataFormatter{
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func getGeoAsString(ctx *gin.Context) {
 | 
			
		||||
	field := strings.ToLower(ctx.Params.ByName("field"))
 | 
			
		||||
	ip := service.Geo{IP: net.ParseIP(ctx.ClientIP())}
 | 
			
		||||
	record := ip.LookUpCity()
 | 
			
		||||
	if geoSvc == nil {
 | 
			
		||||
		ctx.String(http.StatusNotFound, http.StatusText(http.StatusNotFound))
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	field := strings.ToLower(ctx.Params.ByName("field"))
 | 
			
		||||
	record := geoSvc.LookUpCity(net.ParseIP(ctx.ClientIP()))
 | 
			
		||||
	if field == "" {
 | 
			
		||||
		ctx.String(http.StatusOK, geoCityRecordToString(record))
 | 
			
		||||
	} else if g, ok := geoOutput[field]; ok {
 | 
			
		||||
@@ -97,10 +99,12 @@ func getGeoAsString(ctx *gin.Context) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func getASNAsString(ctx *gin.Context) {
 | 
			
		||||
	if geoSvc == nil {
 | 
			
		||||
		ctx.String(http.StatusNotFound, http.StatusText(http.StatusNotFound))
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	field := strings.ToLower(ctx.Params.ByName("field"))
 | 
			
		||||
	ip := service.Geo{IP: net.ParseIP(ctx.ClientIP())}
 | 
			
		||||
	record := ip.LookUpASN()
 | 
			
		||||
 | 
			
		||||
	record := geoSvc.LookUpASN(net.ParseIP(ctx.ClientIP()))
 | 
			
		||||
	if field == "" {
 | 
			
		||||
		ctx.String(http.StatusOK, geoASNRecordToString(record))
 | 
			
		||||
	} else if g, ok := asnOutput[field]; ok {
 | 
			
		||||
 
 | 
			
		||||
@@ -5,9 +5,12 @@ import (
 | 
			
		||||
	"log"
 | 
			
		||||
 | 
			
		||||
	"github.com/dcarrillo/whatismyip/internal/setting"
 | 
			
		||||
	"github.com/dcarrillo/whatismyip/service"
 | 
			
		||||
	"github.com/gin-gonic/gin"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var geoSvc *service.Geo
 | 
			
		||||
 | 
			
		||||
func SetupTemplate(r *gin.Engine) {
 | 
			
		||||
	if setting.App.TemplatePath == "" {
 | 
			
		||||
		t, _ := template.New("home").Parse(home)
 | 
			
		||||
@@ -18,7 +21,8 @@ func SetupTemplate(r *gin.Engine) {
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func Setup(r *gin.Engine) {
 | 
			
		||||
func Setup(r *gin.Engine, geo *service.Geo) {
 | 
			
		||||
	geoSvc = geo
 | 
			
		||||
	r.GET("/", getRoot)
 | 
			
		||||
	r.GET("/scan/tcp/:port", scanTCPPort)
 | 
			
		||||
	r.GET("/client-port", getClientPortAsString)
 | 
			
		||||
 
 | 
			
		||||
@@ -1,10 +1,11 @@
 | 
			
		||||
package router
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"context"
 | 
			
		||||
	"os"
 | 
			
		||||
	"testing"
 | 
			
		||||
 | 
			
		||||
	"github.com/dcarrillo/whatismyip/models"
 | 
			
		||||
	"github.com/dcarrillo/whatismyip/service"
 | 
			
		||||
	"github.com/gin-gonic/gin"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
@@ -34,9 +35,9 @@ var (
 | 
			
		||||
		text: "text/plain; charset=utf-8",
 | 
			
		||||
		json: "application/json; charset=utf-8",
 | 
			
		||||
	}
 | 
			
		||||
	jsonIPv4     = `{"client_port":"1001","ip":"81.2.69.192","ip_version":4,"country":"United Kingdom","country_code":"GB","city":"London","latitude":51.5142,"longitude":-0.0931,"postal_code":"","time_zone":"Europe/London","asn":0,"asn_organization":"","host":"test", "headers": {}}`
 | 
			
		||||
	jsonIPv6     = `{"asn":3352, "asn_organization":"TELEFONICA DE ESPANA", "city":"", "client_port":"1001", "country":"", "country_code":"", "host":"test", "ip":"2a02:9000::1", "ip_version":6, "latitude":0, "longitude":0, "postal_code":"", "time_zone":"", "headers": {}}`
 | 
			
		||||
	jsonDNSIPv4  = `{"dns":{"ip":"81.2.69.192","country":"United Kingdom","provider":""}}`
 | 
			
		||||
	jsonIPv4     = `{"client_port":"1001","ip":"81.2.69.192","ip_version":4,"country":"United Kingdom","country_code":"GB","city":"London","latitude":51.5142,"longitude":-0.0931,"time_zone":"Europe/London","host":"test", "headers": {}}`
 | 
			
		||||
	jsonIPv6     = `{"asn":3352,"asn_organization":"TELEFONICA DE ESPANA","client_port":"1001","host":"test","ip":"2a02:9000::1","ip_version":6,"headers": {}}`
 | 
			
		||||
	jsonDNSIPv4  = `{"dns":{"ip":"81.2.69.192","country":"United Kingdom"}}`
 | 
			
		||||
	plainDNSIPv4 = "81.2.69.192 (United Kingdom / )\n"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
@@ -49,9 +50,8 @@ const (
 | 
			
		||||
func TestMain(m *testing.M) {
 | 
			
		||||
	app = gin.Default()
 | 
			
		||||
	app.TrustedPlatform = trustedHeader
 | 
			
		||||
	models.Setup("../test/GeoIP2-City-Test.mmdb", "../test/GeoLite2-ASN-Test.mmdb")
 | 
			
		||||
	Setup(app)
 | 
			
		||||
	defer models.CloseDBs()
 | 
			
		||||
	svc, _ := service.NewGeo(context.Background(), "../test/GeoIP2-City-Test.mmdb", "../test/GeoLite2-ASN-Test.mmdb")
 | 
			
		||||
	Setup(app, svc)
 | 
			
		||||
 | 
			
		||||
	os.Exit(m.Run())
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -62,20 +62,22 @@ func TestDefaultTemplate(t *testing.T) {
 | 
			
		||||
 | 
			
		||||
	tmpl, _ := template.New("home").Parse(home)
 | 
			
		||||
	response := JSONResponse{
 | 
			
		||||
		IP:              "127.0.0.1",
 | 
			
		||||
		IPVersion:       4,
 | 
			
		||||
		ClientPort:      "1000",
 | 
			
		||||
		Country:         "A Country",
 | 
			
		||||
		CountryCode:     "XX",
 | 
			
		||||
		City:            "A City",
 | 
			
		||||
		Latitude:        100,
 | 
			
		||||
		Longitude:       -100,
 | 
			
		||||
		PostalCode:      "00000",
 | 
			
		||||
		TimeZone:        "My/Timezone",
 | 
			
		||||
		ASN:             0,
 | 
			
		||||
		ASNOrganization: "My ISP",
 | 
			
		||||
		Host:            "localhost",
 | 
			
		||||
		Headers:         req.Header,
 | 
			
		||||
		IP:         "127.0.0.1",
 | 
			
		||||
		IPVersion:  4,
 | 
			
		||||
		ClientPort: "1000",
 | 
			
		||||
		Host:       "localhost",
 | 
			
		||||
		Headers:    req.Header,
 | 
			
		||||
		GeoResponse: GeoResponse{
 | 
			
		||||
			Country:         "A Country",
 | 
			
		||||
			CountryCode:     "XX",
 | 
			
		||||
			City:            "A City",
 | 
			
		||||
			Latitude:        100,
 | 
			
		||||
			Longitude:       -100,
 | 
			
		||||
			PostalCode:      "00000",
 | 
			
		||||
			TimeZone:        "My/Timezone",
 | 
			
		||||
			ASN:             0,
 | 
			
		||||
			ASNOrganization: "My ISP",
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	buf := &bytes.Buffer{}
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user