Skip to content

Commit

Permalink
fix(fetchrss): update detector logic (#2844)
Browse files Browse the repository at this point in the history
  • Loading branch information
rgmz authored Nov 7, 2024
1 parent 6c823e1 commit afe25cf
Showing 1 changed file with 67 additions and 29 deletions.
96 changes: 67 additions & 29 deletions pkg/detectors/fetchrss/fetchrss.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,26 +2,30 @@ package fetchrss

import (
"context"
regexp "github.com/wasilibs/go-re2"
"encoding/json"
"fmt"
"io"
"net/http"
"strings"

regexp "github.com/wasilibs/go-re2"

"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{}
type Scanner struct {
client *http.Client
}

// Ensure the Scanner satisfies the interface at compile time.
var _ detectors.Detector = (*Scanner)(nil)

var (
client = common.SaneHttpClient()
defaultClient = common.SaneHttpClient()

// Make sure that your group is surrounded in boundary characters such as below to reduce false positives.
keyPat = regexp.MustCompile(detectors.PrefixRegex([]string{"fetchrss"}) + `\b([0-9A-Za-z.]{40})\b`)
keyPat = regexp.MustCompile(detectors.PrefixRegex([]string{"fetchrss"}) + `\b([a-zA-Z0-9.]{40})\b`)
)

// Keywords are used for efficiently pre-filtering chunks.
Expand All @@ -34,37 +38,26 @@ func (s Scanner) Keywords() []string {
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])
uniqueMatches := make(map[string]struct{})
for _, match := range keyPat.FindAllStringSubmatch(dataStr, -1) {
uniqueMatches[match[1]] = struct{}{}
}

for token := range uniqueMatches {
s1 := detectors.Result{
DetectorType: detectorspb.DetectorType_Fetchrss,
Raw: []byte(resMatch),
Raw: []byte(token),
}

if verify {
req, err := http.NewRequestWithContext(ctx, "GET", "https://fetchrss.com/api/v1/feed/list?auth="+resMatch, nil)
if err != nil {
continue
}
res, err := client.Do(req)
if err == nil {
defer res.Body.Close()
bodyBytes, err := io.ReadAll(res.Body)
if err != nil {
continue
}
body := string(bodyBytes)

if !strings.Contains(body, "Not authorised") {
s1.Verified = true
}
client := s.client
if client == nil {
client = defaultClient
}

verified, verificationErr := verifyToken(ctx, client, token)
s1.Verified = verified
s1.SetVerificationError(verificationErr)
}

results = append(results, s1)
Expand All @@ -73,6 +66,51 @@ func (s Scanner) FromData(ctx context.Context, verify bool, data []byte) (result
return results, nil
}

func verifyToken(ctx context.Context, client *http.Client, token string) (bool, error) {
req, err := http.NewRequestWithContext(ctx, http.MethodGet, "https://fetchrss.com/api/v1/feed/list?auth="+token, nil)
if err != nil {
return false, err
}

res, err := client.Do(req)
if err != nil {
return false, err
}
defer func() {
_, _ = io.Copy(io.Discard, res.Body)
_ = res.Body.Close()
}()

// The API seems to always return a 200 status code.
// See: https://fetchrss.com/developers
if res.StatusCode != http.StatusOK {
return false, fmt.Errorf("unexpected HTTP response status %d", res.StatusCode)
}

var apiRes response
if err := json.NewDecoder(res.Body).Decode(&apiRes); err != nil {
return false, err
}

if apiRes.Success {
// The key is valid.
return true, nil
} else if apiRes.Error.Code == 401 {
// The key is invalid.
return false, nil
} else {
return false, fmt.Errorf("unexpected error: [code=%d, message=%s]", apiRes.Error.Code, apiRes.Error.Message)
}
}

type response struct {
Success bool `json:"success"`
Error struct {
Message string `json:"message"`
Code int `json:"code"`
} `json:"error"`
}

func (s Scanner) Type() detectorspb.DetectorType {
return detectorspb.DetectorType_Fetchrss
}
Expand Down

0 comments on commit afe25cf

Please sign in to comment.