diff --git a/pkg/detectors/flutterwave/flutterwave.go b/pkg/detectors/flutterwave/flutterwave.go index 3de6afc2bc3a..55e8663832ec 100644 --- a/pkg/detectors/flutterwave/flutterwave.go +++ b/pkg/detectors/flutterwave/flutterwave.go @@ -3,8 +3,8 @@ package flutterwave import ( "context" "fmt" + "io" "net/http" - "strings" regexp "github.com/wasilibs/go-re2" @@ -15,62 +15,59 @@ import ( type Scanner struct{} -// Ensure the Scanner satisfies the interface at compile time. var _ detectors.Detector = (*Scanner)(nil) var ( - client = common.SaneHttpClient() - - // Make sure that your group is surrounded in boundary characters such as below to reduce false positives. - - keyPat = regexp.MustCompile(`\b(FLWSECK-[0-9a-z]{32}-X)\b`) + client = common.SaneHttpClient() + flutterwaveKeyPattern = regexp.MustCompile(`\bFLWSECK(?:_TEST|_LIVE)?-[0-9a-zA-Z]{32}-X\b`) + keywords = []string{"flutterwave", "FLWSECK"} ) -// Keywords are used for efficiently pre-filtering chunks. -// Use identifiers in the secret preferably, or the provider name. -func (s Scanner) Keywords() []string { - return []string{"FLWSECK-"} -} +func (s Scanner) Keywords() []string { return keywords } -// FromData will find and optionally verify Flutterwave secrets in a given set of bytes. func (s Scanner) FromData(ctx context.Context, verify bool, data []byte) (results []detectors.Result, err error) { dataStr := string(data) - - matches := keyPat.FindAllStringSubmatch(dataStr, -1) - + matches := flutterwaveKeyPattern.FindAllString(dataStr, -1) for _, match := range matches { - resMatch := strings.TrimSpace(match[1]) - - s1 := detectors.Result{ + result := detectors.Result{ DetectorType: detectorspb.DetectorType_Flutterwave, - Raw: []byte(resMatch), + Raw: []byte(match), } - if verify { - req, err := http.NewRequestWithContext(ctx, "GET", "https://api.flutterwave.com/v3/subaccounts", nil) - if err != nil { - continue - } - req.Header.Add("Authorization", fmt.Sprintf("Bearer %s", resMatch)) - res, err := client.Do(req) - if err == nil { - defer res.Body.Close() - if res.StatusCode >= 200 && res.StatusCode < 300 { - s1.Verified = true - } + verified, verifyErr := verifyFlutterwave(ctx, match) + result.Verified = verified + if verifyErr != nil { + result.SetVerificationError(verifyErr, match) } } - - results = append(results, s1) + results = append(results, result) } - return results, nil } -func (s Scanner) Type() detectorspb.DetectorType { - return detectorspb.DetectorType_Flutterwave +func verifyFlutterwave(ctx context.Context, key string) (bool, error) { + req, err := http.NewRequestWithContext(ctx, http.MethodGet, "https://api.flutterwave.com/v3/transactions", nil) + if err != nil { + return false, err + } + req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", key)) + resp, err := client.Do(req) + if err != nil { + return false, err + } + defer resp.Body.Close() + _, _ = io.Copy(io.Discard, resp.Body) + switch resp.StatusCode { + case http.StatusOK: + return true, nil + case http.StatusUnauthorized, http.StatusForbidden: + return false, nil + default: + return false, fmt.Errorf("unexpected status code: %d", resp.StatusCode) + } } +func (s Scanner) Type() detectorspb.DetectorType { return detectorspb.DetectorType_Flutterwave } func (s Scanner) Description() string { - return "Flutterwave is a payment technology company providing seamless and secure payment solutions for businesses. Flutterwave API keys can be used to access and manage payment services and transactions." + return "Detects Flutterwave secret API keys (FLWSECK format)" } diff --git a/pkg/detectors/interswitch/interswitch.go b/pkg/detectors/interswitch/interswitch.go new file mode 100644 index 000000000000..fd98a99bb04b --- /dev/null +++ b/pkg/detectors/interswitch/interswitch.go @@ -0,0 +1,84 @@ +package interswitch + +import ( + "context" + "encoding/base64" + "fmt" + "io" + "net/http" + + regexp "github.com/wasilibs/go-re2" + + "github.com/trufflesecurity/trufflehog/v3/pkg/common" + "github.com/trufflesecurity/trufflehog/v3/pkg/detectors" + "github.com/trufflesecurity/trufflehog/v3/pkg/pb/detectorspb" +) + +var ( + interswitchKeyPattern = regexp.MustCompile(`(?i)(?:interswitch|quickteller)[_-]?(?:api[_-])?(?:key|secret)["\s:=]+([0-9a-zA-Z]{40,64})(?:[^0-9a-zA-Z]|$)`) + interswitchClient = common.SaneHttpClient() +) + +type Scanner struct{} + +var _ detectors.Detector = (*Scanner)(nil) + +func (s Scanner) Keywords() []string { + return []string{"interswitch", "quickteller"} +} + +func (s Scanner) FromData(ctx context.Context, verify bool, data []byte) (results []detectors.Result, err error) { + dataStr := string(data) + matches := interswitchKeyPattern.FindAllStringSubmatch(dataStr, -1) + for _, match := range matches { + if len(match) < 2 || match[1] == "" { + continue + } + key := match[1] + result := detectors.Result{ + DetectorType: detectorspb.DetectorType_Interswitch, + Raw: []byte(key), + } + if verify { + verified, verifyErr := verifyInterswitchKey(ctx, key) + result.Verified = verified + if verifyErr != nil { + result.SetVerificationError(verifyErr, key) + } + } + results = append(results, result) + } + return results, nil +} + +func verifyInterswitchKey(ctx context.Context, key string) (bool, error) { + req, err := http.NewRequestWithContext(ctx, "GET", "https://api.interswitchng.com/api/v1/merchant/profile", nil) + if err != nil { + return false, err + } + auth := base64.StdEncoding.EncodeToString([]byte(key + ":")) + req.Header.Add("Authorization", "Basic "+auth) + req.Header.Add("Content-Type", "application/json") + resp, err := interswitchClient.Do(req) + if err != nil { + return false, err + } + defer resp.Body.Close() + _, _ = io.Copy(io.Discard, resp.Body) + switch resp.StatusCode { + case http.StatusOK: + return true, nil + case http.StatusUnauthorized, http.StatusForbidden: + return false, nil + default: + return false, fmt.Errorf("unexpected status code: %d", resp.StatusCode) + } +} + +func (s Scanner) Type() detectorspb.DetectorType { + return detectorspb.DetectorType_Interswitch +} + +func (s Scanner) Description() string { + return "Detects Interswitch API keys" +} diff --git a/pkg/detectors/interswitch/interswitch_test.go b/pkg/detectors/interswitch/interswitch_test.go new file mode 100644 index 000000000000..6933510aa22b --- /dev/null +++ b/pkg/detectors/interswitch/interswitch_test.go @@ -0,0 +1,63 @@ +package interswitch + +import ( + "context" + "testing" + + "github.com/google/go-cmp/cmp" + "github.com/trufflesecurity/trufflehog/v3/pkg/detectors" + "github.com/trufflesecurity/trufflehog/v3/pkg/engine/ahocorasick" +) + +func TestInterswitch_Pattern(t *testing.T) { + d := Scanner{} + ahoCorasickCore := ahocorasick.NewAhoCorasickCore([]detectors.Detector{d}) + tests := []struct { + name string + input string + want []string + }{ + { + name: "valid pattern", + input: "interswitch_api_key=abcdefghijklmnopqrstuvwxyz1234567890abcd", + want: []string{"abcdefghijklmnopqrstuvwxyz1234567890abcd"}, + }, + } + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + matchedDetectors := ahoCorasickCore.FindDetectorMatches([]byte(test.input)) + if len(matchedDetectors) == 0 { + t.Errorf("keywords '%v' not matched by: %s", d.Keywords(), test.input) + return + } + results, err := d.FromData(context.Background(), false, []byte(test.input)) + if err != nil { + t.Errorf("error = %v", err) + return + } + if len(results) != len(test.want) { + if len(results) == 0 { + t.Errorf("did not receive result") + } else { + t.Errorf("expected %d results, only received %d", len(test.want), len(results)) + } + return + } + actual := make(map[string]struct{}, len(results)) + for _, r := range results { + if len(r.RawV2) > 0 { + actual[string(r.RawV2)] = struct{}{} + } else { + actual[string(r.Raw)] = struct{}{} + } + } + expected := make(map[string]struct{}, len(test.want)) + for _, v := range test.want { + expected[v] = struct{}{} + } + if diff := cmp.Diff(expected, actual); diff != "" { + t.Errorf("%s diff: (-want +got)\n%s", test.name, diff) + } + }) + } +} diff --git a/pkg/detectors/paystack/paystack.go b/pkg/detectors/paystack/paystack.go index 8814f95059b5..0a4920d88eb5 100644 --- a/pkg/detectors/paystack/paystack.go +++ b/pkg/detectors/paystack/paystack.go @@ -3,71 +3,90 @@ package paystack import ( "context" "fmt" - regexp "github.com/wasilibs/go-re2" + "io" "net/http" - "strings" + + regexp "github.com/wasilibs/go-re2" "github.com/trufflesecurity/trufflehog/v3/pkg/common" "github.com/trufflesecurity/trufflehog/v3/pkg/detectors" "github.com/trufflesecurity/trufflehog/v3/pkg/pb/detectorspb" ) +var ( + paystackKeyPattern = regexp.MustCompile(`\b(sk_[a-z]+_[0-9a-zA-Z]{40})\b`) + paystackClient = common.SaneHttpClient() +) + type Scanner struct{} -// Ensure the Scanner satisfies the interface at compile time. var _ detectors.Detector = (*Scanner)(nil) -var ( - client = common.SaneHttpClient() - // TODO: support live key - keyPat = regexp.MustCompile(`\b(sk\_[a-z]{1,}\_[A-Za-z0-9]{40})\b`) -) - -// Keywords are used for efficiently pre-filtering chunks. -// Use identifiers in the secret preferably, or the provider name. func (s Scanner) Keywords() []string { - return []string{"paystack"} + return []string{"paystack", "sk_live", "sk_test"} } -// FromData will find and optionally verify Paystack secrets in a given set of bytes. func (s Scanner) FromData(ctx context.Context, verify bool, data []byte) (results []detectors.Result, err error) { dataStr := string(data) - matches := keyPat.FindAllStringSubmatch(dataStr, -1) + matches := paystackKeyPattern.FindAllStringSubmatch(dataStr, -1) for _, match := range matches { - resMatch := strings.TrimSpace(match[1]) + if len(match) < 2 { + continue + } + key := match[1] - s1 := detectors.Result{ + result := detectors.Result{ DetectorType: detectorspb.DetectorType_Paystack, - Raw: []byte(resMatch), + Raw: []byte(key), } if verify { - req, err := http.NewRequestWithContext(ctx, "GET", "https://api.paystack.co/customer", nil) - if err != nil { - continue - } - req.Header.Add("Authorization", fmt.Sprintf("Bearer %s", resMatch)) - res, err := client.Do(req) - if err == nil { - defer res.Body.Close() - if res.StatusCode >= 200 && res.StatusCode < 300 { - s1.Verified = true - } + verified, verifyErr := verifyPaystackKey(ctx, key) + result.Verified = verified + if verifyErr != nil { + result.SetVerificationError(verifyErr, key) } } - results = append(results, s1) + results = append(results, result) } return results, nil } +func verifyPaystackKey(ctx context.Context, key string) (bool, error) { + req, err := http.NewRequestWithContext(ctx, "GET", "https://api.paystack.co/balance", nil) + if err != nil { + return false, err + } + + req.Header.Add("Authorization", "Bearer "+key) + req.Header.Add("Content-Type", "application/json") + + resp, err := paystackClient.Do(req) + if err != nil { + return false, err + } + defer resp.Body.Close() + + _, _ = io.Copy(io.Discard, resp.Body) + + switch resp.StatusCode { + case http.StatusOK: + return true, nil + case http.StatusUnauthorized, http.StatusForbidden: + return false, nil + default: + return false, fmt.Errorf("unexpected status code: %d", resp.StatusCode) + } +} + func (s Scanner) Type() detectorspb.DetectorType { return detectorspb.DetectorType_Paystack } func (s Scanner) Description() string { - return "Paystack is a payment processing service. Paystack API keys can be used to access and manage payment transactions and customer data." + return "Detects Paystack API secret keys (sk_* format)" } diff --git a/pkg/detectors/remita/remita.go b/pkg/detectors/remita/remita.go new file mode 100644 index 000000000000..44fee56e3165 --- /dev/null +++ b/pkg/detectors/remita/remita.go @@ -0,0 +1,95 @@ +package remita + +import ( + "context" + "encoding/base64" + "fmt" + "io" + "net/http" + + regexp "github.com/wasilibs/go-re2" + + "github.com/trufflesecurity/trufflehog/v3/pkg/common" + "github.com/trufflesecurity/trufflehog/v3/pkg/detectors" + "github.com/trufflesecurity/trufflehog/v3/pkg/pb/detectorspb" +) + +var ( + remitaKeyPattern = regexp.MustCompile(`(?i)remita[_-]?(?:api[_-])?key["\s:=]+([0-9a-zA-Z]{40,64})`) + remitaClient = common.SaneHttpClient() +) + +type Scanner struct{} + +var _ detectors.Detector = (*Scanner)(nil) + +func (s Scanner) Keywords() []string { + return []string{"remita", "remita_api_key", "remita_merchant"} +} + +func (s Scanner) FromData(ctx context.Context, verify bool, data []byte) (results []detectors.Result, err error) { + dataStr := string(data) + + matches := remitaKeyPattern.FindAllStringSubmatch(dataStr, -1) + + for _, match := range matches { + if len(match) < 2 { + continue + } + + key := match[1] + + result := detectors.Result{ + DetectorType: detectorspb.DetectorType_Remita, + Raw: []byte(key), + } + + if verify { + verified, verifyErr := verifyRemitaKey(ctx, key) + result.Verified = verified + if verifyErr != nil { + result.SetVerificationError(verifyErr, key) + } + } + + results = append(results, result) + } + + return results, nil +} + +func verifyRemitaKey(ctx context.Context, key string) (bool, error) { + req, err := http.NewRequestWithContext(ctx, "GET", "https://api.remita.net/v1/send/api/echo", nil) + if err != nil { + return false, err + } + + auth := base64.StdEncoding.EncodeToString([]byte(key + ":")) + req.Header.Add("Authorization", "Basic "+auth) + req.Header.Add("Content-Type", "application/json") + + resp, err := remitaClient.Do(req) + if err != nil { + return false, err + } + defer resp.Body.Close() + + _, _ = io.Copy(io.Discard, resp.Body) + + switch resp.StatusCode { + case http.StatusOK: + return true, nil + case http.StatusUnauthorized, http.StatusForbidden: + return false, nil + default: + return false, fmt.Errorf("unexpected status code: %d", resp.StatusCode) + } +} + +func (s Scanner) Type() detectorspb.DetectorType { + return detectorspb.DetectorType_Remita +} + +func (s Scanner) Description() string { + return "Detects Remita API keys and merchant credentials" +} diff --git a/pkg/detectors/remita/remita_test.go b/pkg/detectors/remita/remita_test.go new file mode 100644 index 000000000000..bc40001c3794 --- /dev/null +++ b/pkg/detectors/remita/remita_test.go @@ -0,0 +1,63 @@ +package remita + +import ( + "context" + "testing" + + "github.com/google/go-cmp/cmp" + "github.com/trufflesecurity/trufflehog/v3/pkg/detectors" + "github.com/trufflesecurity/trufflehog/v3/pkg/engine/ahocorasick" +) + +func TestRemita_Pattern(t *testing.T) { + d := Scanner{} + ahoCorasickCore := ahocorasick.NewAhoCorasickCore([]detectors.Detector{d}) + tests := []struct { + name string + input string + want []string + }{ + { + name: "valid pattern", + input: "remita_api_key=abcdefghijklmnopqrstuvwxyz1234567890abcd", + want: []string{"abcdefghijklmnopqrstuvwxyz1234567890abcd"}, + }, + } + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + matchedDetectors := ahoCorasickCore.FindDetectorMatches([]byte(test.input)) + if len(matchedDetectors) == 0 { + t.Errorf("keywords '%v' not matched by: %s", d.Keywords(), test.input) + return + } + results, err := d.FromData(context.Background(), false, []byte(test.input)) + if err != nil { + t.Errorf("error = %v", err) + return + } + if len(results) != len(test.want) { + if len(results) == 0 { + t.Errorf("did not receive result") + } else { + t.Errorf("expected %d results, only received %d", len(test.want), len(results)) + } + return + } + actual := make(map[string]struct{}, len(results)) + for _, r := range results { + if len(r.RawV2) > 0 { + actual[string(r.RawV2)] = struct{}{} + } else { + actual[string(r.Raw)] = struct{}{} + } + } + expected := make(map[string]struct{}, len(test.want)) + for _, v := range test.want { + expected[v] = struct{}{} + } + if diff := cmp.Diff(expected, actual); diff != "" { + t.Errorf("%s diff: (-want +got)\n%s", test.name, diff) + } + }) + } +} diff --git a/pkg/detectors/sportybet/sportybet.go b/pkg/detectors/sportybet/sportybet.go new file mode 100644 index 000000000000..90ddf423d4a5 --- /dev/null +++ b/pkg/detectors/sportybet/sportybet.go @@ -0,0 +1,93 @@ +package sportybet + +import ( + "context" + "fmt" + "io" + "net/http" + + regexp "github.com/wasilibs/go-re2" + + "github.com/trufflesecurity/trufflehog/v3/pkg/common" + "github.com/trufflesecurity/trufflehog/v3/pkg/detectors" + "github.com/trufflesecurity/trufflehog/v3/pkg/pb/detectorspb" +) + +var ( + sportybetKeyPattern = regexp.MustCompile(`(?i)sportybet[_-]?(?:api[_-])?(?:key|token)["\s:=]+([0-9a-zA-Z]{40,64})(?:[^0-9a-zA-Z]|$)`) + sportybetClient = common.SaneHttpClient() +) + +type Scanner struct{} + +var _ detectors.Detector = (*Scanner)(nil) + +func (s Scanner) Keywords() []string { + return []string{"sportybet", "sportybet_api"} +} + +func (s Scanner) FromData(ctx context.Context, verify bool, data []byte) (results []detectors.Result, err error) { + dataStr := string(data) + + matches := sportybetKeyPattern.FindAllStringSubmatch(dataStr, -1) + + for _, match := range matches { + if len(match) < 2 { + continue + } + + key := match[1] + + result := detectors.Result{ + DetectorType: detectorspb.DetectorType_Sportybet, + Raw: []byte(key), + } + + if verify { + verified, verifyErr := verifySportybetKey(ctx, key) + result.Verified = verified + if verifyErr != nil { + result.SetVerificationError(verifyErr, key) + } + } + + results = append(results, result) + } + + return results, nil +} + +func verifySportybetKey(ctx context.Context, key string) (bool, error) { + req, err := http.NewRequestWithContext(ctx, "GET", "https://api.sportybet.com/api/v2/user/account", nil) + if err != nil { + return false, err + } + + req.Header.Add("Authorization", "Bearer "+key) + req.Header.Add("Content-Type", "application/json") + + resp, err := sportybetClient.Do(req) + if err != nil { + return false, err + } + defer resp.Body.Close() + + _, _ = io.Copy(io.Discard, resp.Body) + + switch resp.StatusCode { + case http.StatusOK: + return true, nil + case http.StatusUnauthorized, http.StatusForbidden: + return false, nil + default: + return false, fmt.Errorf("unexpected status code: %d", resp.StatusCode) + } +} + +func (s Scanner) Type() detectorspb.DetectorType { + return detectorspb.DetectorType_Sportybet +} + +func (s Scanner) Description() string { + return "Detects SportyBet/BetKing API tokens and credentials" +} diff --git a/pkg/detectors/sportybet/sportybet_test.go b/pkg/detectors/sportybet/sportybet_test.go new file mode 100644 index 000000000000..ae9df22f1679 --- /dev/null +++ b/pkg/detectors/sportybet/sportybet_test.go @@ -0,0 +1,63 @@ +package sportybet + +import ( + "context" + "testing" + + "github.com/google/go-cmp/cmp" + "github.com/trufflesecurity/trufflehog/v3/pkg/detectors" + "github.com/trufflesecurity/trufflehog/v3/pkg/engine/ahocorasick" +) + +func TestSportybet_Pattern(t *testing.T) { + d := Scanner{} + ahoCorasickCore := ahocorasick.NewAhoCorasickCore([]detectors.Detector{d}) + tests := []struct { + name string + input string + want []string + }{ + { + name: "valid pattern", + input: "sportybet_token=abcdefghijklmnopqrstuvwxyz1234567890abcd", + want: []string{"abcdefghijklmnopqrstuvwxyz1234567890abcd"}, + }, + } + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + matchedDetectors := ahoCorasickCore.FindDetectorMatches([]byte(test.input)) + if len(matchedDetectors) == 0 { + t.Errorf("keywords '%v' not matched by: %s", d.Keywords(), test.input) + return + } + results, err := d.FromData(context.Background(), false, []byte(test.input)) + if err != nil { + t.Errorf("error = %v", err) + return + } + if len(results) != len(test.want) { + if len(results) == 0 { + t.Errorf("did not receive result") + } else { + t.Errorf("expected %d results, only received %d", len(test.want), len(results)) + } + return + } + actual := make(map[string]struct{}, len(results)) + for _, r := range results { + if len(r.RawV2) > 0 { + actual[string(r.RawV2)] = struct{}{} + } else { + actual[string(r.Raw)] = struct{}{} + } + } + expected := make(map[string]struct{}, len(test.want)) + for _, v := range test.want { + expected[v] = struct{}{} + } + if diff := cmp.Diff(expected, actual); diff != "" { + t.Errorf("%s diff: (-want +got)\n%s", test.name, diff) + } + }) + } +} diff --git a/pkg/engine/defaults/defaults.go b/pkg/engine/defaults/defaults.go index c3e76f3caed5..3a11eb384219 100644 --- a/pkg/engine/defaults/defaults.go +++ b/pkg/engine/defaults/defaults.go @@ -548,6 +548,9 @@ import ( "github.com/trufflesecurity/trufflehog/v3/pkg/detectors/paymongo" "github.com/trufflesecurity/trufflehog/v3/pkg/detectors/paypaloauth" "github.com/trufflesecurity/trufflehog/v3/pkg/detectors/paystack" + "github.com/trufflesecurity/trufflehog/v3/pkg/detectors/remita" + "github.com/trufflesecurity/trufflehog/v3/pkg/detectors/interswitch" + "github.com/trufflesecurity/trufflehog/v3/pkg/detectors/sportybet" "github.com/trufflesecurity/trufflehog/v3/pkg/detectors/pdflayer" "github.com/trufflesecurity/trufflehog/v3/pkg/detectors/pdfshift" "github.com/trufflesecurity/trufflehog/v3/pkg/detectors/peopledatalabs" @@ -1431,6 +1434,9 @@ func buildDetectorList() []detectors.Detector { &paymongo.Scanner{}, &paypaloauth.Scanner{}, &paystack.Scanner{}, + &remita.Scanner{}, + &interswitch.Scanner{}, + &sportybet.Scanner{}, &pdflayer.Scanner{}, &pdfshift.Scanner{}, &peopledatalabs.Scanner{}, diff --git a/pkg/pb/detectorspb/detectors.pb.go b/pkg/pb/detectorspb/detectors.pb.go index 9dc30b110d3b..cd4176f20662 100644 --- a/pkg/pb/detectorspb/detectors.pb.go +++ b/pkg/pb/detectorspb/detectors.pb.go @@ -1146,6 +1146,9 @@ const ( DetectorType_PhraseAccessToken DetectorType = 1037 DetectorType_Photoroom DetectorType = 1038 DetectorType_JWT DetectorType = 1039 + DetectorType_Sportybet DetectorType = 1046 + DetectorType_Interswitch DetectorType = 1045 + DetectorType_Remita DetectorType = 1044 DetectorType_OpenAIAdmin DetectorType = 1040 DetectorType_GoogleGeminiAPIKey DetectorType = 1041 DetectorType_ArtifactoryReferenceToken DetectorType = 1042 @@ -2191,6 +2194,9 @@ var ( 1037: "PhraseAccessToken", 1038: "Photoroom", 1039: "JWT", + 1046: "Sportybet", + 1045: "Interswitch", + 1044: "Remita", 1040: "OpenAIAdmin", 1041: "GoogleGeminiAPIKey", 1042: "ArtifactoryReferenceToken", @@ -3233,6 +3239,9 @@ var ( "PhraseAccessToken": 1037, "Photoroom": 1038, "JWT": 1039, + "Sportybet": 1046, + "Interswitch": 1045, + "Remita": 1044, "OpenAIAdmin": 1040, "GoogleGeminiAPIKey": 1041, "ArtifactoryReferenceToken": 1042, @@ -3272,16 +3281,14 @@ type Result struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - SourceId int64 `protobuf:"varint,2,opt,name=source_id,json=sourceId,proto3" json:"source_id,omitempty"` - Redacted string `protobuf:"bytes,3,opt,name=redacted,proto3" json:"redacted,omitempty"` - Verified bool `protobuf:"varint,4,opt,name=verified,proto3" json:"verified,omitempty"` - Hash string `protobuf:"bytes,5,opt,name=hash,proto3" json:"hash,omitempty"` - ExtraData map[string]string `protobuf:"bytes,6,rep,name=extra_data,json=extraData,proto3" json:"extra_data,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` - StructuredData *StructuredData `protobuf:"bytes,7,opt,name=structured_data,json=structuredData,proto3" json:"structured_data,omitempty"` - HashV2 string `protobuf:"bytes,8,opt,name=hash_v2,json=hashV2,proto3" json:"hash_v2,omitempty"` - DecoderType DecoderType `protobuf:"varint,9,opt,name=decoder_type,json=decoderType,proto3,enum=detectors.DecoderType" json:"decoder_type,omitempty"` - // This field should only be populated if the verification process itself failed in a way that provides no information - // about the verification status of the candidate secret, such as if the verification request timed out. + SourceId int64 `protobuf:"varint,2,opt,name=source_id,json=sourceId,proto3" json:"source_id,omitempty"` + Redacted string `protobuf:"bytes,3,opt,name=redacted,proto3" json:"redacted,omitempty"` + Verified bool `protobuf:"varint,4,opt,name=verified,proto3" json:"verified,omitempty"` + Hash string `protobuf:"bytes,5,opt,name=hash,proto3" json:"hash,omitempty"` + ExtraData map[string]string `protobuf:"bytes,6,rep,name=extra_data,json=extraData,proto3" json:"extra_data,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + StructuredData *StructuredData `protobuf:"bytes,7,opt,name=structured_data,json=structuredData,proto3" json:"structured_data,omitempty"` + HashV2 string `protobuf:"bytes,8,opt,name=hash_v2,json=hashV2,proto3" json:"hash_v2,omitempty"` + DecoderType DecoderType `protobuf:"varint,9,opt,name=decoder_type,json=decoderType,proto3,enum=detectors.DecoderType" json:"decoder_type,omitempty"` VerificationErrorMessage string `protobuf:"bytes,10,opt,name=verification_error_message,json=verificationErrorMessage,proto3" json:"verification_error_message,omitempty"` FalsePositiveInfo *FalsePositiveInfo `protobuf:"bytes,11,opt,name=false_positive_info,json=falsePositiveInfo,proto3" json:"false_positive_info,omitempty"` } @@ -3690,7 +3697,7 @@ var file_detectors_proto_rawDesc = []byte{ 0x4c, 0x41, 0x49, 0x4e, 0x10, 0x01, 0x12, 0x0a, 0x0a, 0x06, 0x42, 0x41, 0x53, 0x45, 0x36, 0x34, 0x10, 0x02, 0x12, 0x09, 0x0a, 0x05, 0x55, 0x54, 0x46, 0x31, 0x36, 0x10, 0x03, 0x12, 0x13, 0x0a, 0x0f, 0x45, 0x53, 0x43, 0x41, 0x50, 0x45, 0x44, 0x5f, 0x55, 0x4e, 0x49, 0x43, 0x4f, 0x44, 0x45, - 0x10, 0x04, 0x2a, 0xa4, 0x87, 0x01, 0x0a, 0x0c, 0x44, 0x65, 0x74, 0x65, 0x63, 0x74, 0x6f, 0x72, + 0x10, 0x04, 0x2a, 0xd3, 0x87, 0x01, 0x0a, 0x0c, 0x44, 0x65, 0x74, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x54, 0x79, 0x70, 0x65, 0x12, 0x0b, 0x0a, 0x07, 0x41, 0x6c, 0x69, 0x62, 0x61, 0x62, 0x61, 0x10, 0x00, 0x12, 0x08, 0x0a, 0x04, 0x41, 0x4d, 0x51, 0x50, 0x10, 0x01, 0x12, 0x07, 0x0a, 0x03, 0x41, 0x57, 0x53, 0x10, 0x02, 0x12, 0x09, 0x0a, 0x05, 0x41, 0x7a, 0x75, 0x72, 0x65, 0x10, 0x03, 0x12, @@ -4766,18 +4773,20 @@ var file_detectors_proto_rawDesc = []byte{ 0x6c, 0x74, 0x41, 0x75, 0x74, 0x68, 0x10, 0x8c, 0x08, 0x12, 0x16, 0x0a, 0x11, 0x50, 0x68, 0x72, 0x61, 0x73, 0x65, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x10, 0x8d, 0x08, 0x12, 0x0e, 0x0a, 0x09, 0x50, 0x68, 0x6f, 0x74, 0x6f, 0x72, 0x6f, 0x6f, 0x6d, 0x10, 0x8e, - 0x08, 0x12, 0x08, 0x0a, 0x03, 0x4a, 0x57, 0x54, 0x10, 0x8f, 0x08, 0x12, 0x10, 0x0a, 0x0b, 0x4f, - 0x70, 0x65, 0x6e, 0x41, 0x49, 0x41, 0x64, 0x6d, 0x69, 0x6e, 0x10, 0x90, 0x08, 0x12, 0x17, 0x0a, - 0x12, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x47, 0x65, 0x6d, 0x69, 0x6e, 0x69, 0x41, 0x50, 0x49, - 0x4b, 0x65, 0x79, 0x10, 0x91, 0x08, 0x12, 0x1e, 0x0a, 0x19, 0x41, 0x72, 0x74, 0x69, 0x66, 0x61, - 0x63, 0x74, 0x6f, 0x72, 0x79, 0x52, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x54, 0x6f, - 0x6b, 0x65, 0x6e, 0x10, 0x92, 0x08, 0x12, 0x12, 0x0a, 0x0d, 0x44, 0x61, 0x74, 0x61, 0x64, 0x6f, - 0x67, 0x41, 0x70, 0x69, 0x6b, 0x65, 0x79, 0x10, 0x93, 0x08, 0x42, 0x3d, 0x5a, 0x3b, 0x67, 0x69, - 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x74, 0x72, 0x75, 0x66, 0x66, 0x6c, 0x65, - 0x73, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x2f, 0x74, 0x72, 0x75, 0x66, 0x66, 0x6c, 0x65, - 0x68, 0x6f, 0x67, 0x2f, 0x76, 0x33, 0x2f, 0x70, 0x6b, 0x67, 0x2f, 0x70, 0x62, 0x2f, 0x64, 0x65, - 0x74, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x73, 0x70, 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x33, + 0x08, 0x12, 0x08, 0x0a, 0x03, 0x4a, 0x57, 0x54, 0x10, 0x8f, 0x08, 0x12, 0x0e, 0x0a, 0x09, 0x53, + 0x70, 0x6f, 0x72, 0x74, 0x79, 0x62, 0x65, 0x74, 0x10, 0x96, 0x08, 0x12, 0x10, 0x0a, 0x0b, 0x49, + 0x6e, 0x74, 0x65, 0x72, 0x73, 0x77, 0x69, 0x74, 0x63, 0x68, 0x10, 0x95, 0x08, 0x12, 0x0b, 0x0a, + 0x06, 0x52, 0x65, 0x6d, 0x69, 0x74, 0x61, 0x10, 0x94, 0x08, 0x12, 0x10, 0x0a, 0x0b, 0x4f, 0x70, + 0x65, 0x6e, 0x41, 0x49, 0x41, 0x64, 0x6d, 0x69, 0x6e, 0x10, 0x90, 0x08, 0x12, 0x17, 0x0a, 0x12, + 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x47, 0x65, 0x6d, 0x69, 0x6e, 0x69, 0x41, 0x50, 0x49, 0x4b, + 0x65, 0x79, 0x10, 0x91, 0x08, 0x12, 0x1e, 0x0a, 0x19, 0x41, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, + 0x74, 0x6f, 0x72, 0x79, 0x52, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x54, 0x6f, 0x6b, + 0x65, 0x6e, 0x10, 0x92, 0x08, 0x12, 0x12, 0x0a, 0x0d, 0x44, 0x61, 0x74, 0x61, 0x64, 0x6f, 0x67, + 0x41, 0x70, 0x69, 0x6b, 0x65, 0x79, 0x10, 0x93, 0x08, 0x42, 0x3d, 0x5a, 0x3b, 0x67, 0x69, 0x74, + 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x74, 0x72, 0x75, 0x66, 0x66, 0x6c, 0x65, 0x73, + 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x2f, 0x74, 0x72, 0x75, 0x66, 0x66, 0x6c, 0x65, 0x68, + 0x6f, 0x67, 0x2f, 0x76, 0x33, 0x2f, 0x70, 0x6b, 0x67, 0x2f, 0x70, 0x62, 0x2f, 0x64, 0x65, 0x74, + 0x65, 0x63, 0x74, 0x6f, 0x72, 0x73, 0x70, 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( diff --git a/proto/detectors.proto b/proto/detectors.proto index bb7bbe69dcff..79a5a4dea1e6 100644 --- a/proto/detectors.proto +++ b/proto/detectors.proto @@ -472,7 +472,7 @@ enum DetectorType { KakaoTalk = 460; // Not yet implemented RiteKit = 461; Shutterstock = 462; - Text2Data = 463 [deprecated = true];; + Text2Data = 463 [deprecated = true]; YouNeedABudget = 464; Cricket = 465; // Not yet implemented Filestack = 466; // Not yet implemented @@ -668,7 +668,7 @@ enum DetectorType { Meistertask = 656; Mindmeister = 657; PeopleDataLabs = 658; - ScraperSite = 659 [deprecated = true]; + ScraperSite = 659 [deprecated = true]; Scrapfly = 660; SimplyNoted = 661; TravelPayouts = 662; @@ -790,7 +790,7 @@ enum DetectorType { TimeCamp = 778; Userflow = 779; Wistia = 780; - SportRadar = 781 [deprecated = true];; + SportRadar = 781 [deprecated = true]; UptimeRobot = 782; Codequiry = 783; ExtractorAPI = 784; @@ -878,7 +878,7 @@ enum DetectorType { Copyscape = 866; // Not yet implemented Besnappy = 867; Salesmate = 868; - Heatmapapi = 869 [deprecated = true];; + Heatmapapi = 869 [deprecated = true]; Websitepulse = 870; Uclassify = 871; Convert = 872; @@ -1049,6 +1049,13 @@ enum DetectorType { PhraseAccessToken = 1037; Photoroom = 1038; JWT = 1039; + Sportybet = 1046; + Interswitch = 1045; + Remita = 1044; + + + + OpenAIAdmin = 1040; GoogleGeminiAPIKey = 1041; ArtifactoryReferenceToken = 1042; @@ -1064,11 +1071,7 @@ message Result { StructuredData structured_data = 7; string hash_v2 = 8; DecoderType decoder_type = 9; - - // This field should only be populated if the verification process itself failed in a way that provides no information - // about the verification status of the candidate secret, such as if the verification request timed out. string verification_error_message = 10; - FalsePositiveInfo false_positive_info = 11; } @@ -1091,4 +1094,4 @@ message TlsPrivateKey { message GitHubSSHKey { string user = 1; string public_key_fingerprint = 2; -} +} \ No newline at end of file