diff --git a/go.mod b/go.mod index ddbb381..5a38fc2 100644 --- a/go.mod +++ b/go.mod @@ -4,5 +4,5 @@ go 1.14 require ( github.com/alicebob/sqlittle v1.4.1-0.20200506090143-e4b415246cd8 - github.com/sirupsen/logrus v1.6.0 + github.com/mmcloughlin/geohash v0.9.0 ) diff --git a/go.sum b/go.sum index 12253ea..2c8c542 100644 --- a/go.sum +++ b/go.sum @@ -6,16 +6,13 @@ github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/konsorten/go-windows-terminal-sequences v1.0.3 h1:CE8S1cTafDpPvMhIxNJKvHsGVBgn1xWYf1NbHQhywc8= -github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/mmcloughlin/geohash v0.9.0 h1:FihR004p/aE1Sju6gcVq5OLDqGcMnpBY+8moBqIsVOs= +github.com/mmcloughlin/geohash v0.9.0/go.mod h1:oNZxQo5yWJh0eMQEP/8hwQuVx9Z9tjwFUqcTB1SmG0c= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/sergi/go-diff v1.0.0 h1:Kpca3qRNrduNnOQeazBd0ysaKrUJiIuISHxogkT9RPQ= github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= -github.com/sirupsen/logrus v1.6.0 h1:UBcNElsrwanuuMsnGSlYmtmgbb23qDR5dG+6X6Oo89I= -github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= @@ -26,9 +23,8 @@ golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190419153524-e8e3143a4f4a h1:XCr/YX7O0uxRkLq2k1ApNQMims9eCioF9UpzIPBDmuo= golang.org/x/sys v0.0.0-20190419153524-e8e3143a4f4a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190422165155-953cdadca894 h1:Cz4ceDQGXuKRnVBDTS23GTn/pU5OE2C0WrNTOYK1Uuc= -golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= diff --git a/main.go b/main.go index 65081c9..6f97c97 100644 --- a/main.go +++ b/main.go @@ -1,15 +1,29 @@ package main import ( + "log" + "time" + "github.com/alicebob/sqlittle" - log "github.com/sirupsen/logrus" + "github.com/glvr182/f2b-exporter/provider" ) +// prisoner is an ip that has been (temp) banned by f2b type prisoner struct { - jail string - ip string + // jail represents the jail f2b assigned + jail string + // ip is the prisoners ip + ip string + // timeofban indicates moment he was banned timeofban int - bantime int + // bantime indicates how long he will be banned (-1 = infinity) + bantime int + // country is the general location of the prisoner + country string + // geohash is a more accurate location of the prisoner + geohash string + // currentlyBanned indicates if the prisoner is currently banned + currentlyBanned bool } func main() { @@ -20,7 +34,12 @@ func main() { } defer db.Close() - prisoners, err := jailed(db) + provider, err := provider.New("freeGeoIP") + if err != nil { + panic(err) + } + + prisoners, err := jailed(db, provider) if err != nil { panic(err) } @@ -28,20 +47,38 @@ func main() { log.Printf("%v", prisoners) } -func jailed(db *sqlittle.DB) ([]prisoner, error) { +func jailed(db *sqlittle.DB, provider provider.Provider) ([]prisoner, error) { var ( prisoners []prisoner p prisoner + err error ) - db.Select("bans", func(r sqlittle.Row) { - err := r.Scan(&p.jail, &p.ip, &p.timeofban, &p.bantime) + db.SelectDone("bans", func(r sqlittle.Row) bool { + err = r.Scan(&p.jail, &p.ip, &p.timeofban, &p.bantime) + if err != nil { + return true + } + + payload, err := provider.Lookup(p.ip) if err != nil { - panic(err) + return true + } + p.country = payload.CountryCode + p.geohash = payload.GeoHash + + if int64(p.timeofban+p.bantime) > time.Now().Unix() || p.bantime < 0 { + p.currentlyBanned = true } + prisoners = append(prisoners, p) + return false }, "jail", "ip", "timeofban", "bantime") + if err != nil { + return nil, err + } + return prisoners, nil } diff --git a/provider/freegeoip.go b/provider/freegeoip.go new file mode 100644 index 0000000..8b0915a --- /dev/null +++ b/provider/freegeoip.go @@ -0,0 +1,50 @@ +package provider + +import ( + "bytes" + "encoding/json" + "net/http" + + "github.com/mmcloughlin/geohash" +) + +// server url +const freeGeoIPServer = "https://freegeoip.app/json/" + +// Geo contains all the geolocation data +type freeGeoIPPayload struct { + // CountryCode of the prisoner + CountryCode string `json:"country_code"` + // Latitude of the prisoner + Latitude float64 `json:"latitude"` + // Longitude of the prisoner + Longitude float64 `json:"longitude"` +} + +// freeGeoIP is a provider +type freeGeoIP struct{} + +// Check if freeGeoIP is a provider on compile-time +var _ Provider = (*freeGeoIP)(nil) + +// Lookup takes an ip and returns the geohash if everthing went well. +func (f freeGeoIP) Lookup(ip string) (Payload, error) { + resp, err := http.Get(freeGeoIPServer + ip) + if err != nil { + return Payload{}, err + } + + var ( + data freeGeoIPPayload + reader = new(bytes.Buffer) + ) + _, err = reader.ReadFrom(resp.Body) + if err != nil { + return Payload{}, err + } + if err = json.Unmarshal(reader.Bytes(), &data); err != nil { + return Payload{}, err + } + + return Payload{data.CountryCode, geohash.Encode(data.Latitude, data.Longitude)}, nil +} diff --git a/provider/provider.go b/provider/provider.go new file mode 100644 index 0000000..2641287 --- /dev/null +++ b/provider/provider.go @@ -0,0 +1,32 @@ +package provider + +import "errors" + +var ( + // ErrNoSuchProvider is thrown when there is no provider + ErrNoSuchProvider = errors.New("no such provider") +) + +// Payload is all the info we need about a prisoners location +type Payload struct { + // CountryCode represents the code, for example "NL" + CountryCode string + // GeoHash is latitude and longitude combined in a hash + GeoHash string +} + +// Provider is able to return a prisoners location data +type Provider interface { + // Fetch the prisoners location data + Lookup(ip string) (Payload, error) +} + +// New creates a new provider using the given provider name +func New(provider string) (Provider, error) { + switch provider { + case "freeGeoIP": + pr := new(freeGeoIP) + return pr, nil + } + return nil, ErrNoSuchProvider +}