-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
bd3bc63
commit caa6915
Showing
6 changed files
with
254 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
package spur | ||
|
||
import ( | ||
"github.com/evalphobia/go-ip-fraud-check/provider/privateclient" | ||
) | ||
|
||
const ( | ||
defaultBaseURL = "https://api.spur.us" | ||
) | ||
|
||
type Client struct { | ||
privateclient.RESTClient | ||
} | ||
|
||
func NewClient(token string) Client { | ||
return Client{ | ||
RESTClient: privateclient.RESTClient{ | ||
Option: privateclient.Option{ | ||
Headers: map[string]string{"Token": token}, | ||
BaseURL: defaultBaseURL, | ||
}, | ||
}, | ||
} | ||
} | ||
|
||
func (c *Client) SetDebug(b bool) { | ||
c.RESTClient.Debug = b | ||
} | ||
|
||
func (c Client) DoContext(ipaddr string) (Response, error) { | ||
resp := Response{} | ||
err := c.RESTClient.CallGET("/v1/context/"+ipaddr, nil, &resp) | ||
return resp, err | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
package spur | ||
|
||
import ( | ||
"errors" | ||
"fmt" | ||
"strings" | ||
|
||
"github.com/evalphobia/go-ip-fraud-check/ipfraudcheck" | ||
"github.com/evalphobia/go-ip-fraud-check/provider" | ||
) | ||
|
||
type SpurProvider struct { | ||
client Client | ||
} | ||
|
||
func (p *SpurProvider) Init(conf provider.Config) error { | ||
c, ok := conf.(ipfraudcheck.Config) | ||
if !ok { | ||
return errors.New("incompatible config type for SpurProvider") | ||
} | ||
|
||
token := c.GetSpurToken() | ||
if token == "" { | ||
return errors.New("token for spur is empty. you must set directly or use 'FRAUD_CHECK_SPUR_TOKEN' envvar") | ||
} | ||
cli := NewClient(token) | ||
cli.SetDebug(c.Debug) | ||
p.client = cli | ||
return nil | ||
} | ||
|
||
func (p SpurProvider) String() string { | ||
return "spur" | ||
} | ||
|
||
func (p SpurProvider) CheckIP(ipaddr string) (provider.FraudCheckResponse, error) { | ||
emptyResult := provider.FraudCheckResponse{} | ||
|
||
resp, err := p.client.DoContext(ipaddr) | ||
if err != nil { | ||
return emptyResult, err | ||
} | ||
|
||
var comments []string | ||
hostingLoc := resp.GeoLite.Country | ||
geop := resp.GeoPrecision | ||
if geop.Exists { | ||
if hostingLoc != geop.Country { | ||
comments = append(comments, fmt.Sprintf("hosting_country=[%s] actual_country=[%s]", hostingLoc, geop.Country)) | ||
} | ||
} | ||
if resp.Devices.Estimate >= 25 && !resp.IsMobile() { | ||
comments = append(comments, fmt.Sprintf("estimate_devices=[%d] infra=[%s]", resp.Devices.Estimate, resp.Infrastructure)) | ||
} | ||
hasThreat := len(comments) != 0 | ||
|
||
if resp.IsFileSharing() { | ||
comments = append(comments, "file_sharing") | ||
} | ||
return provider.FraudCheckResponse{ | ||
ServiceName: p.String(), | ||
IP: resp.IP, | ||
Organization: resp.AS.Organization, | ||
ASNumber: resp.AS.Number, | ||
Country: resp.GeoLite.Country, | ||
City: resp.GeoLite.City, | ||
Latitude: resp.GeoPrecision.Point.Latitude, | ||
Longitude: resp.GeoPrecision.Point.Longitude, | ||
IsProxy: resp.IsProxy(), | ||
IsVPN: resp.IsVPN(), | ||
IsTor: resp.IsTor(), | ||
IsHosting: resp.IsHosting(), | ||
HasOtherThreat: hasThreat, | ||
ThreatComment: strings.Join(comments, " | "), | ||
}, nil | ||
} | ||
|
||
func (p SpurProvider) RawCheckIP(ipaddr string) (interface{}, error) { | ||
return p.client.DoContext(ipaddr) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,124 @@ | ||
package spur | ||
|
||
type Response struct { | ||
IP string `json:"ip"` | ||
Anonymous bool `json:"anonymous"` | ||
AS AS `json:"as"` | ||
Assignment Assignment `json:"assignment"` | ||
DeviceBehaviors DeviceBehaviors `json:"deviceBehaviors"` | ||
Devices Devices `json:"devices"` | ||
GeoLite GeoLite `json:"geoLite"` | ||
GeoPrecision GeoPrecision `json:"geoPrecision"` | ||
Infrastructure string `json:"infrastructure"` | ||
ProxiedTraffic ProxiedTraffic `json:"proxiedTraffic"` | ||
SimilarIPs SimilarIPs `json:"similarIPs"` | ||
VPNOperators VPNOperators `json:"VPNOperators"` | ||
WiFi WiFi `json:"wifi"` | ||
} | ||
|
||
func (r Response) IsProxy() bool { | ||
return r.ProxiedTraffic.Exists | ||
} | ||
|
||
func (r Response) IsVPN() bool { | ||
return r.VPNOperators.Exists | ||
} | ||
|
||
func (r Response) IsHosting() bool { | ||
return r.Infrastructure == "DATACENTER" | ||
} | ||
|
||
func (r Response) IsTor() bool { | ||
for _, v := range r.DeviceBehaviors.Behaviors { | ||
if v.Name == "TOR_PROXY_USER" { | ||
return true | ||
} | ||
} | ||
return false | ||
} | ||
|
||
func (r Response) IsMobile() bool { | ||
return r.Infrastructure == "MOBILE" | ||
} | ||
|
||
func (r Response) IsFileSharing() bool { | ||
for _, v := range r.DeviceBehaviors.Behaviors { | ||
if v.Name == "FILE_SHARING" { | ||
return true | ||
} | ||
} | ||
return false | ||
} | ||
|
||
type AS struct { | ||
Number int64 `json:"number"` | ||
Organization string `json:"organization"` | ||
} | ||
|
||
type Assignment struct { | ||
Exists bool `json:"exists"` | ||
LastTurnover string `json:"lastTurnover"` | ||
} | ||
|
||
type DeviceBehaviors struct { | ||
Exists bool `json:"exists"` | ||
Behaviors []Behavior `json:"behaviors"` | ||
} | ||
|
||
type Behavior struct { | ||
Name string `json:"name"` | ||
} | ||
|
||
type Devices struct { | ||
Estimate int64 `json:"estimate"` | ||
} | ||
|
||
type GeoLite struct { | ||
City string `json:"city"` | ||
Country string `json:"country"` | ||
State string `json:"state"` | ||
} | ||
|
||
type GeoPrecision struct { | ||
Exists bool `json:"exists"` | ||
City string `json:"city"` | ||
Country string `json:"country"` | ||
State string `json:"state"` | ||
Hash string `json:"hash"` | ||
Spread string `json:"spread"` | ||
Point Point `json:"point"` | ||
} | ||
|
||
type Point struct { | ||
Latitude float64 `json:"latitude"` | ||
Longitude float64 `json:"longitude"` | ||
Radius int64 `json:"radius"` | ||
} | ||
|
||
type ProxiedTraffic struct { | ||
Exists bool `json:"exists"` | ||
Proxies []Proxy `json:"proxies"` | ||
} | ||
|
||
type Proxy struct { | ||
Name string `json:"name"` | ||
Type string `json:"type"` | ||
} | ||
|
||
type SimilarIPs struct { | ||
Exists bool `json:"exists"` | ||
IPs []string `json:"ips"` | ||
} | ||
|
||
type VPNOperators struct { | ||
Exists bool `json:"exists"` | ||
Operators []Operator `json:"operators"` | ||
} | ||
|
||
type Operator struct { | ||
Name string `json:"name"` | ||
} | ||
|
||
type WiFi struct { | ||
Exists bool `json:"exists"` | ||
} |