[Detector]-Detector for tableau personal access token (#4261)

* add detector for tableau personal access token

* add test for tableau detector

* removed unnecessary checks

* add cloud endpoint for tableau

* cleanup: simplify map copying with maps.Copy

* resolve comments

* added correct detector type for tableau

* updated tableau PAT key and corrected integration tests

* resolved comments

* updated test cases

* resolved comments

* fixed integration tests

* removed redundant validation

* resolved false positive issue

* updated regex for pat-name

* resolved comments

* update regex for better token name extraction

* simplify prefix regex  for tableau pat name

* merged main into origin/detector/tableau-personal-access-token

---------

Co-authored-by: Amaan Ullah <[email protected]>
This commit is contained in:
SyedAliHamad
2025-07-28 21:42:58 +05:00
committed by GitHub
co-authored by Amaan Ullah
parent 98c36a4b2a
commit 05e2328da2
7 changed files with 691 additions and 7 deletions
+263
View File
@@ -0,0 +1,263 @@
package tableau
import (
"bytes"
"context"
"encoding/json"
"fmt"
"io"
"maps"
"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"
)
type Scanner struct {
detectors.DefaultMultiPartCredentialProvider
detectors.EndpointSetter
client *http.Client
}
// Ensure the Scanner satisfies the interface at compile time.
var _ detectors.Detector = (*Scanner)(nil)
var _ detectors.EndpointCustomizer = (*Scanner)(nil)
func (Scanner) CloudEndpoint() string { return "" }
var (
defaultClient = common.SaneHttpClient()
// Simplified token name pattern using PrefixRegex
tokenNamePat = regexp.MustCompile(detectors.PrefixRegex([]string{"pat", "token", "name", "tableau"}) + `([a-zA-Z][a-zA-Z0-9_-]{2,50})`)
// Pattern for Personal Access Token Secrets
tokenSecretPat = regexp.MustCompile(`\b([A-Za-z0-9+/]{22}==:[A-Za-z0-9]{32})\b`)
// Simplified Tableau Server URLs pattern
tableauURLPat = regexp.MustCompile(`\b([a-zA-Z0-9\-]+\.online\.tableau\.com)\b`)
)
// Keywords are used for efficiently pre-filtering chunks.
func (s Scanner) Keywords() []string {
return []string{
"tableau",
"online.tableau.com",
}
}
func (s Scanner) getClient() *http.Client {
if s.client != nil {
return s.client
}
return defaultClient
}
func (s Scanner) FromData(ctx context.Context, verify bool, data []byte) (results []detectors.Result, err error) {
dataStr := string(data)
// Extract token names, secrets, and URLs separately
tokenNames := extractTokenNames(dataStr)
tokenSecrets := extractTokenSecrets(dataStr)
foundURLs := extractTableauURLs(dataStr)
// If no names or secrets found, return empty results
if len(tokenNames) == 0 || len(tokenSecrets) == 0 {
return results, nil
}
// Use maps to deduplicate endpoints
var uniqueEndpoints = make(map[string]struct{})
// Add endpoints to the list
for _, endpoint := range s.Endpoints(foundURLs...) {
// Remove https:// prefix if present since we add it during verification
endpoint = strings.TrimPrefix(endpoint, "https://")
uniqueEndpoints[endpoint] = struct{}{}
}
// Process each combination of token name, token secret, and endpoint
for _, tokenName := range tokenNames {
for _, tokenSecret := range tokenSecrets {
for endpoint := range uniqueEndpoints {
result := detectors.Result{
DetectorType: detectorspb.DetectorType_TableauPersonalAccessToken,
Raw: []byte(tokenName),
RawV2: []byte(fmt.Sprintf("%s:%s:%s", tokenName, tokenSecret, endpoint)),
ExtraData: make(map[string]string),
}
if verify {
client := s.getClient()
isVerified, extraData, verificationErr := verifyTableauPAT(ctx, client, tokenName, tokenSecret, endpoint)
result.Verified = isVerified
maps.Copy(result.ExtraData, extraData)
result.SetVerificationError(verificationErr, tokenName, tokenSecret, endpoint)
}
results = append(results, result)
}
}
}
return results, nil
}
// extractTokenNames finds all potential token names in the data
func extractTokenNames(data string) []string {
var names []string
// Create a map of false positive terms
falsePositives := map[detectors.FalsePositive]struct{}{
detectors.FalsePositive("com"): {},
}
for _, match := range tokenNamePat.FindAllStringSubmatch(data, -1) {
if len(match) >= 2 {
name := strings.TrimSpace(match[1])
isFalsePositive, _ := detectors.IsKnownFalsePositive(name, falsePositives, false)
if !isFalsePositive {
names = append(names, name)
}
}
}
return names
}
// extractTokenSecrets finds all potential token secrets in the data
func extractTokenSecrets(data string) []string {
var secrets []string
for _, match := range tokenSecretPat.FindAllStringSubmatch(data, -1) {
if len(match) >= 2 {
secret := strings.TrimSpace(match[1])
secrets = append(secrets, secret)
}
}
return secrets
}
// extractTableauURLs finds all potential Tableau server URLs in the data
func extractTableauURLs(data string) []string {
var urls []string
for _, match := range tableauURLPat.FindAllStringSubmatch(data, -1) {
if len(match) >= 2 {
url := strings.TrimSpace(match[1])
if url != "" {
urls = append(urls, url)
}
}
}
return urls
}
// TableauAuthRequest represents the authentication request structure
type TableauAuthRequest struct {
Credentials TableauCredentials `json:"credentials"`
}
type TableauCredentials struct {
PersonalAccessTokenName string `json:"personalAccessTokenName"`
PersonalAccessTokenSecret string `json:"personalAccessTokenSecret"`
Site interface{} `json:"site"`
}
// TableauAuthResponse represents the authentication response structure
type TableauAuthResponse struct {
Credentials struct {
Site struct {
ID string `json:"id"`
ContentURL string `json:"contentUrl"`
} `json:"site"`
User struct {
ID string `json:"id"`
} `json:"user"`
Token string `json:"token"`
} `json:"credentials"`
}
// verifyTableauPAT verifies a Tableau Personal Access Token by attempting authentication
func verifyTableauPAT(ctx context.Context, client *http.Client, tokenName, tokenSecret, endpoint string) (bool, map[string]string, error) {
// Build the verification URL
verifyURL := fmt.Sprintf("https://%s/api/3.26/auth/signin", endpoint)
// Prepare metadata early - before any potential errors
extraData := map[string]string{
"verification_endpoint": verifyURL,
"verification_method": "tableau_pat_auth",
"tableau_endpoint": endpoint,
}
// Rest of your verification logic...
authReq := TableauAuthRequest{
Credentials: TableauCredentials{
PersonalAccessTokenName: tokenName,
PersonalAccessTokenSecret: tokenSecret,
Site: map[string]interface{}{},
},
}
// Marshal to JSON
jsonData, err := json.Marshal(authReq)
if err != nil {
return false, nil, fmt.Errorf("failed to marshal auth request: %v", err)
}
// Create HTTP request
req, err := http.NewRequestWithContext(ctx, http.MethodPost, verifyURL, bytes.NewBuffer(jsonData))
if err != nil {
return false, nil, fmt.Errorf("failed to create request: %v", err)
}
req.Header.Set("Content-Type", "application/json")
req.Header.Set("Accept", "application/json")
// Execute request
resp, err := client.Do(req)
if err != nil {
// Check if it's a DNS/network error
if strings.Contains(err.Error(), "no such host") ||
strings.Contains(err.Error(), "dial tcp") ||
strings.Contains(err.Error(), "connection refused") {
extraData["network_error"] = "true"
return false, extraData, nil // No error, just invalid endpoint
}
return false, nil, fmt.Errorf("request failed: %v", err)
}
defer func() {
_, _ = io.Copy(io.Discard, resp.Body)
_ = resp.Body.Close()
}()
// Read the response
bodyBytes, err := io.ReadAll(resp.Body)
if err != nil {
return false, nil, fmt.Errorf("failed to read response body: %v", err)
}
// Status code handling...
switch resp.StatusCode {
case http.StatusOK:
var authResp TableauAuthResponse
if err := json.Unmarshal(bodyBytes, &authResp); err != nil {
return true, extraData, err
}
return true, extraData, nil
case http.StatusUnauthorized, http.StatusBadRequest, http.StatusForbidden:
return false, extraData, nil
default:
return false, extraData, fmt.Errorf("unexpected HTTP response status %d", resp.StatusCode)
}
}
func (s Scanner) Type() detectorspb.DetectorType {
return detectorspb.DetectorType_TableauPersonalAccessToken
}
func (s Scanner) Description() string {
return "Tableau is a data visualization and business intelligence platform. Personal Access Tokens (PATs) provide programmatic access to Tableau Server/Online APIs and can be used to authenticate applications and automate workflows."
}
@@ -0,0 +1,266 @@
//go:build detectors
// +build detectors
package tableau
import (
"context"
"fmt"
"testing"
"time"
"github.com/google/go-cmp/cmp"
"github.com/google/go-cmp/cmp/cmpopts"
"github.com/trufflesecurity/trufflehog/v3/pkg/common"
"github.com/trufflesecurity/trufflehog/v3/pkg/detectors"
"github.com/trufflesecurity/trufflehog/v3/pkg/pb/detectorspb"
)
func TestTableau_FromChunk(t *testing.T) {
ctx, cancel := context.WithTimeout(context.Background(), time.Second*5)
defer cancel()
testSecrets, err := common.GetSecret(ctx, "trufflehog-testing", "detectors6")
if err != nil {
t.Fatalf("could not get test secrets from GCP: %s", err)
}
tokenName := testSecrets.MustGetField("TABLEAU_TOKEN_NAME")
tokenSecret := testSecrets.MustGetField("TABLEAU_TOKEN_SECRET")
inactiveTokenName := testSecrets.MustGetField("TABLEAU_INACTIVE_TOKEN_NAME")
inactiveTokenSecret := testSecrets.MustGetField("TABLEAU_INACTIVE_TOKEN_SECRET")
tableauURL := testSecrets.MustGetField("TABLEAU_VALID_POD_NAME")
invalidURL := testSecrets.MustGetField("TABLEAU_INVALID_POD_NAME")
type args struct {
ctx context.Context
data []byte
verify bool
}
tests := []struct {
name string
s Scanner
args args
want []detectors.Result
wantErr bool
wantVerificationErr bool
}{
{
name: "found, verified with URL",
s: Scanner{},
args: args{
ctx: context.Background(),
data: []byte(fmt.Sprintf("token=%s\nsecret=%s\nserver=%s", tokenName, tokenSecret, tableauURL)),
verify: true,
},
want: []detectors.Result{
{
DetectorType: detectorspb.DetectorType_TableauPersonalAccessToken,
Verified: true,
ExtraData: map[string]string{
"token_name": tokenName,
"token_secret": tokenSecret,
"endpoint": tableauURL,
"credential_type": "personal_access_token",
"verification_endpoint": "https://" + tableauURL + "/api/3.26/auth/signin",
"http_status": "200",
"verification_method": "tableau_pat_auth",
"verification_status": "valid",
"auth_token_received": "true",
},
},
},
wantErr: false,
},
{
name: "found, verified but unexpected api surface",
s: Scanner{client: common.ConstantResponseHttpClient(500, "Internal Server Error")},
args: args{
ctx: context.Background(),
data: []byte(fmt.Sprintf("name = '%s'\n secret = '%s'\nserver = '%s'", tokenName, tokenSecret, tableauURL)),
verify: true,
},
want: []detectors.Result{
{
DetectorType: detectorspb.DetectorType_TableauPersonalAccessToken,
Verified: false,
ExtraData: map[string]string{
"token_name": tokenName,
"token_secret": tokenSecret,
"endpoint": tableauURL,
"credential_type": "personal_access_token",
"verification_endpoint": "https://" + tableauURL + "/api/3.26/auth/signin",
"http_status": "500",
"verification_method": "tableau_pat_auth",
"verification_status": "error",
},
},
},
wantErr: false,
wantVerificationErr: true,
},
{
name: "found, unverified with invalid URL",
s: Scanner{},
args: args{
ctx: context.Background(),
data: []byte(fmt.Sprintf("name = '%s'\nsecret = '%s'\nserver = '%s'", tokenName, tokenSecret, invalidURL)),
verify: true,
},
want: []detectors.Result{
{
DetectorType: detectorspb.DetectorType_TableauPersonalAccessToken,
Verified: false,
ExtraData: map[string]string{
"token_name": tokenName,
"token_secret": tokenSecret,
"endpoint": invalidURL,
"credential_type": "personal_access_token",
"verification_endpoint": "https://" + invalidURL + "/api/3.26/auth/signin",
"http_status": "404", // or whatever status invalid URL returns
"verification_method": "tableau_pat_auth",
"verification_status": "error",
},
},
},
wantErr: false,
},
{
name: "found, unverified with inactive token",
s: Scanner{},
args: args{
ctx: context.Background(),
data: []byte(fmt.Sprintf("name = '%s'\n secret = '%s'\nserver = '%s'", inactiveTokenName, inactiveTokenSecret, tableauURL)),
verify: true,
},
want: []detectors.Result{
{
DetectorType: detectorspb.DetectorType_TableauPersonalAccessToken,
Verified: false,
ExtraData: map[string]string{
"token_name": inactiveTokenName,
"token_secret": inactiveTokenSecret,
"endpoint": tableauURL,
"credential_type": "personal_access_token",
"verification_endpoint": "https://" + tableauURL + "/api/3.26/auth/signin",
"http_status": "401",
"verification_method": "tableau_pat_auth",
"verification_status": "invalid",
},
},
},
wantErr: false,
},
{
name: "not found",
s: Scanner{},
args: args{
ctx: context.Background(),
data: []byte("You cannot find the tableau secret within"),
verify: true,
},
want: nil,
wantErr: false,
},
{
name: "found, unverified - malformed token",
s: Scanner{},
args: args{
ctx: context.Background(),
data: []byte("tableau pat_name = 'TestToken'\ntableau pat_secret = 'malformed_secret_format'"),
verify: true,
},
want: nil, // Should not find due to invalid secret format
wantErr: false,
},
{
name: "found multiple, mixed verification results with URLs",
s: Scanner{},
args: args{
ctx: context.Background(),
data: []byte(fmt.Sprintf(`
name1 = '%s'
name2 = '%s'
secret = '%s'
secret2 = '%s'
server1 = '%s'
server2 = '%s'
`, tokenName, inactiveTokenName, tokenSecret, inactiveTokenSecret, tableauURL, invalidURL)),
verify: true,
},
want: []detectors.Result{
{
DetectorType: detectorspb.DetectorType_TableauPersonalAccessToken,
Verified: true, // tokenName + tokenSecret + valid URL
},
{
DetectorType: detectorspb.DetectorType_TableauPersonalAccessToken,
Verified: false, // tokenName + tokenSecret + invalid URL
},
{
DetectorType: detectorspb.DetectorType_TableauPersonalAccessToken,
Verified: false, // tokenName + inactiveTokenSecret + valid URL
},
{
DetectorType: detectorspb.DetectorType_TableauPersonalAccessToken,
Verified: false, // tokenName + inactiveTokenSecret + invalid URL
},
{
DetectorType: detectorspb.DetectorType_TableauPersonalAccessToken,
Verified: false, // inactiveTokenName + tokenSecret + valid URL
},
{
DetectorType: detectorspb.DetectorType_TableauPersonalAccessToken,
Verified: false, // inactiveTokenName + tokenSecret + invalid URL
},
{
DetectorType: detectorspb.DetectorType_TableauPersonalAccessToken,
Verified: false, // inactiveTokenName + inactiveTokenSecret + valid URL
},
{
DetectorType: detectorspb.DetectorType_TableauPersonalAccessToken,
Verified: false, // inactiveTokenName + inactiveTokenSecret + invalid URL
},
},
wantErr: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
// Enable found endpoints for tests that need URL detection
scanner := tt.s
scanner.UseFoundEndpoints(true)
got, err := scanner.FromData(tt.args.ctx, tt.args.verify, tt.args.data)
if (err != nil) != tt.wantErr {
t.Errorf("Tableau.FromData() error = %v, wantErr %v", err, tt.wantErr)
return
}
// Check that we got the expected number of results
if len(got) != len(tt.want) {
t.Errorf("Tableau.FromData() got %d results, want %d", len(got), len(tt.want))
}
for i := range got {
if len(got[i].Raw) == 0 {
t.Fatalf("no raw secret present: \n %+v", got[i])
}
if (got[i].VerificationError() != nil) != tt.wantVerificationErr {
t.Errorf("Tableau.FromData() verificationError = %v, wantVerificationErr %v", got[i].VerificationError(), tt.wantVerificationErr)
}
}
ignoreOpts := []cmp.Option{
cmpopts.IgnoreFields(detectors.Result{}, "Raw", "RawV2", "verificationError", "ExtraData"),
cmpopts.IgnoreUnexported(detectors.Result{}),
}
if diff := cmp.Diff(got, tt.want, ignoreOpts...); diff != "" {
t.Errorf("Tableau.FromData() %s diff: (-got +want)\n%s", tt.name, diff)
}
})
}
}
+144
View File
@@ -0,0 +1,144 @@
package tableau
import (
"context"
"fmt"
"testing"
"github.com/google/go-cmp/cmp"
"github.com/trufflesecurity/trufflehog/v3/pkg/detectors"
"github.com/trufflesecurity/trufflehog/v3/pkg/engine/ahocorasick"
)
var (
validPATName = "test-token-6"
validPATSecret = "YMqNfVWiTSa0QgpoJ9GpCw==:KTamjuKrXF5gVETjIJafBBvP8Ctj5aJ3"
invalidPATSecret = "invalid-secret-format"
// Tableau Online endpoints for testing
validTableauURL = "prod-ansouthgest-a.online.tableau.com"
valid2ndTableauURL = "prod.online.tableau.com"
invalidTableauURL = "prod.tabeau.com"
)
func TestTableau_Pattern(t *testing.T) {
d := Scanner{}
d.UseFoundEndpoints(true) // Enable found endpoints for tests
ahoCorasickCore := ahocorasick.NewAhoCorasickCore([]detectors.Detector{d})
tests := []struct {
name string
input string
want []string
description string
}{
{
name: "tableau_prefix_with_token_name",
input: fmt.Sprintf("token=%s\nsecret=%s\nserver=%s", validPATName, validPATSecret, validTableauURL),
want: []string{fmt.Sprintf("%s:%s:%s", validPATName, validPATSecret, validTableauURL)},
description: "Tests tableau prefix directly followed by token name",
},
{
name: "pat_prefix_with_name",
input: fmt.Sprintf("pat %s\n%s\nurl=%s", validPATName, validPATSecret, validTableauURL),
want: []string{fmt.Sprintf("%s:%s:%s", validPATName, validPATSecret, validTableauURL)},
description: "Tests pat prefix triggering detection",
},
{
name: "name_prefix_with_token",
input: fmt.Sprintf("name %s\n%s\nurl=%s", validPATName, validPATSecret, validTableauURL),
want: []string{fmt.Sprintf("%s:%s:%s", validPATName, validPATSecret, validTableauURL)},
description: "Tests name prefix triggering detection",
},
{
name: "single_token_multiple_urls",
input: fmt.Sprintf("token %s\n%s\nserver1=%s\nserver2=%s", validPATName, validPATSecret, validTableauURL, valid2ndTableauURL),
want: []string{
fmt.Sprintf("%s:%s:%s", validPATName, validPATSecret, validTableauURL),
fmt.Sprintf("%s:%s:%s", validPATName, validPATSecret, valid2ndTableauURL),
},
description: "Tests single token with multiple URLs",
},
{
name: "invalid_secret_format",
input: fmt.Sprintf("tableau %s\n%s\nserver=%s", validPATName, invalidPATSecret, validTableauURL),
want: []string{},
description: "Tests that invalid secret format is not detected",
},
{
name: "invalid_tableau_url",
input: fmt.Sprintf("tableau %s\n%s\nserver=%s", validPATName, validPATSecret, invalidTableauURL),
want: []string{},
description: "Tests that invalid Tableau URL is not detected when useFoundEndpoints is true",
},
{
name: "missing_token_name",
input: fmt.Sprintf("\n%s\nserver=%s", validPATSecret, validTableauURL),
want: []string{},
description: "Tests that missing token name produces no results",
},
{
name: "missing_secret",
input: fmt.Sprintf("tableau %s\nserver=%s", validPATName, validTableauURL),
want: []string{},
description: "Tests that missing secret produces no results",
},
{
name: "no_tableau_keywords",
input: "username=test\npassword=secret123\nhost=example.com",
want: []string{},
description: "Tests that non-Tableau config produces no results",
},
{
name: "token_name_with_whitespace",
input: fmt.Sprintf("name %s\n%s\nserver=%s", validPATName, validPATSecret, validTableauURL),
want: []string{fmt.Sprintf("%s:%s:%s", validPATName, validPATSecret, validTableauURL)},
description: "Tests token name with extra whitespace",
},
{
name: "pat_with_single_quotes",
input: fmt.Sprintf("pat '%s'\n%s\nserver=%s", validPATName, validPATSecret, validTableauURL),
want: []string{fmt.Sprintf("%s:%s:%s", validPATName, validPATSecret, validTableauURL)},
description: "Tests token name with single quotes",
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
matchedDetectors := ahoCorasickCore.FindDetectorMatches([]byte(test.input))
if len(test.want) > 0 {
if len(matchedDetectors) == 0 {
t.Errorf("keywords '%v' not matched in input: %s", d.Keywords(), test.input)
return
}
}
if len(matchedDetectors) == 0 && len(test.want) == 0 {
return
}
results, err := d.FromData(context.Background(), false, []byte(test.input))
if err != nil {
t.Errorf("FromData error: %v", err)
return
}
if len(results) != len(test.want) {
t.Errorf("expected %d results, got %d", len(test.want), len(results))
return
}
actual := make(map[string]struct{}, len(results))
for _, r := range results {
actual[string(r.RawV2)] = 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)
}
})
}
}
+5
View File
@@ -725,6 +725,7 @@ import (
"github.com/trufflesecurity/trufflehog/v3/pkg/detectors/survicate"
"github.com/trufflesecurity/trufflehog/v3/pkg/detectors/swell"
"github.com/trufflesecurity/trufflehog/v3/pkg/detectors/swiftype"
"github.com/trufflesecurity/trufflehog/v3/pkg/detectors/tableau"
"github.com/trufflesecurity/trufflehog/v3/pkg/detectors/tailscale"
"github.com/trufflesecurity/trufflehog/v3/pkg/detectors/tallyfy"
"github.com/trufflesecurity/trufflehog/v3/pkg/detectors/tatumio"
@@ -1723,6 +1724,10 @@ func buildDetectorList() []detectors.Detector {
&zohocrm.Scanner{},
&zonkafeedback.Scanner{},
&zulipchat.Scanner{},
&stripepaymentintent.Scanner{},
&tableau.Scanner{},
&bitbucketapppassword.Scanner{},
&hasura.Scanner{},
}
}
+1 -1
View File
@@ -1228,7 +1228,7 @@ func TestEngineInitializesCloudProviderDetectors(t *testing.T) {
for _, det := range e.detectors {
if endpoints, ok := det.(interface{ Endpoints(...string) []string }); ok {
id := config.GetDetectorID(det)
if len(endpoints.Endpoints()) == 0 && det.Type() != detectorspb.DetectorType_ArtifactoryAccessToken { // artifactory does not have any cloud endpoint
if len(endpoints.Endpoints()) == 0 && det.Type() != detectorspb.DetectorType_ArtifactoryAccessToken && det.Type() != detectorspb.DetectorType_TableauPersonalAccessToken { // artifactory and tableau does not have any cloud endpoint
t.Fatalf("detector %q Endpoints() is empty", id.String())
}
count++
+11 -6
View File
@@ -1140,6 +1140,7 @@ const (
DetectorType_SalesforceRefreshToken DetectorType = 1031
DetectorType_AnypointOAuth2 DetectorType = 1032
DetectorType_WebexBot DetectorType = 1033
DetectorType_TableauPersonalAccessToken DetectorType = 1034
)
// Enum value maps for DetectorType.
@@ -2175,6 +2176,7 @@ var (
1031: "SalesforceRefreshToken",
1032: "AnypointOAuth2",
1033: "WebexBot",
1034: "TableauPersonalAccessToken",
}
DetectorType_value = map[string]int32{
"Alibaba": 0,
@@ -3207,6 +3209,7 @@ var (
"SalesforceRefreshToken": 1031,
"AnypointOAuth2": 1032,
"WebexBot": 1033,
"TableauPersonalAccessToken": 1034,
}
)
@@ -3660,7 +3663,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, 0xcb, 0x85, 0x01, 0x0a, 0x0c, 0x44, 0x65, 0x74, 0x65, 0x63, 0x74, 0x6f, 0x72,
0x10, 0x04, 0x2a, 0xec, 0x85, 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,
@@ -4729,11 +4732,13 @@ var file_detectors_proto_rawDesc = []byte{
0x66, 0x72, 0x65, 0x73, 0x68, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x10, 0x87, 0x08, 0x12, 0x13, 0x0a,
0x0e, 0x41, 0x6e, 0x79, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x4f, 0x41, 0x75, 0x74, 0x68, 0x32, 0x10,
0x88, 0x08, 0x12, 0x0d, 0x0a, 0x08, 0x57, 0x65, 0x62, 0x65, 0x78, 0x42, 0x6f, 0x74, 0x10, 0x89,
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, 0x1f, 0x0a, 0x1a, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x61, 0x75, 0x50, 0x65, 0x72, 0x73,
0x6f, 0x6e, 0x61, 0x6c, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x10,
0x8a, 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 (
+1
View File
@@ -1043,6 +1043,7 @@ enum DetectorType {
SalesforceRefreshToken = 1031;
AnypointOAuth2 = 1032;
WebexBot = 1033;
TableauPersonalAccessToken = 1034;
}
message Result {