@@ -2,6 +2,8 @@ package enigma
22
33import (
44 "context"
5+ "fmt"
6+ "io"
57 "net/http"
68 "strings"
79
@@ -33,7 +35,6 @@ func (s Scanner) Keywords() []string {
3335// FromData will find and optionally verify Enigma secrets in a given set of bytes.
3436func (s Scanner ) FromData (ctx context.Context , verify bool , data []byte ) (results []detectors.Result , err error ) {
3537 dataStr := string (data )
36-
3738 matches := keyPat .FindAllStringSubmatch (dataStr , - 1 )
3839
3940 for _ , match := range matches {
@@ -46,20 +47,9 @@ func (s Scanner) FromData(ctx context.Context, verify bool, data []byte) (result
4647 }
4748
4849 if verify {
49- payload := strings .NewReader (`{"name":"Enigma Technologies, Inc.","person":{"first_name":"","last_name":""},"address":{"street_address1":"245 5th Ave","street_address2":"","city":"New York","state":"NY","postal_code":"10016"}}` )
50- req , err := http .NewRequestWithContext (ctx , "POST" , "https://api.enigma.com/businesses/match" , payload )
51- if err != nil {
52- continue
53- }
54- req .Header .Add ("Content-Type" , "application/json" )
55- req .Header .Add ("x-api-key" , resMatch )
56- res , err := client .Do (req )
57- if err == nil {
58- defer func () { _ = res .Body .Close () }()
59- if res .StatusCode >= 200 && res .StatusCode < 300 {
60- s1 .Verified = true
61- }
62- }
50+ isVerified , verificationErr := verifyKey (ctx , client , resMatch )
51+ s1 .Verified = isVerified
52+ s1 .SetVerificationError (verificationErr , resMatch )
6353 }
6454
6555 results = append (results , s1 )
@@ -68,10 +58,52 @@ func (s Scanner) FromData(ctx context.Context, verify bool, data []byte) (result
6858 return results , nil
6959}
7060
61+ // verifyKey checks an Enigma API key against the GraphQL endpoint.
62+ //
63+ // The query selects only `__typename`, which the GraphQL spec guarantees on
64+ // every root type, so verification does not depend on Enigma's evolving schema
65+ // or any specific entity id. Authentication is driven by the HTTP status code:
66+ // 200 means the key is valid, 401 mean it is not.
67+ //
68+ // A 200 is additionally guarded by a JSON Content-Type check: server could return
69+ // a 200 HTML block page, which we must not mistake for a live key.
70+ func verifyKey (ctx context.Context , client * http.Client , key string ) (bool , error ) {
71+ payload := strings .NewReader (`{"query":"{ __typename }"}` )
72+
73+ req , err := http .NewRequestWithContext (ctx , http .MethodPost , "https://api.enigma.com/graphql" , payload )
74+ if err != nil {
75+ return false , err
76+ }
77+ req .Header .Add ("Content-Type" , "application/json" )
78+ req .Header .Add ("x-api-key" , key )
79+
80+ res , err := client .Do (req )
81+ if err != nil {
82+ return false , err
83+ }
84+ defer func () {
85+ _ , _ = io .Copy (io .Discard , res .Body )
86+ _ = res .Body .Close ()
87+ }()
88+
89+ switch res .StatusCode {
90+ case http .StatusOK :
91+ if contentType := res .Header .Get ("Content-Type" ); ! strings .Contains (contentType , "application/json" ) {
92+ return false , fmt .Errorf ("got HTTP 200 with unexpected Content-Type %q" , contentType )
93+ }
94+
95+ return true , nil
96+ case http .StatusUnauthorized :
97+ return false , nil
98+ default :
99+ return false , fmt .Errorf ("unexpected HTTP response status %d" , res .StatusCode )
100+ }
101+ }
102+
71103func (s Scanner ) Type () detector_typepb.DetectorType {
72104 return detector_typepb .DetectorType_Enigma
73105}
74106
75107func (s Scanner ) Description () string {
76- return "Enigma is a data intelligence company that provides comprehensive data about businesses . Enigma API keys can be used to access and interact with this data ."
108+ return "Enigma is a business data intelligence platform . Enigma API keys grant access to comprehensive firmographic, legal, and identity datasets ."
77109}
0 commit comments