* Add Type() to detector interface The goal here is to allow the detector type information to be used without the need for reflection. This could possibly allow us to more easily inject information into detectors or filter them out if necessary. Co-authored-by: ahmed <[email protected]> * remove test detector --------- Co-authored-by: ahmed <[email protected]>
100 lines
2.7 KiB
Go
100 lines
2.7 KiB
Go
package squareapp
|
|
|
|
import (
|
|
"bytes"
|
|
"context"
|
|
"encoding/json"
|
|
"fmt"
|
|
"net/http"
|
|
"regexp"
|
|
"strings"
|
|
|
|
"github.com/trufflesecurity/trufflehog/v3/pkg/common"
|
|
"github.com/trufflesecurity/trufflehog/v3/pkg/detectors"
|
|
"github.com/trufflesecurity/trufflehog/v3/pkg/pb/detectorspb"
|
|
)
|
|
|
|
type Scanner struct{}
|
|
|
|
// Ensure the Scanner satisfies the interface at compile time.
|
|
var _ detectors.Detector = (*Scanner)(nil)
|
|
|
|
var (
|
|
//possibly always `sq0csp` for secret
|
|
// and `sq0idb` for app
|
|
keyPat = regexp.MustCompile(`[\w\-]*sq0i[a-z]{2}-[0-9A-Za-z\-_]{22,43}`)
|
|
secPat = regexp.MustCompile(`[\w\-]*sq0c[a-z]{2}-[0-9A-Za-z\-_]{40,50}`)
|
|
)
|
|
|
|
// 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{"sq0i"}
|
|
}
|
|
|
|
// FromData will find and optionally verify SquareApp 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.FindAllString(dataStr, -1)
|
|
secMatches := secPat.FindAllString(dataStr, -1)
|
|
for _, match := range matches {
|
|
|
|
for _, secMatch := range secMatches {
|
|
|
|
if detectors.IsKnownFalsePositive(strings.ToLower(secMatch), detectors.DefaultFalsePositives, true) {
|
|
continue
|
|
}
|
|
|
|
s := detectors.Result{
|
|
DetectorType: detectorspb.DetectorType_Square,
|
|
Raw: []byte(match),
|
|
Redacted: match,
|
|
}
|
|
|
|
if verify {
|
|
baseURL := "https://connect.squareupsandbox.com/oauth2/revoke"
|
|
|
|
client := common.SaneHttpClient()
|
|
reqData, err := json.Marshal(map[string]string{
|
|
"client_id": match,
|
|
"access_token": "fakeTruffleHogAccessTokenForVerification",
|
|
})
|
|
if err != nil {
|
|
return results, err
|
|
}
|
|
|
|
req, err := http.NewRequestWithContext(ctx, "POST", baseURL, bytes.NewReader(reqData))
|
|
if err != nil {
|
|
continue
|
|
}
|
|
req.Header.Add("Authorization", fmt.Sprintf("Client %s", secMatch))
|
|
req.Header.Add("Content-Type", "application/json")
|
|
|
|
// unclear if this version needs to be set or matters, seems to work without, but docs want it
|
|
//req.Header.Add("Square-Version", "2020-08-12")
|
|
res, err := client.Do(req)
|
|
if err == nil {
|
|
res.Body.Close() // The request body is unused.
|
|
|
|
// 404 = Correct credentials. The fake access token should not be found.
|
|
if res.StatusCode == http.StatusNotFound {
|
|
s.Verified = true
|
|
}
|
|
}
|
|
}
|
|
|
|
if !s.Verified && detectors.IsKnownFalsePositive(string(s.Raw), detectors.DefaultFalsePositives, true) {
|
|
continue
|
|
}
|
|
|
|
results = append(results, s)
|
|
}
|
|
}
|
|
return
|
|
}
|
|
|
|
func (s Scanner) Type() detectorspb.DetectorType {
|
|
return detectorspb.DetectorType_Square
|
|
}
|