2022-01-19 06:19:08 +00:00
package ipapi
import (
"context"
"fmt"
2024-01-23 21:16:22 +00:00
regexp "github.com/wasilibs/go-re2"
2022-08-30 16:41:12 +00:00
"io"
2022-03-10 06:22:24 +00:00
"net/http"
2022-01-19 06:19:08 +00:00
"strings"
2022-02-10 18:54:33 +00:00
"github.com/trufflesecurity/trufflehog/v3/pkg/common"
"github.com/trufflesecurity/trufflehog/v3/pkg/detectors"
"github.com/trufflesecurity/trufflehog/v3/pkg/pb/detectorspb"
2022-01-19 06:19:08 +00:00
)
type Scanner struct { }
2022-05-16 16:03:10 +00:00
// Ensure the Scanner satisfies the interface at compile time.
2022-01-19 06:19:08 +00:00
var _ detectors . Detector = ( * Scanner ) ( nil )
var (
client = common . SaneHttpClient ( )
2022-05-16 16:03:10 +00:00
// Make sure that your group is surrounded in boundary characters such as below to reduce false positives.
2022-01-19 06:19:08 +00:00
keyPat = regexp . MustCompile ( detectors . PrefixRegex ( [ ] string { "ipapi" } ) + ` \b([a-z0-9] { 32})\b ` )
)
// Keywords are used for efficiently pre-filtering chunks.
// Use identifiers in the secret preferably, or the provider name.
func ( s Scanner ) Keywords ( ) [ ] string {
return [ ] string { "ipapi" }
}
// FromData will find and optionally verify Ipapi secrets in a given set of bytes.
func ( s Scanner ) FromData ( ctx context . Context , verify bool , data [ ] byte ) ( results [ ] detectors . Result , err error ) {
dataStr := string ( data )
matches := keyPat . FindAllStringSubmatch ( dataStr , - 1 )
for _ , match := range matches {
if len ( match ) != 2 {
continue
}
resMatch := strings . TrimSpace ( match [ 1 ] )
s1 := detectors . Result {
DetectorType : detectorspb . DetectorType_Ipapi ,
Raw : [ ] byte ( resMatch ) ,
}
if verify {
2022-03-23 23:42:34 +00:00
req , err := http . NewRequestWithContext ( ctx , "GET" , fmt . Sprintf ( "https://api.ipapi.com/49.146.239.251?access_key=%s" , resMatch ) , nil )
if err != nil {
continue
}
2022-01-19 06:19:08 +00:00
res , err := client . Do ( req )
if err == nil {
2022-08-30 16:41:12 +00:00
bodyBytes , err := io . ReadAll ( res . Body )
2022-01-19 06:19:08 +00:00
if err == nil {
bodyString := string ( bodyBytes )
2022-04-03 18:20:09 +00:00
valid := strings . Contains ( bodyString , "continent_code" ) || strings . Contains ( bodyString , ` "info":"Access Restricted - Your current Subscription Plan does not support HTTPS Encryption." ` )
2022-01-19 06:19:08 +00:00
defer res . Body . Close ( )
if res . StatusCode >= 200 && res . StatusCode < 300 {
if valid {
s1 . Verified = true
} else {
s1 . Verified = false
}
} else {
2022-05-16 16:03:10 +00:00
// This function will check false positives for common test words, but also it will make sure the key appears 'random' enough to be a real key.
2022-01-19 06:19:08 +00:00
if detectors . IsKnownFalsePositive ( resMatch , detectors . DefaultFalsePositives , true ) {
continue
}
}
}
}
}
results = append ( results , s1 )
}
2022-10-31 16:36:10 +00:00
return results , nil
2022-01-19 06:19:08 +00:00
}
2023-02-09 22:46:03 +00:00
func ( s Scanner ) Type ( ) detectorspb . DetectorType {
return detectorspb . DetectorType_Ipapi
}