Skip to content

Commit d287246

Browse files
Refactored caflou detector (#4372)
1 parent eb908bd commit d287246

File tree

2 files changed

+56
-42
lines changed

2 files changed

+56
-42
lines changed

pkg/detectors/caflou/caflou.go

Lines changed: 37 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package caflou
33
import (
44
"context"
55
"fmt"
6+
"io"
67
"net/http"
78
"strings"
89
"time"
@@ -25,7 +26,7 @@ var (
2526
defaultClient = common.SaneHttpClientTimeOut(time.Second * 10)
2627

2728
// Make sure that your group is surrounded in boundary characters such as below to reduce false positives.
28-
keyPat = regexp.MustCompile(detectors.PrefixRegex([]string{"caflou"}) + `\b([a-bA-Z0-9\S]{155})\b`)
29+
keyPat = regexp.MustCompile(`\b(eyJhbGciOiJIUzI1NiJ9[a-zA-Z0-9._-]{135})\b`)
2930
)
3031

3132
// Keywords are used for efficiently pre-filtering chunks.
@@ -34,6 +35,14 @@ func (s Scanner) Keywords() []string {
3435
return []string{"caflou"}
3536
}
3637

38+
func (s Scanner) Type() detectorspb.DetectorType {
39+
return detectorspb.DetectorType_Caflou
40+
}
41+
42+
func (s Scanner) Description() string {
43+
return "Caflou is a business management software used for managing projects, tasks, and finances. Caflou API keys can be used to access and modify this data."
44+
}
45+
3746
// FromData will find and optionally verify Caflou secrets in a given set of bytes.
3847
func (s Scanner) FromData(ctx context.Context, verify bool, data []byte) (results []detectors.Result, err error) {
3948
dataStr := string(data)
@@ -54,18 +63,9 @@ func (s Scanner) FromData(ctx context.Context, verify bool, data []byte) (result
5463
client = defaultClient
5564
}
5665

57-
req, err := http.NewRequestWithContext(ctx, "GET", "https://app.caflou.com/api/v1/accounts", nil)
58-
if err != nil {
59-
continue
60-
}
61-
req.Header.Add("Authorization", fmt.Sprintf("Bearer %s", resMatch))
62-
res, err := client.Do(req)
63-
if err == nil {
64-
defer res.Body.Close()
65-
if res.StatusCode >= 200 && res.StatusCode < 300 {
66-
s1.Verified = true
67-
}
68-
}
66+
isVerified, verificationErr := verifyCaflou(ctx, client, resMatch)
67+
s1.Verified = isVerified
68+
s1.SetVerificationError(verificationErr, resMatch)
6969
}
7070

7171
results = append(results, s1)
@@ -74,10 +74,29 @@ func (s Scanner) FromData(ctx context.Context, verify bool, data []byte) (result
7474
return results, nil
7575
}
7676

77-
func (s Scanner) Type() detectorspb.DetectorType {
78-
return detectorspb.DetectorType_Caflou
79-
}
77+
func verifyCaflou(ctx context.Context, client *http.Client, token string) (bool, error) {
78+
req, err := http.NewRequestWithContext(ctx, http.MethodGet, "https://app.caflou.com/api/v1/accounts", http.NoBody)
79+
if err != nil {
80+
return false, err
81+
}
8082

81-
func (s Scanner) Description() string {
82-
return "Caflou is a business management software used for managing projects, tasks, and finances. Caflou API keys can be used to access and modify this data."
83+
req.Header.Add("Authorization", fmt.Sprintf("Bearer %s", token))
84+
resp, err := client.Do(req)
85+
if err != nil {
86+
return false, err
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+
}
83102
}

pkg/detectors/caflou/caflou_test.go

Lines changed: 19 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -10,27 +10,6 @@ import (
1010
"github.com/trufflesecurity/trufflehog/v3/pkg/engine/ahocorasick"
1111
)
1212

13-
var (
14-
validPattern = `
15-
# Configuration File: config.yaml
16-
database:
17-
host: $DB_HOST
18-
port: $DB_PORT
19-
username: $DB_USERNAME
20-
password: $DB_PASS # IMPORTANT: Do not share this password publicly
21-
22-
api:
23-
base_url: "https://api.example.com/instances"
24-
api_key: $API_KEY
25-
caflou_auth_token: "Bearer b8SQoPKLMCBbwIm0XDzbZiDydUk9qNqqBlKnR5Nouwbjs9cv3D1azAXpiFq9WrfNlwxbCwDL2FWCheXmdYKZkMRZklahJh5NQZZY7Zf220hjGJOtKgFbWxy9xQ9hodQqsOOx9Of30qtTrnRxFPa9wxYkSBn"
26-
27-
# Notes:
28-
# - Remember to rotate the secret every 90 days.
29-
# - The above credentials should only be used in a secure environment.
30-
`
31-
secret = "b8SQoPKLMCBbwIm0XDzbZiDydUk9qNqqBlKnR5Nouwbjs9cv3D1azAXpiFq9WrfNlwxbCwDL2FWCheXmdYKZkMRZklahJh5NQZZY7Zf220hjGJOtKgFbWxy9xQ9hodQqsOOx9Of30qtTrnRxFPa9wxYkSBn"
32-
)
33-
3413
func TestCaflou_Pattern(t *testing.T) {
3514
d := Scanner{}
3615
ahoCorasickCore := ahocorasick.NewAhoCorasickCore([]detectors.Detector{d})
@@ -41,9 +20,25 @@ func TestCaflou_Pattern(t *testing.T) {
4120
want []string
4221
}{
4322
{
44-
name: "valid pattern",
45-
input: validPattern,
46-
want: []string{secret},
23+
name: "valid pattern",
24+
input: `
25+
# Configuration File: config.yaml
26+
database:
27+
host: $DB_HOST
28+
port: $DB_PORT
29+
username: $DB_USERNAME
30+
password: $DB_PASS # IMPORTANT: Do not share this password publicly
31+
32+
api:
33+
base_url: "https://api.example.com/instances"
34+
api_key: $API_KEY
35+
caflou_auth_token: "Bearer eyJhbGciOiJIUzI1NiJ9.eyJ1c2VyX9lkIjo1OTQ5MCwianCpIjoiOTQwZjBlODkxNPhhZjM4OTQ1OGQwMDIxIiziZXhwIjoxGzU1MTk4MDAwfQ.EMNGCPX7aNIvriX360oLFAgMwHeXxKD7N4kdcJtPqTI"
36+
37+
# Notes:
38+
# - Remember to rotate the secret every 90 days.
39+
# - The above credentials should only be used in a secure environment.
40+
`,
41+
want: []string{"eyJhbGciOiJIUzI1NiJ9.eyJ1c2VyX9lkIjo1OTQ5MCwianCpIjoiOTQwZjBlODkxNPhhZjM4OTQ1OGQwMDIxIiziZXhwIjoxGzU1MTk4MDAwfQ.EMNGCPX7aNIvriX360oLFAgMwHeXxKD7N4kdcJtPqTI"},
4742
},
4843
}
4944

0 commit comments

Comments
 (0)