11package mesibo
22
33import (
4+ "bytes"
45 "context"
5- regexp "github.com/wasilibs/go-re2"
6+ "encoding/json"
7+ "fmt"
68 "io"
79 "net/http"
810 "strings"
911
12+ regexp "github.com/wasilibs/go-re2"
13+
1014 "github.com/trufflesecurity/trufflehog/v3/pkg/common"
1115 "github.com/trufflesecurity/trufflehog/v3/pkg/detectors"
1216 "github.com/trufflesecurity/trufflehog/v3/pkg/pb/detector_typepb"
1317)
1418
15- type Scanner struct {}
19+ type Scanner struct {
20+ client * http.Client
21+ }
22+
23+ type apiResponse struct {
24+ Code int `json:"code"`
25+ }
1626
1727// Ensure the Scanner satisfies the interface at compile time.
1828var _ detectors.Detector = (* Scanner )(nil )
1929
2030var (
21- client = common .SaneHttpClient ()
31+ defaultClient = common .SaneHttpClient ()
2232
2333 // Make sure that your group is surrounded in boundary characters such as below to reduce false positives.
2434 keyPat = regexp .MustCompile (detectors .PrefixRegex ([]string {"mesibo" }) + `\b([0-9A-Za-z]{64})\b` )
2535)
2636
37+ func (s Scanner ) getClient () * http.Client {
38+ if s .client != nil {
39+ return s .client
40+ }
41+ return defaultClient
42+ }
43+
2744// Keywords are used for efficiently pre-filtering chunks.
2845// Use identifiers in the secret preferably, or the provider name.
2946func (s Scanner ) Keywords () []string {
@@ -45,22 +62,9 @@ func (s Scanner) FromData(ctx context.Context, verify bool, data []byte) (result
4562 }
4663
4764 if verify {
48- req , err := http . NewRequestWithContext (ctx , "GET" , "https://api.mesibo.com/api.php?op=useradd&token=" + resMatch , nil )
65+ s1 . Verified , err = s . verify (ctx , resMatch )
4966 if err != nil {
50- continue
51- }
52- res , err := client .Do (req )
53- if err == nil {
54- defer res .Body .Close ()
55- bodyBytes , err := io .ReadAll (res .Body )
56- if err != nil {
57- continue
58- }
59- body := string (bodyBytes )
60-
61- if ! strings .Contains (body , "AUTHFAIL" ) {
62- s1 .Verified = true
63- }
67+ s1 .SetVerificationError (err , resMatch )
6468 }
6569 }
6670
@@ -70,6 +74,55 @@ func (s Scanner) FromData(ctx context.Context, verify bool, data []byte) (result
7074 return results , nil
7175}
7276
77+ // verify checks the validity of a Mesibo app token against the backend API.
78+ // https://docs.mesibo.com/api/backend-api/
79+ func (s Scanner ) verify (ctx context.Context , token string ) (bool , error ) {
80+
81+ // We use the `useradd` operation as a probe: a valid token will yield
82+ // code 400 (bad request due to missing required user parameters, but
83+ // authentication succeeded), whereas an invalid or unauthorized
84+ // token will yield a different code such as 401.
85+ payload , err := json .Marshal (map [string ]string {"op" : "useradd" , "token" : token })
86+ if err != nil {
87+ return false , fmt .Errorf ("failed to marshal request payload: %w" , err )
88+ }
89+ req , err := http .NewRequestWithContext (ctx , http .MethodPost , "https://api.mesibo.com/backend" , bytes .NewBuffer (payload ))
90+ if err != nil {
91+ return false , fmt .Errorf ("failed to create request: %w" , err )
92+ }
93+ req .Header .Set ("Content-Type" , "application/json" )
94+ res , err := s .getClient ().Do (req )
95+ if err != nil {
96+ return false , fmt .Errorf ("failed to execute request: %w" , err )
97+ }
98+ defer res .Body .Close ()
99+
100+ // The backend API always returns HTTP 200, with the actual result encoded in the
101+ // JSON response body.
102+ if res .StatusCode != http .StatusOK {
103+ return false , fmt .Errorf ("unexpected status code: %d" , res .StatusCode )
104+ }
105+ bodyBytes , err := io .ReadAll (res .Body )
106+ if err != nil {
107+ return false , fmt .Errorf ("failed to read response body: %w" , err )
108+ }
109+ var result apiResponse
110+ if err := json .Unmarshal (bodyBytes , & result ); err != nil {
111+ return false , fmt .Errorf ("failed to unmarshal response body: %w" , err )
112+ }
113+ // The `code` field contains an RFC 9110 compliant HTTP status
114+ // code indicating the outcome of the operation.
115+ switch result .Code {
116+ case http .StatusBadRequest :
117+ // code 400 means valid token (bad request due to missing params, but auth passed)
118+ return true , nil
119+ case http .StatusUnauthorized :
120+ return false , nil
121+ default :
122+ return false , fmt .Errorf ("unexpected code field: %d" , result .Code )
123+ }
124+ }
125+
73126func (s Scanner ) Type () detector_typepb.DetectorType {
74127 return detector_typepb .DetectorType_Mesibo
75128}
0 commit comments