@@ -3,9 +3,10 @@ package smartsheets
3
3
import (
4
4
"context"
5
5
"fmt"
6
- regexp "github.com/wasilibs/go-re2 "
6
+ "io "
7
7
"net/http"
8
- "strings"
8
+
9
+ regexp "github.com/wasilibs/go-re2"
9
10
10
11
"github.com/trufflesecurity/trufflehog/v3/pkg/common"
11
12
"github.com/trufflesecurity/trufflehog/v3/pkg/detectors"
@@ -21,42 +22,35 @@ var (
21
22
client = common .SaneHttpClient ()
22
23
23
24
// Make sure that your group is surrounded in boundary characters such as below to reduce false positives.
24
- keyPat = regexp .MustCompile (detectors .PrefixRegex ([]string {"smartsheets " }) + `\b([a-zA-Z0-9]{37})\b` )
25
+ keyPat = regexp .MustCompile (detectors .PrefixRegex ([]string {"sheet " }) + `\b([a-zA-Z0-9]{37})\b` )
25
26
)
26
27
27
28
// Keywords are used for efficiently pre-filtering chunks.
28
29
// Use identifiers in the secret preferably, or the provider name.
29
30
func (s Scanner ) Keywords () []string {
30
- return []string {"smartsheets " }
31
+ return []string {"smartsheet " }
31
32
}
32
33
33
34
// FromData will find and optionally verify Smartsheets secrets in a given set of bytes.
34
35
func (s Scanner ) FromData (ctx context.Context , verify bool , data []byte ) (results []detectors.Result , err error ) {
35
36
dataStr := string (data )
36
37
37
- matches := keyPat . FindAllStringSubmatch ( dataStr , - 1 )
38
+ var uniqueKeys = make ( map [ string ] struct {} )
38
39
39
- for _ , match := range matches {
40
- resMatch := strings .TrimSpace (match [1 ])
40
+ for _ , matche := range keyPat .FindAllStringSubmatch (dataStr , - 1 ) {
41
+ uniqueKeys [matche [1 ]] = struct {}{}
42
+ }
41
43
44
+ for key := range uniqueKeys {
42
45
s1 := detectors.Result {
43
46
DetectorType : detectorspb .DetectorType_Smartsheets ,
44
- Raw : []byte (resMatch ),
47
+ Raw : []byte (key ),
45
48
}
46
49
47
50
if verify {
48
- req , err := http .NewRequestWithContext (ctx , "GET" , "https://api.smartsheet.com/2.0/sheets" , nil )
49
- if err != nil {
50
- continue
51
- }
52
- req .Header .Add ("Authorization" , fmt .Sprintf ("Bearer %s" , 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
- }
51
+ isVerified , verificationErr := verifySmartSheetsToken (ctx , client , key )
52
+ s1 .Verified = isVerified
53
+ s1 .SetVerificationError (verificationErr )
60
54
}
61
55
62
56
results = append (results , s1 )
@@ -72,3 +66,31 @@ func (s Scanner) Type() detectorspb.DetectorType {
72
66
func (s Scanner ) Description () string {
73
67
return "Smartsheets is a platform for work management and automation. Smartsheets API keys can be used to access and modify data and automate workflows within the platform."
74
68
}
69
+
70
+ func verifySmartSheetsToken (ctx context.Context , client * http.Client , token string ) (bool , error ) {
71
+ req , err := http .NewRequestWithContext (ctx , http .MethodGet , "https://api.smartsheet.com/2.0/sheets" , http .NoBody )
72
+ if err != nil {
73
+ return false , err
74
+ }
75
+
76
+ req .Header .Add ("Authorization" , fmt .Sprintf ("Bearer %s" , token ))
77
+
78
+ resp , err := client .Do (req )
79
+ if err != nil {
80
+ return false , err
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
+ }
0 commit comments