@@ -11,26 +11,60 @@ import (
1111 "encoding/json"
1212 "fmt"
1313 "net/url"
14+ "strconv"
15+ "strings"
1416
1517 "github.com/TwoA2U/iocscan/internal/httpclient"
1618)
1719
1820const ipapiEndpoint = "https://api.ipapi.is"
1921
22+ type flexibleBool bool
23+
24+ func (b * flexibleBool ) UnmarshalJSON (data []byte ) error {
25+ var raw any
26+ if err := json .Unmarshal (data , & raw ); err != nil {
27+ return err
28+ }
29+
30+ switch v := raw .(type ) {
31+ case bool :
32+ * b = flexibleBool (v )
33+ case string :
34+ s := strings .TrimSpace (strings .ToLower (v ))
35+ if s == "" || s == "false" || s == "0" || s == "no" || s == "none" || s == "null" {
36+ * b = false
37+ return nil
38+ }
39+ if parsed , err := strconv .ParseBool (s ); err == nil {
40+ * b = flexibleBool (parsed )
41+ return nil
42+ }
43+ * b = true
44+ case float64 :
45+ * b = flexibleBool (v != 0 )
46+ case nil :
47+ * b = false
48+ default :
49+ * b = false
50+ }
51+ return nil
52+ }
53+
2054// IPAPIResponse is the raw response from ipapi.is.
2155type IPAPIResponse struct {
22- IP string `json:"ip"`
23- RIR string `json:"rir"`
24- IsBogon bool `json:"is_bogon"`
25- IsMobile bool `json:"is_mobile"`
26- IsSatellite bool `json:"is_satellite"`
27- IsCrawler bool `json:"is_crawler"`
28- IsDatacenter bool `json:"is_datacenter"`
29- IsTor bool `json:"is_tor"`
30- IsProxy bool `json:"is_proxy"`
31- IsVPN bool `json:"is_vpn"`
32- IsAbuser bool `json:"is_abuser"`
33- VPN struct {
56+ IP string `json:"ip"`
57+ RIR string `json:"rir"`
58+ IsBogon bool `json:"is_bogon"`
59+ IsMobile bool `json:"is_mobile"`
60+ IsSatellite bool `json:"is_satellite"`
61+ IsCrawler flexibleBool `json:"is_crawler"`
62+ IsDatacenter bool `json:"is_datacenter"`
63+ IsTor bool `json:"is_tor"`
64+ IsProxy bool `json:"is_proxy"`
65+ IsVPN bool `json:"is_vpn"`
66+ IsAbuser bool `json:"is_abuser"`
67+ VPN struct {
3468 Service string `json:"service"`
3569 Type string `json:"type"`
3670 LastSeenStr string `json:"last_seen_str"`
@@ -47,13 +81,13 @@ type IPAPIResponse struct {
4781 Org string `json:"org"`
4882 } `json:"asn"`
4983 Location struct {
50- Country string `json:"country"`
84+ Country string `json:"country"`
5185 CountryCode string `json:"country_code"`
52- State string `json:"state"`
53- City string `json:"city"`
54- Timezone string `json:"timezone"`
55- LocalTime string `json:"local_time"`
56- IsDST bool `json:"is_dst"`
86+ State string `json:"state"`
87+ City string `json:"city"`
88+ Timezone string `json:"timezone"`
89+ LocalTime string `json:"local_time"`
90+ IsDST bool `json:"is_dst"`
5791 } `json:"location"`
5892}
5993
@@ -186,28 +220,28 @@ func (i IPAPIIntegration) Run(ctx context.Context, ioc, apiKey string, useCache
186220
187221func ipapiToResult (r * IPAPIResponse ) * Result {
188222 return & Result {Fields : map [string ]any {
189- "country" : r .Location .Country ,
190- "city" : r .Location .City ,
191- "state" : r .Location .State ,
192- "timezone" : r .Location .Timezone ,
193- "localTime" : r .Location .LocalTime ,
194- "isDST" : r .Location .IsDST ,
195- "org" : r .ASN .Org ,
196- "companyName" : r .Company .Name ,
197- "companyType" : r .Company .Type ,
223+ "country" : r .Location .Country ,
224+ "city" : r .Location .City ,
225+ "state" : r .Location .State ,
226+ "timezone" : r .Location .Timezone ,
227+ "localTime" : r .Location .LocalTime ,
228+ "isDST" : r .Location .IsDST ,
229+ "org" : r .ASN .Org ,
230+ "companyName" : r .Company .Name ,
231+ "companyType" : r .Company .Type ,
198232 "companyDomain" : r .Company .Domain ,
199- "abuserScore" : r .Company .AbuserScore ,
200- "isBogon" : r .IsBogon ,
201- "isMobile" : r .IsMobile ,
202- "isSatellite" : r .IsSatellite ,
203- "isCrawler" : r .IsCrawler ,
204- "isDatacenter" : r .IsDatacenter ,
205- "isTor" : r .IsTor ,
206- "isProxy" : r .IsProxy ,
207- "isVPN" : r .IsVPN ,
208- "isAbuser" : r .IsAbuser ,
209- "vpnService" : r .VPN .Service ,
210- "vpnType" : r .VPN .Type ,
211- "vpnLastSeen" : r .VPN .LastSeenStr ,
233+ "abuserScore" : r .Company .AbuserScore ,
234+ "isBogon" : r .IsBogon ,
235+ "isMobile" : r .IsMobile ,
236+ "isSatellite" : r .IsSatellite ,
237+ "isCrawler" : bool ( r .IsCrawler ) ,
238+ "isDatacenter" : r .IsDatacenter ,
239+ "isTor" : r .IsTor ,
240+ "isProxy" : r .IsProxy ,
241+ "isVPN" : r .IsVPN ,
242+ "isAbuser" : r .IsAbuser ,
243+ "vpnService" : r .VPN .Service ,
244+ "vpnType" : r .VPN .Type ,
245+ "vpnLastSeen" : r .VPN .LastSeenStr ,
212246 }}
213247}
0 commit comments