@@ -2,8 +2,8 @@ package satismeterprojectkey
2
2
3
3
import (
4
4
"context"
5
- b64 "encoding/base64"
6
5
"fmt"
6
+ "io"
7
7
"net/http"
8
8
"strings"
9
9
25
25
client = common .SaneHttpClient ()
26
26
27
27
// Make sure that your group is surrounded in boundary characters such as below to reduce false positives.
28
- keyPat = regexp .MustCompile (detectors .PrefixRegex ([]string {"satismeter" }) + `\b([a-zA-Z0-9]{24})\b` )
29
- emailPat = regexp .MustCompile (detectors .PrefixRegex ([]string {"satismeter" }) + common .EmailPattern )
30
- passPat = regexp .MustCompile (detectors .PrefixRegex ([]string {"satismeter" }) + `\b([a-zA-Z0-9!=@#$%^]{6,32})` )
28
+ projectPat = regexp .MustCompile (detectors .PrefixRegex ([]string {"satismeter" }) + `\b([a-zA-Z0-9]{24})\b` )
29
+ tokenPat = regexp .MustCompile (detectors .PrefixRegex ([]string {"satismeter" }) + `\b([A-Za-z0-9]{32})\b` )
31
30
)
32
31
33
32
// Keywords are used for efficiently pre-filtering chunks.
@@ -40,49 +39,30 @@ func (s Scanner) Keywords() []string {
40
39
func (s Scanner ) FromData (ctx context.Context , verify bool , data []byte ) (results []detectors.Result , err error ) {
41
40
dataStr := string (data )
42
41
43
- uniqueEmailMatches , uniqueKeyMatches , uniquePassMatches := make ( map [ string ] struct {}), make (map [string ]struct {}), make (map [string ]struct {})
44
- for _ , match := range emailPat .FindAllStringSubmatch (dataStr , - 1 ) {
45
- uniqueEmailMatches [strings .TrimSpace (match [1 ])] = struct {}{}
42
+ uniqueProjectMatches , uniqueTokenMatches := make (map [string ]struct {}), make (map [string ]struct {})
43
+ for _ , match := range projectPat .FindAllStringSubmatch (dataStr , - 1 ) {
44
+ uniqueProjectMatches [strings .TrimSpace (match [1 ])] = struct {}{}
46
45
}
47
46
48
- for _ , match := range keyPat .FindAllStringSubmatch (dataStr , - 1 ) {
49
- uniqueKeyMatches [strings .TrimSpace (match [1 ])] = struct {}{}
47
+ for _ , match := range tokenPat .FindAllStringSubmatch (dataStr , - 1 ) {
48
+ uniqueTokenMatches [strings .TrimSpace (match [1 ])] = struct {}{}
50
49
}
51
50
52
- for _ , match := range passPat .FindAllStringSubmatch (dataStr , - 1 ) {
53
- uniquePassMatches [strings .TrimSpace (match [1 ])] = struct {}{}
54
- }
51
+ for projectID := range uniqueProjectMatches {
52
+ for token := range uniqueTokenMatches {
53
+ s1 := detectors.Result {
54
+ DetectorType : detectorspb .DetectorType_SatismeterProjectkey ,
55
+ Raw : []byte (projectID ),
56
+ RawV2 : []byte (projectID + token ),
57
+ }
55
58
56
- for keyMatch := range uniqueKeyMatches {
57
- for emailMatch := range uniqueEmailMatches {
58
- for passMatch := range uniquePassMatches {
59
- s1 := detectors.Result {
60
- DetectorType : detectorspb .DetectorType_SatismeterProjectkey ,
61
- Raw : []byte (keyMatch ),
62
- RawV2 : []byte (keyMatch + passMatch ),
63
- }
64
-
65
- if verify {
66
-
67
- data := fmt .Sprintf ("%s:%s" , emailMatch , passMatch )
68
- sEnc := b64 .StdEncoding .EncodeToString ([]byte (data ))
69
-
70
- req , err := http .NewRequestWithContext (ctx , "GET" , "https://app.satismeter.com/api/users?project=" + keyMatch , nil )
71
- if err != nil {
72
- continue
73
- }
74
- req .Header .Add ("Authorization" , fmt .Sprintf ("Basic %s" , sEnc ))
75
- res , err := client .Do (req )
76
- if err == nil {
77
- defer res .Body .Close ()
78
- if res .StatusCode >= 200 && res .StatusCode < 300 {
79
- s1 .Verified = true
80
- }
81
- }
82
- }
83
-
84
- results = append (results , s1 )
59
+ if verify {
60
+ isVerified , verificationErr := verifySatisMeterApp (ctx , client , projectID , token )
61
+ s1 .Verified = isVerified
62
+ s1 .SetVerificationError (verificationErr , token )
85
63
}
64
+
65
+ results = append (results , s1 )
86
66
}
87
67
88
68
}
@@ -97,3 +77,32 @@ func (s Scanner) Type() detectorspb.DetectorType {
97
77
func (s Scanner ) Description () string {
98
78
return "Satismeter is a customer feedback platform. Satismeter project keys can be used to access project-specific data and manage feedback settings."
99
79
}
80
+
81
+ func verifySatisMeterApp (ctx context.Context , client * http.Client , projectID , token string ) (bool , error ) {
82
+ req , err := http .NewRequestWithContext (ctx , "GET" , "https://app.satismeter.com/api/users?project=" + projectID , nil )
83
+ if err != nil {
84
+ return false , err
85
+ }
86
+
87
+ req .Header .Add ("Authorization" , fmt .Sprintf ("Bearer %s" , token ))
88
+ resp , err := client .Do (req )
89
+ if err != nil {
90
+ return false , err
91
+ }
92
+ defer func () {
93
+ _ , _ = io .Copy (io .Discard , resp .Body )
94
+ _ = resp .Body .Close ()
95
+ }()
96
+
97
+ switch resp .StatusCode {
98
+ case http .StatusOK :
99
+ return true , nil
100
+ case http .StatusUnauthorized , http .StatusForbidden :
101
+ return false , nil
102
+ case http .StatusNotFound :
103
+ // if project id is not found, api return 401
104
+ return false , nil
105
+ default :
106
+ return false , fmt .Errorf ("unexpected status code: %d" , resp .StatusCode )
107
+ }
108
+ }
0 commit comments