Skip to content

Commit 8e5ef0f

Browse files
Added support for indeterminate verification for letter B detectors (#4049)
* first 10 detectors * more detectors --------- Co-authored-by: Nabeel Alam <[email protected]>
1 parent b73fa5f commit 8e5ef0f

File tree

31 files changed

+1062
-495
lines changed

31 files changed

+1062
-495
lines changed

pkg/detectors/bannerbear/bannerbear.go

Lines changed: 33 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package bannerbear
33
import (
44
"context"
55
"fmt"
6+
"io"
67
"net/http"
78
"strings"
89

@@ -46,18 +47,9 @@ func (s Scanner) FromData(ctx context.Context, verify bool, data []byte) (result
4647
}
4748

4849
if verify {
49-
req, err := http.NewRequestWithContext(ctx, "GET", "https://api.bannerbear.com/v2/auth", nil)
50-
if err != nil {
51-
continue
52-
}
53-
req.Header.Add("Authorization", fmt.Sprintf("Bearer %s", resMatch))
54-
res, err := client.Do(req)
55-
if err == nil {
56-
defer res.Body.Close()
57-
if res.StatusCode >= 200 && res.StatusCode < 300 {
58-
s1.Verified = true
59-
}
60-
}
50+
isVerified, verificationErr := verifyBannerBear(ctx, client, resMatch)
51+
s1.Verified = isVerified
52+
s1.SetVerificationError(verificationErr, resMatch)
6153
}
6254

6355
results = append(results, s1)
@@ -73,3 +65,32 @@ func (s Scanner) Type() detectorspb.DetectorType {
7365
func (s Scanner) Description() string {
7466
return "Bannerbear is an API for generating dynamic images, videos, and GIFs. Bannerbear API keys can be used to access and manipulate these resources."
7567
}
68+
69+
// docs: https://developers.bannerbear.com/
70+
func verifyBannerBear(ctx context.Context, client *http.Client, key string) (bool, error) {
71+
req, err := http.NewRequestWithContext(ctx, "GET", "https://api.bannerbear.com/v2/auth", http.NoBody)
72+
if err != nil {
73+
return false, err
74+
}
75+
76+
req.Header.Add("Authorization", fmt.Sprintf("Bearer %s", key))
77+
78+
resp, err := client.Do(req)
79+
if err != nil {
80+
return false, nil
81+
}
82+
83+
defer func() {
84+
_, _ = io.Copy(io.Discard, resp.Body)
85+
_ = resp.Body.Close()
86+
}()
87+
88+
switch resp.StatusCode {
89+
case http.StatusOK:
90+
return true, nil
91+
case http.StatusUnauthorized:
92+
return false, nil
93+
default:
94+
return false, fmt.Errorf("unexpected status code: %d", resp.StatusCode)
95+
}
96+
}

pkg/detectors/baremetrics/baremetrics.go

Lines changed: 33 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package baremetrics
33
import (
44
"context"
55
"fmt"
6+
"io"
67
"net/http"
78
"strings"
89

@@ -52,18 +53,9 @@ func (s Scanner) FromData(ctx context.Context, verify bool, data []byte) (result
5253
}
5354

5455
if verify {
55-
req, err := http.NewRequestWithContext(ctx, "GET", "https://api.baremetrics.com/v1/account", nil)
56-
if err != nil {
57-
continue
58-
}
59-
req.Header.Add("Authorization", fmt.Sprintf("Bearer %s", resMatch))
60-
res, err := client.Do(req)
61-
if err == nil {
62-
defer res.Body.Close()
63-
if res.StatusCode >= 200 && res.StatusCode < 300 {
64-
s1.Verified = true
65-
}
66-
}
56+
isVerified, verificationErr := verifyBaremetrics(ctx, client, resMatch)
57+
s1.Verified = isVerified
58+
s1.SetVerificationError(verificationErr, resMatch)
6759
}
6860

6961
results = append(results, s1)
@@ -79,3 +71,32 @@ func (s Scanner) Type() detectorspb.DetectorType {
7971
func (s Scanner) Description() string {
8072
return "Baremetrics is a subscription analytics and insights tool. Baremetrics API keys can be used to access and analyze subscription data."
8173
}
74+
75+
// docs: https://developers.baremetrics.com/reference/authentication
76+
func verifyBaremetrics(ctx context.Context, client *http.Client, key string) (bool, error) {
77+
req, err := http.NewRequestWithContext(ctx, "GET", "https://api.baremetrics.com/v1/account", http.NoBody)
78+
if err != nil {
79+
return false, err
80+
}
81+
82+
req.Header.Add("Authorization", fmt.Sprintf("Bearer %s", key))
83+
84+
resp, err := client.Do(req)
85+
if err != nil {
86+
return false, nil
87+
}
88+
89+
defer func() {
90+
_, _ = io.Copy(io.Discard, resp.Body)
91+
_ = resp.Body.Close()
92+
}()
93+
94+
switch resp.StatusCode {
95+
case http.StatusOK:
96+
return true, nil
97+
case http.StatusUnauthorized:
98+
return false, nil
99+
default:
100+
return false, fmt.Errorf("unexpected status code: %d", resp.StatusCode)
101+
}
102+
}

pkg/detectors/beamer/beamer.go

Lines changed: 33 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ package beamer
22

33
import (
44
"context"
5+
"fmt"
6+
"io"
57
"net/http"
68
"strings"
79

@@ -45,18 +47,9 @@ func (s Scanner) FromData(ctx context.Context, verify bool, data []byte) (result
4547
}
4648

4749
if verify {
48-
req, err := http.NewRequestWithContext(ctx, "GET", "https://api.getbeamer.com/v0/url", nil)
49-
if err != nil {
50-
continue
51-
}
52-
req.Header.Add("Beamer-Api-Key", resMatch)
53-
res, err := client.Do(req)
54-
if err == nil {
55-
defer res.Body.Close()
56-
if res.StatusCode >= 200 && res.StatusCode < 300 {
57-
s1.Verified = true
58-
}
59-
}
50+
isVerified, verificationErr := verifyBeamer(ctx, client, resMatch)
51+
s1.Verified = isVerified
52+
s1.SetVerificationError(verificationErr, resMatch)
6053
}
6154

6255
results = append(results, s1)
@@ -72,3 +65,31 @@ func (s Scanner) Type() detectorspb.DetectorType {
7265
func (s Scanner) Description() string {
7366
return "Beamer is a user engagement platform that helps you communicate product updates and other important information to your users. Beamer API keys can be used to access and manage this information."
7467
}
68+
69+
func verifyBeamer(ctx context.Context, client *http.Client, key string) (bool, error) {
70+
req, err := http.NewRequestWithContext(ctx, "GET", "https://api.getbeamer.com/v0/url", http.NoBody)
71+
if err != nil {
72+
return false, err
73+
}
74+
75+
req.Header.Add("Beamer-Api-Key", key)
76+
77+
resp, err := client.Do(req)
78+
if err != nil {
79+
return false, err
80+
}
81+
82+
defer func() {
83+
_, _ = io.Copy(io.Discard, resp.Body)
84+
_ = resp.Body.Close()
85+
}()
86+
87+
switch resp.StatusCode {
88+
case http.StatusOK:
89+
return true, nil
90+
case http.StatusUnauthorized:
91+
return false, nil
92+
default:
93+
return false, fmt.Errorf("unexpected status code: %d", resp.StatusCode)
94+
}
95+
}

pkg/detectors/beebole/beebole.go

Lines changed: 36 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@ package beebole
22

33
import (
44
"context"
5-
b64 "encoding/base64"
65
"fmt"
6+
"io"
77
"net/http"
88
"strings"
99

@@ -47,22 +47,9 @@ func (s Scanner) FromData(ctx context.Context, verify bool, data []byte) (result
4747
}
4848

4949
if verify {
50-
data := fmt.Sprintf("%s:X", resMatch)
51-
sEnc := b64.StdEncoding.EncodeToString([]byte(data))
52-
payload := strings.NewReader(`{"service": "custom_field.list"}`)
53-
req, err := http.NewRequestWithContext(ctx, "POST", "https://beebole-apps.com/api/v2", payload)
54-
if err != nil {
55-
continue
56-
}
57-
req.Header.Add("Content-Type", "application/json")
58-
req.Header.Add("Authorization", fmt.Sprintf("Basic %s", sEnc))
59-
res, err := client.Do(req)
60-
if err == nil {
61-
defer res.Body.Close()
62-
if res.StatusCode >= 200 && res.StatusCode < 300 {
63-
s1.Verified = true
64-
}
65-
}
50+
isVerified, verificationErr := verifyBeebole(ctx, client, resMatch)
51+
s1.Verified = isVerified
52+
s1.SetVerificationError(verificationErr, resMatch)
6653
}
6754

6855
results = append(results, s1)
@@ -78,3 +65,35 @@ func (s Scanner) Type() detectorspb.DetectorType {
7865
func (s Scanner) Description() string {
7966
return "Beebole is a time tracking and business management tool. Beebole API keys can be used to access and manage time tracking data and other business-related information."
8067
}
68+
69+
// docs: https://beebole.com/help/api/
70+
func verifyBeebole(ctx context.Context, client *http.Client, key string) (bool, error) {
71+
payload := strings.NewReader(`{"service": "custom_field.list"}`)
72+
73+
req, err := http.NewRequestWithContext(ctx, "POST", "https://beebole-apps.com/api/v2", payload)
74+
if err != nil {
75+
return false, err
76+
}
77+
78+
req.Header.Add("Content-Type", "application/json")
79+
req.SetBasicAuth(key, "x")
80+
81+
resp, err := client.Do(req)
82+
if err != nil {
83+
return false, err
84+
}
85+
86+
defer func() {
87+
_, _ = io.Copy(io.Discard, resp.Body)
88+
_ = resp.Body.Close()
89+
}()
90+
91+
switch resp.StatusCode {
92+
case http.StatusOK:
93+
return true, nil
94+
case http.StatusUnauthorized:
95+
return false, nil
96+
default:
97+
return false, fmt.Errorf("unexpected status code: %d", resp.StatusCode)
98+
}
99+
}

pkg/detectors/besnappy/besnappy.go

Lines changed: 33 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@ package besnappy
22

33
import (
44
"context"
5-
b64 "encoding/base64"
65
"fmt"
6+
"io"
77
"net/http"
88
"strings"
99

@@ -46,20 +46,9 @@ func (s Scanner) FromData(ctx context.Context, verify bool, data []byte) (result
4646
Raw: []byte(resMatch),
4747
}
4848
if verify {
49-
data := fmt.Sprintf("%s:x", resMatch)
50-
sEnc := b64.StdEncoding.EncodeToString([]byte(data))
51-
req, err := http.NewRequestWithContext(ctx, "GET", "https://app.besnappy.com/api/v1/accounts", nil)
52-
if err != nil {
53-
continue
54-
}
55-
req.Header.Add("Authorization", fmt.Sprintf("Basic %s", sEnc))
56-
res, err := client.Do(req)
57-
if err == nil {
58-
defer res.Body.Close()
59-
if res.StatusCode >= 200 && res.StatusCode < 300 {
60-
s1.Verified = true
61-
}
62-
}
49+
isVerified, verificationErr := verifyBesnappy(ctx, client, resMatch)
50+
s1.Verified = isVerified
51+
s1.SetVerificationError(verificationErr, resMatch)
6352
}
6453

6554
results = append(results, s1)
@@ -75,3 +64,32 @@ func (s Scanner) Type() detectorspb.DetectorType {
7564
func (s Scanner) Description() string {
7665
return "Besnappy is a customer service platform. The detected key can be used to access Besnappy's API, potentially exposing sensitive customer service data."
7766
}
67+
68+
// docs: https://github.com/BeSnappy/api-docs
69+
func verifyBesnappy(ctx context.Context, client *http.Client, key string) (bool, error) {
70+
req, err := http.NewRequestWithContext(ctx, "GET", "https://app.besnappy.com/api/v1/accounts", http.NoBody)
71+
if err != nil {
72+
return false, err
73+
}
74+
75+
req.SetBasicAuth(key, "x")
76+
77+
resp, err := client.Do(req)
78+
if err != nil {
79+
return false, err
80+
}
81+
82+
defer func() {
83+
_, _ = io.Copy(io.Discard, resp.Body)
84+
_ = resp.Body.Close()
85+
}()
86+
87+
switch resp.StatusCode {
88+
case http.StatusOK:
89+
return true, nil
90+
case http.StatusUnauthorized:
91+
return false, nil
92+
default:
93+
return false, fmt.Errorf("unexpected status code: %d", resp.StatusCode)
94+
}
95+
}

0 commit comments

Comments
 (0)