@@ -2,11 +2,11 @@ package tickettailor
2
2
3
3
import (
4
4
"context"
5
- b64 "encoding/base64"
6
5
"fmt"
7
- regexp "github.com/wasilibs/go-re2 "
6
+ "io "
8
7
"net/http"
9
- "strings"
8
+
9
+ regexp "github.com/wasilibs/go-re2"
10
10
11
11
"github.com/trufflesecurity/trufflehog/v3/pkg/common"
12
12
"github.com/trufflesecurity/trufflehog/v3/pkg/detectors"
22
22
client = common .SaneHttpClient ()
23
23
24
24
// Make sure that your group is surrounded in boundary characters such as below to reduce false positives
25
- keyPat = regexp .MustCompile (detectors .PrefixRegex ([]string {"tickettailor" }) + `\b(sk[a-fA-Z0-9_]{45})\b ` )
25
+ keyPat = regexp .MustCompile (detectors .PrefixRegex ([]string {"tickettailor" }) + `\b(sk_[0-9]{4}_[0-9]{6}_[a-f0-9]{32}) ` )
26
26
)
27
27
28
28
// Keywords are used for efficiently pre-filtering chunks.
@@ -35,35 +35,22 @@ func (s Scanner) Keywords() []string {
35
35
func (s Scanner ) FromData (ctx context.Context , verify bool , data []byte ) (results []detectors.Result , err error ) {
36
36
dataStr := string (data )
37
37
38
- matches := keyPat . FindAllStringSubmatch ( dataStr , - 1 )
38
+ uniqueKeyMatches := make ( map [ string ] struct {} )
39
39
40
- for _ , match := range matches {
41
- if len (match ) != 2 {
42
- continue
43
- }
44
- resMatch := strings .TrimSpace (match [1 ])
40
+ for _ , match := range keyPat .FindAllStringSubmatch (dataStr , - 1 ) {
41
+ uniqueKeyMatches [match [1 ]] = struct {}{}
42
+ }
45
43
44
+ for key := range uniqueKeyMatches {
46
45
s1 := detectors.Result {
47
46
DetectorType : detectorspb .DetectorType_Tickettailor ,
48
- Raw : []byte (resMatch ),
47
+ Raw : []byte (key ),
49
48
}
50
49
51
50
if verify {
52
- data := fmt .Sprintf ("%s:" , resMatch )
53
- sEnc := b64 .StdEncoding .EncodeToString ([]byte (data ))
54
- req , err := http .NewRequestWithContext (ctx , "GET" , "https://api.tickettailor.com/v1/orders" , nil )
55
- if err != nil {
56
- continue
57
- }
58
- req .Header .Add ("Accept" , "application/vnd.tickettailor+json; version=3" )
59
- req .Header .Add ("Authorization" , fmt .Sprintf ("Basic %s" , sEnc ))
60
- res , err := client .Do (req )
61
- if err == nil {
62
- defer res .Body .Close ()
63
- if res .StatusCode >= 200 && res .StatusCode < 300 {
64
- s1 .Verified = true
65
- }
66
- }
51
+ isVerified , verificationErr := verifyTicketTailor (ctx , client , key )
52
+ s1 .Verified = isVerified
53
+ s1 .SetVerificationError (verificationErr )
67
54
}
68
55
69
56
results = append (results , s1 )
@@ -79,3 +66,32 @@ func (s Scanner) Type() detectorspb.DetectorType {
79
66
func (s Scanner ) Description () string {
80
67
return "Tickettailor is an online ticketing platform that allows event organizers to sell tickets. Tickettailor API keys can be used to manage events, orders, and tickets programmatically."
81
68
}
69
+
70
+ func verifyTicketTailor (ctx context.Context , client * http.Client , apiKey string ) (bool , error ) {
71
+ req , err := http .NewRequestWithContext (ctx , "GET" , "https://api.tickettailor.com/v1/orders" , nil )
72
+ if err != nil {
73
+ return false , err
74
+ }
75
+
76
+ req .Header .Add ("Accept" , "application/json" )
77
+ // as per API docs we only need to use apiKey as username in basic auth and leave password as empty: https://developers.tickettailor.com/#authentication
78
+ req .SetBasicAuth (apiKey , "" )
79
+ resp , err := client .Do (req )
80
+ if err != nil {
81
+ return false , nil
82
+ }
83
+
84
+ defer func () {
85
+ _ , _ = io .Copy (io .Discard , resp .Body )
86
+ _ = resp .Body .Close ()
87
+ }()
88
+
89
+ switch resp .StatusCode {
90
+ case http .StatusOK :
91
+ return true , nil
92
+ case http .StatusUnauthorized , http .StatusForbidden :
93
+ return false , nil
94
+ default :
95
+ return false , fmt .Errorf ("unexpected status code: %d" , resp .StatusCode )
96
+ }
97
+ }
0 commit comments