diff --git a/pkg/detectors/bitlyaccesstoken/bitlyaccesstoken.go b/pkg/detectors/bitlyaccesstoken/bitlyaccesstoken.go index 4f80d46d9..acb2eec3c 100644 --- a/pkg/detectors/bitlyaccesstoken/bitlyaccesstoken.go +++ b/pkg/detectors/bitlyaccesstoken/bitlyaccesstoken.go @@ -3,8 +3,8 @@ package bitlyaccesstoken import ( "context" "fmt" + "io" "net/http" - "strings" regexp "github.com/wasilibs/go-re2" @@ -35,29 +35,22 @@ 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) + var uniqueTokens = make(map[string]struct{}) - for _, match := range matches { - resMatch := strings.TrimSpace(match[1]) + for _, matches := range keyPat.FindAllStringSubmatch(dataStr, -1) { + uniqueTokens[matches[1]] = struct{}{} + } + for token := range uniqueTokens { s1 := detectors.Result{ DetectorType: detectorspb.DetectorType_BitLyAccessToken, - Raw: []byte(resMatch), + Raw: []byte(token), } if verify { - req, err := http.NewRequestWithContext(ctx, "GET", "https://api-ssl.bitly.com/v4/user", nil) - if err != nil { - continue - } - req.Header.Add("Authorization", fmt.Sprintf("Bearer %s", resMatch)) - res, err := client.Do(req) - if err == nil { - defer res.Body.Close() - if res.StatusCode >= 200 && res.StatusCode < 300 { - s1.Verified = true - } - } + isVerified, verificationErr := verifyBitlyAccessToken(ctx, client, token) + s1.Verified = isVerified + s1.SetVerificationError(verificationErr) } results = append(results, s1) @@ -73,3 +66,31 @@ func (s Scanner) Type() detectorspb.DetectorType { func (s Scanner) Description() string { return "Bitly is a URL shortening service. Bitly access tokens can be used to interact with the Bitly API, allowing users to create, manage, and track shortened URLs." } + +func verifyBitlyAccessToken(ctx context.Context, client *http.Client, token string) (bool, error) { + req, err := http.NewRequestWithContext(ctx, http.MethodGet, "https://api-ssl.bitly.com/v4/user", nil) + if err != nil { + return false, err + } + + req.Header.Add("Authorization", fmt.Sprintf("Bearer %s", token)) + + resp, err := client.Do(req) + if err != nil { + return false, err + } + + defer func() { + _, _ = io.Copy(io.Discard, resp.Body) + _ = resp.Body.Close() + }() + + switch resp.StatusCode { + case http.StatusOK: + return true, nil + case http.StatusUnauthorized, http.StatusForbidden: + return false, nil + default: + return false, fmt.Errorf("unexpected status code: %d", resp.StatusCode) + } +}