@@ -2,9 +2,8 @@ package copper
22
33import (
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.
4132func (s Scanner ) Keywords () []string {
@@ -46,28 +37,41 @@ func (s Scanner) Keywords() []string {
4637func (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}
0 commit comments