Skip to content

Commit cc50239

Browse files
authored
Revert "Improved and fixed copper detector (#4394)" (#4470)
This reverts commit 810fcef.
1 parent bd45a70 commit cc50239

File tree

3 files changed

+66
-82
lines changed

3 files changed

+66
-82
lines changed

pkg/detectors/copper/copper.go

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

33
import (
44
"context"
5-
"fmt"
6-
"io"
75
"net/http"
6+
"strings"
87

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

@@ -24,18 +23,10 @@ var (
2423
client = common.SaneHttpClient()
2524

2625
// Make sure that your group is surrounded in boundary characters such as below to reduce false positives.
27-
emailPat = regexp.MustCompile(common.EmailPattern)
28-
keyPat = regexp.MustCompile(detectors.PrefixRegex([]string{"copper"}) + `\b([a-f0-9]{32})\b`)
26+
keyPat = regexp.MustCompile(detectors.PrefixRegex([]string{"copper"}) + `\b([a-z0-9]{32})\b`)
27+
idPat = regexp.MustCompile(`\b([a-z0-9]{4,25}@[a-zA-Z0-9]{2,12}.[a-zA-Z0-9]{2,6})\b`)
2928
)
3029

31-
func (s Scanner) Type() detectorspb.DetectorType {
32-
return detectorspb.DetectorType_Copper
33-
}
34-
35-
func (s Scanner) Description() string {
36-
return "Copper is a CRM platform that helps businesses manage their relationships with customers and leads. Copper API keys can be used to access and modify customer data and interactions."
37-
}
38-
3930
// Keywords are used for efficiently pre-filtering chunks.
4031
// Use identifiers in the secret preferably, or the provider name.
4132
func (s Scanner) Keywords() []string {
@@ -46,28 +37,41 @@ func (s Scanner) Keywords() []string {
4637
func (s Scanner) FromData(ctx context.Context, verify bool, data []byte) (results []detectors.Result, err error) {
4738
dataStr := string(data)
4839

49-
var emails, apiKeys = make(map[string]struct{}), make(map[string]struct{})
40+
matches := keyPat.FindAllStringSubmatch(dataStr, -1)
41+
idmatches := idPat.FindAllStringSubmatch(dataStr, -1)
5042

51-
for _, match := range emailPat.FindAllStringSubmatch(dataStr, -1) {
52-
emails[match[1]] = struct{}{}
53-
}
54-
55-
for _, match := range keyPat.FindAllStringSubmatch(dataStr, -1) {
56-
apiKeys[match[1]] = struct{}{}
57-
}
43+
for _, match := range matches {
44+
resMatch := strings.TrimSpace(match[1])
45+
for _, idmatch := range idmatches {
46+
resIdMatch := strings.TrimSpace(idmatch[1])
5847

59-
for email := range emails {
60-
for apiKey := range apiKeys {
6148
s1 := detectors.Result{
6249
DetectorType: detectorspb.DetectorType_Copper,
63-
Raw: []byte(apiKey),
64-
RawV2: []byte(apiKey + email),
50+
Raw: []byte(resMatch),
51+
RawV2: []byte(resMatch + resIdMatch),
6552
}
6653

6754
if verify {
68-
isVerified, verificationErr := verifyCopper(ctx, client, email, apiKey)
69-
s1.Verified = isVerified
70-
s1.SetVerificationError(verificationErr, apiKey)
55+
56+
payload := strings.NewReader(`{
57+
"page_size": 25,
58+
"sort_by": "name"
59+
}`)
60+
req, err := http.NewRequestWithContext(ctx, "POST", "https://api.copper.com/developer_api/v1/tasks/search", payload)
61+
if err != nil {
62+
continue
63+
}
64+
req.Header.Add("X-PW-AccessToken", resMatch)
65+
req.Header.Add("X-PW-Application", "developer_api")
66+
req.Header.Add("X-PW-UserEmail", resIdMatch)
67+
req.Header.Add("Content-Type", "application/json")
68+
res, err := client.Do(req)
69+
if err == nil {
70+
defer res.Body.Close()
71+
if res.StatusCode >= 200 && res.StatusCode < 300 {
72+
s1.Verified = true
73+
}
74+
}
7175
}
7276

7377
results = append(results, s1)
@@ -79,33 +83,10 @@ func (s Scanner) FromData(ctx context.Context, verify bool, data []byte) (result
7983
return results, nil
8084
}
8185

82-
func verifyCopper(ctx context.Context, client *http.Client, emailID, apiKey string) (bool, error) {
83-
req, err := http.NewRequestWithContext(ctx, http.MethodGet, "https://api.copper.com/developer_api/v1/account", http.NoBody)
84-
if err != nil {
85-
return false, err
86-
}
87-
88-
req.Header.Add("X-PW-AccessToken", apiKey)
89-
req.Header.Add("X-PW-Application", "developer_api")
90-
req.Header.Add("X-PW-UserEmail", emailID)
91-
req.Header.Add("Content-Type", "application/json")
92-
93-
resp, err := client.Do(req)
94-
if err != nil {
95-
return false, err
96-
}
86+
func (s Scanner) Type() detectorspb.DetectorType {
87+
return detectorspb.DetectorType_Copper
88+
}
9789

98-
defer func() {
99-
_, _ = io.Copy(io.Discard, resp.Body)
100-
_ = resp.Body.Close()
101-
}()
102-
103-
switch resp.StatusCode {
104-
case http.StatusOK:
105-
return true, nil
106-
case http.StatusUnauthorized:
107-
return false, nil
108-
default:
109-
return false, fmt.Errorf("unexpected status code: %d", resp.StatusCode)
110-
}
90+
func (s Scanner) Description() string {
91+
return "Copper is a CRM platform that helps businesses manage their relationships with customers and leads. Copper API keys can be used to access and modify customer data and interactions."
11192
}

pkg/detectors/copper/copper_integration_test.go

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@ import (
99
"testing"
1010
"time"
1111

12-
"github.com/google/go-cmp/cmp"
13-
"github.com/google/go-cmp/cmp/cmpopts"
12+
"github.com/kylelemons/godebug/pretty"
13+
1414
"github.com/trufflesecurity/trufflehog/v3/pkg/common"
1515
"github.com/trufflesecurity/trufflehog/v3/pkg/detectors"
1616
"github.com/trufflesecurity/trufflehog/v3/pkg/pb/detectorspb"
@@ -96,11 +96,9 @@ func TestCopper_FromChunk(t *testing.T) {
9696
t.Fatalf("no raw secret present: \n %+v", got[i])
9797
}
9898
got[i].Raw = nil
99-
got[i].RawV2 = nil
10099
}
101-
ignoreOpts := cmpopts.IgnoreFields(detectors.Result{}, "Raw", "RawV2", "verificationError", "primarySecret")
102-
if diff := cmp.Diff(got, tt.want, ignoreOpts); diff != "" {
103-
t.Errorf("Abstract.FromData() %s diff: (-got +want)\n%s", tt.name, diff)
100+
if diff := pretty.Compare(got, tt.want); diff != "" {
101+
t.Errorf("Copper.FromData() %s diff: (-got +want)\n%s", tt.name, diff)
104102
}
105103
})
106104
}

pkg/detectors/copper/copper_test.go

Lines changed: 26 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,29 @@ 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+
auth_type: ""
24+
in: "Header"
25+
copper_email: "s0ovh@P8I~p3"
26+
copper_token: "noqs39jzqaegbam2k6mai9ov1uwsl21y"
27+
base_url: "https://api.example.com/v1/user"
28+
29+
# Notes:
30+
# - Remember to rotate the secret every 90 days.
31+
# - The above credentials should only be used in a secure environment.
32+
`
33+
secret = "noqs39jzqaegbam2k6mai9ov1uwsl21ys0ovh@P8I~p3"
34+
)
35+
1336
func TestCopper_Pattern(t *testing.T) {
1437
d := Scanner{}
1538
ahoCorasickCore := ahocorasick.NewAhoCorasickCore([]detectors.Detector{d})
@@ -20,27 +43,9 @@ func TestCopper_Pattern(t *testing.T) {
2043
want []string
2144
}{
2245
{
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-
auth_type: ""
34-
in: "Header"
35-
36-
copper_token: "1affa0d5966556307efd91046e87fe2f"
37-
base_url: "https://api.example.com/v1/user"
38-
39-
# Notes:
40-
# - Remember to rotate the secret every 90 days.
41-
# - The above credentials should only be used in a secure environment.
42-
`,
43-
want: []string{"[email protected]"},
46+
name: "valid pattern",
47+
input: validPattern,
48+
want: []string{secret},
4449
},
4550
}
4651

0 commit comments

Comments
 (0)