Skip to content

Commit

Permalink
#minor: move to ipbase.com api
Browse files Browse the repository at this point in the history
  • Loading branch information
circa10a committed Aug 10, 2022
1 parent b03a325 commit 7a94016
Show file tree
Hide file tree
Showing 7 changed files with 174 additions and 80 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/tag.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ jobs:
with:
go-version: ${{ steps.vars.outputs.go_version }}
- name: Bump version and push tag
uses: anothrNick/github-tag-action@1.26.0
uses: anothrNick/github-tag-action@1.39.0
id: tagging
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
Expand Down
4 changes: 0 additions & 4 deletions .github/workflows/test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,6 @@ jobs:
steps:
- name: Install Go
uses: actions/setup-go@v2
with:
go-version: '^1.17.0'
- name: Checkout code
uses: actions/checkout@v2
- name: Test
Expand All @@ -23,7 +21,5 @@ jobs:
- uses: actions/checkout@v2
- name: Install Go
uses: actions/setup-go@v2
with:
go-version: '^1.17.0'
- name: golangci-lint
uses: golangci/golangci-lint-action@v2
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@
[![PkgGoDev](https://pkg.go.dev/badge/github.com/circa10a/go-geofence)](https://pkg.go.dev/github.com/circa10a/go-geofence?tab=overview)
[![Go Report Card](https://goreportcard.com/badge/github.com/circa10a/go-geofence)](https://goreportcard.com/report/github.com/circa10a/go-geofence)

A small library to detect if an IP address is close to yours or another of your choosing using https://freegeoip.app/
A small library to detect if an IP address is close to yours or another of your choosing using https://ipbase.com/

## Usage

First you will need a free API Token from [freegeoip.app](https://freegeoip.app/)
First you will need a free API Token from [ipbase.com](https://ipbase.com/)

```bash
go get github.com/circa10a/go-geofence
Expand All @@ -29,8 +29,8 @@ func main() {
geofence, err := geofence.New(&geofence.Config{
// Empty string to geofence your current public IP address, or you can monitor a remote address by supplying it as the first parameter
IPAddress: "",
// freegeoip.app API token
Token: "YOUR_FREEGEOIP_API_TOKEN",
// ipbase.com API token
Token: "YOUR_IPBASE_API_TOKEN",
// Maximum radius of the geofence in kilometers, only clients less than or equal to this distance will return true with isAddressNearby
// 1 kilometer
Radius: 1.0,
Expand Down
150 changes: 110 additions & 40 deletions geofence.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import (
)

const (
freeGeoIPBaseURL = "https://api.freegeoip.app/json"
ipBaseBaseURL = "https://api.ipbase.com/v2"
deleteExpiredCacheItemsInternal = 10 * time.Minute
)

Expand All @@ -24,36 +24,105 @@ type Config struct {
CacheTTL time.Duration
}

// Geofence holds a freegeoip.app client, cache and user supplied config
// Geofence holds a ipbase.com client, cache and user supplied config
type Geofence struct {
Cache *cache.Cache
FreeGeoIPClient *resty.Client
Cache *cache.Cache
IPBaseClient *resty.Client
Config
Latitude float64
Longitude float64
}

// FreeGeoIPResponse is the json response from freegeoip.app
type FreeGeoIPResponse struct {
IP string `json:"ip"`
CountryCode string `json:"country_code"`
CountryName string `json:"country_name"`
RegionCode string `json:"region_code"`
RegionName string `json:"region_name"`
City string `json:"city"`
ZipCode string `json:"zip_code"`
TimeZone string `json:"time_zone"`
Latitude float64 `json:"latitude"`
Longitude float64 `json:"longitude"`
MetroCode int `json:"metro_code"`
// ipBaseResponse is the json response from ipbase.com
type ipBaseResponse struct {
Data data `json:"data"`
}

// FreeGeoIPError is the json response when there is an error from freegeoip.app
type FreeGeoIPError struct {
type timezone struct {
Id string `json:"id"`
CurrentTime string `json:"current_time"`
Code string `json:"code"`
IDaylightSaving bool `json:"is_daylight_saving"`
GmtOffset int `json:"gmt_offset"`
}

type connection struct {
Organization string `json:"organization"`
Isp string `json:"isp"`
Asn int `json:"asn"`
}

type continent struct {
Code string `json:"code"`
Name string `json:"name"`
NameTranslated string `json:"name_translated"`
}

type currencies struct {
Symbol string `json:"symbol"`
Name string `json:"name"`
SymbolNative string `json:"symbol_native"`
Code string `json:"code"`
NamePlural string `json:"name_plural"`
DecimalDigits int `json:"decimal_digits"`
Rounding int `json:"rounding"`
}

type languages struct {
Name string `json:"name"`
NameNative string `json:"name_native"`
}
type country struct {
Alpha2 string `json:"alpha2"`
Alpha3 string `json:"alpha3"`
CallingCodes []string `json:"calling_codes"`
Currencies []currencies `json:"currencies"`
Emoji string `json:"emoji"`
Ioc string `json:"ioc"`
Languages []languages `json:"languages"`
Name string `json:"name"`
NameTranslated string `json:"name_translated"`
Timezones []string `json:"timezones"`
IsInEuropeanUnion bool `json:"is_in_european_union"`
}

type city struct {
Name string `json:"name"`
NameTranslated string `json:"name_translated"`
}

type region struct {
Fips interface{} `json:"fips"`
Alpha2 interface{} `json:"alpha2"`
Name string `json:"name"`
NameTranslated string `json:"name_translated"`
}

type location struct {
GeonamesID interface{} `json:"geonames_id"`
Region region `json:"region"`
Continent continent `json:"continent"`
City city `json:"city"`
Zip string `json:"zip"`
Country country `json:"country"`
Latitude float64 `json:"latitude"`
Longitude float64 `json:"longitude"`
}

type data struct {
Timezone timezone `json:"timezone"`
IP string `json:"ip"`
Type string `json:"type"`
Connection connection `json:"connection"`
Location location `json:"location"`
}

// IPBaseError is the json response when there is an error from ipbase.com
type IPBaseError struct {
Message string `json:"message"`
}

func (e *FreeGeoIPError) Error() string {
func (e *IPBaseError) Error() string {
return e.Message
}

Expand All @@ -68,41 +137,42 @@ func validateIPAddress(ipAddress string) error {
return nil
}

// getIPGeoData fetches geolocation data for specified IP address from https://freegeoip.app
func (g *Geofence) getIPGeoData(ipAddress string) (*FreeGeoIPResponse, error) {
freeGeoIPResponse := &FreeGeoIPResponse{}
freeGeoIPError := &FreeGeoIPError{}
// getIPGeoData fetches geolocation data for specified IP address from https://ipbase.com
func (g *Geofence) getIPGeoData(ipAddress string) (*ipBaseResponse, error) {
response := &ipBaseResponse{}
ipBaseError := &IPBaseError{}

resp, err := g.FreeGeoIPClient.R().
resp, err := g.IPBaseClient.R().
SetHeader("Accept", "application/json").
SetQueryParam("apikey", g.Token).
SetResult(freeGeoIPResponse).
SetError(freeGeoIPError).
Get(ipAddress)
SetQueryParam("ip", ipAddress).
SetResult(response).
SetError(ipBaseError).
Get("/info")
if err != nil {
return freeGeoIPResponse, err
return response, err
}

// If api gives back status code >399, report error to user
if resp.IsError() {
return freeGeoIPResponse, freeGeoIPError
return response, ipBaseError
}

return resp.Result().(*FreeGeoIPResponse), nil
return resp.Result().(*ipBaseResponse), nil
}

// New creates a new geofence for the IP address specified.
// Use "" as the ip address to geofence the machine your application is running on
// Token comes from https://freegeoip.app/
// Token comes from https://ipbase.com/
func New(c *Config) (*Geofence, error) {
// Create new client for freegeoip.app
freeGeoIPClient := resty.New().SetBaseURL(freeGeoIPBaseURL)
// Create new client for ipbase.com
IPBaseClient := resty.New().SetBaseURL(ipBaseBaseURL)

// New Geofence object
geofence := &Geofence{
Config: *c,
FreeGeoIPClient: freeGeoIPClient,
Cache: cache.New(c.CacheTTL, deleteExpiredCacheItemsInternal),
Config: *c,
IPBaseClient: IPBaseClient,
Cache: cache.New(c.CacheTTL, deleteExpiredCacheItemsInternal),
}

// Get current location of specified IP address
Expand All @@ -114,8 +184,8 @@ func New(c *Config) (*Geofence, error) {
}

// Set the location of our geofence to compare against looked up IP's
geofence.Latitude = ipAddressLookupDetails.Latitude
geofence.Longitude = ipAddressLookupDetails.Longitude
geofence.Latitude = ipAddressLookupDetails.Data.Location.Latitude
geofence.Longitude = ipAddressLookupDetails.Data.Location.Longitude

return geofence, nil
}
Expand Down Expand Up @@ -148,7 +218,7 @@ func (g *Geofence) IsIPAddressNear(ipAddress string) (bool, error) {

// Format our IP coordinates and the clients
currentCoordinates := geo.NewCoordinatesFromDegrees(g.Latitude, g.Longitude)
clientCoordinates := geo.NewCoordinatesFromDegrees(ipAddressLookupDetails.Latitude, ipAddressLookupDetails.Longitude)
clientCoordinates := geo.NewCoordinatesFromDegrees(ipAddressLookupDetails.Data.Location.Latitude, ipAddressLookupDetails.Data.Location.Longitude)

// Get distance in kilometers
distance := currentCoordinates.Distance(clientCoordinates)
Expand Down
Loading

0 comments on commit 7a94016

Please sign in to comment.