@@ -4,13 +4,15 @@ import (
4
4
"bytes"
5
5
"context"
6
6
"encoding/json"
7
+ "errors"
7
8
"fmt"
8
9
"io"
9
10
"net/http"
10
11
"strings"
11
12
12
13
regexp "github.com/wasilibs/go-re2"
13
14
15
+ "github.com/trufflesecurity/trufflehog/v3/pkg/cache/simple"
14
16
"github.com/trufflesecurity/trufflehog/v3/pkg/common"
15
17
"github.com/trufflesecurity/trufflehog/v3/pkg/detectors"
16
18
"github.com/trufflesecurity/trufflehog/v3/pkg/pb/detectorspb"
34
36
tokenPat = regexp .MustCompile (detectors .PrefixRegex ([]string {"atlassian" , "confluence" , "jira" }) + `\b([a-zA-Z-0-9]{24})\b` )
35
37
domainPat = regexp .MustCompile (detectors .PrefixRegex ([]string {"atlassian" , "confluence" , "jira" }) + `\b((?:[a-zA-Z0-9-]{1,24}\.)+[a-zA-Z0-9-]{2,24}\.[a-zA-Z0-9-]{2,16})\b` )
36
38
emailPat = regexp .MustCompile (detectors .PrefixRegex ([]string {"atlassian" , "confluence" , "jira" }) + common .EmailPattern )
39
+
40
+ invalidHosts = simple .NewCache [struct {}]()
41
+
42
+ errNoHost = errors .New ("no such host" )
37
43
)
38
44
45
+ type JIRAGraphQLResponse struct {
46
+ Data struct {
47
+ Me struct {
48
+ User struct {
49
+ Name string `json:"name"`
50
+ } `json:"user"`
51
+ } `json:"me"`
52
+ } `json:"data"`
53
+ }
54
+
39
55
func (s Scanner ) getClient () * http.Client {
40
56
if s .client != nil {
41
57
return s .client
@@ -76,6 +92,11 @@ func (s Scanner) FromData(ctx context.Context, verify bool, data []byte) (result
76
92
for email := range uniqueEmails {
77
93
for token := range uniqueTokens {
78
94
for domain := range uniqueDomains {
95
+ if invalidHosts .Exists (domain ) {
96
+ delete (uniqueDomains , domain )
97
+ continue
98
+ }
99
+
79
100
s1 := detectors.Result {
80
101
DetectorType : detectorspb .DetectorType_JiraToken ,
81
102
Raw : []byte (token ),
@@ -90,7 +111,13 @@ func (s Scanner) FromData(ctx context.Context, verify bool, data []byte) (result
90
111
client := s .getClient ()
91
112
isVerified , verificationErr := VerifyJiraToken (ctx , client , email , domain , token )
92
113
s1 .Verified = isVerified
93
- s1 .SetVerificationError (verificationErr , token )
114
+ if verificationErr != nil {
115
+ if errors .Is (verificationErr , errNoHost ) {
116
+ invalidHosts .Set (domain , struct {}{})
117
+ }
118
+
119
+ s1 .SetVerificationError (verificationErr , token )
120
+ }
94
121
}
95
122
96
123
results = append (results , s1 )
@@ -104,7 +131,7 @@ func (s Scanner) FromData(ctx context.Context, verify bool, data []byte) (result
104
131
func VerifyJiraToken (ctx context.Context , client * http.Client , email , domain , token string ) (bool , error ) {
105
132
// wrap the query in a JSON body
106
133
body := map [string ]string {
107
- "query" : `verify { me { user {name}} }` ,
134
+ "query" : `query verify { me { user { name } } }` ,
108
135
}
109
136
110
137
// encode the body as JSON
@@ -125,6 +152,11 @@ func VerifyJiraToken(ctx context.Context, client *http.Client, email, domain, to
125
152
126
153
resp , err := client .Do (req )
127
154
if err != nil {
155
+ // lookup foo.test.net: no such host
156
+ if strings .Contains (err .Error (), "no such host" ) {
157
+ return false , errNoHost
158
+ }
159
+
128
160
return false , err
129
161
}
130
162
@@ -136,6 +168,11 @@ func VerifyJiraToken(ctx context.Context, client *http.Client, email, domain, to
136
168
// the API returns 200 if the token is valid
137
169
switch resp .StatusCode {
138
170
case http .StatusOK :
171
+ var jiraResp JIRAGraphQLResponse
172
+ if err := json .NewDecoder (resp .Body ).Decode (& jiraResp ); err != nil {
173
+ return false , nil // can't decode response in case of 200 OK = not valid JIRA domain
174
+ }
175
+
139
176
return true , nil
140
177
case http .StatusUnauthorized :
141
178
return false , nil
0 commit comments