From 23e8ae4a1e36dc591d3860a3d27a630f20ea5c56 Mon Sep 17 00:00:00 2001 From: Kashif Khan <70996046+kashifkhan0771@users.noreply.github.com> Date: Mon, 7 Oct 2024 21:39:54 +0500 Subject: [PATCH 01/76] improved the agora detector (#3360) * improved the agora detector * updated prefix keywords and test cases --------- Co-authored-by: Zachary Rice --- pkg/detectors/agora/agora.go | 27 ++++++++++++++++++--------- pkg/detectors/agora/agora_test.go | 30 +++++++++++++++++++++--------- 2 files changed, 39 insertions(+), 18 deletions(-) diff --git a/pkg/detectors/agora/agora.go b/pkg/detectors/agora/agora.go index 95ca02263136..d2da6f1eca74 100644 --- a/pkg/detectors/agora/agora.go +++ b/pkg/detectors/agora/agora.go @@ -27,8 +27,8 @@ var ( defaultClient = common.SaneHttpClient() // Make sure that your group is surrounded in boundary characters such as below to reduce false positives. - keyPat = regexp.MustCompile(detectors.PrefixRegex([]string{"agora"}) + `\b([a-z0-9]{32})\b`) - secretPat = regexp.MustCompile(detectors.PrefixRegex([]string{"agora"}) + `\b([a-z0-9]{32})\b`) + keyPat = regexp.MustCompile(detectors.PrefixRegex([]string{"agora", "key", "token"}) + `\b([a-z0-9]{32})\b`) + secretPat = regexp.MustCompile(detectors.PrefixRegex([]string{"agora", "secret"}) + `\b([a-z0-9]{32})\b`) ) // Keywords are used for efficiently pre-filtering chunks. @@ -48,21 +48,30 @@ func (s Scanner) getClient() *http.Client { func (s Scanner) FromData(ctx context.Context, verify bool, data []byte) (results []detectors.Result, err error) { dataStr := string(data) - matches := keyPat.FindAllStringSubmatch(dataStr, -1) + keyMatches := keyPat.FindAllStringSubmatch(dataStr, -1) secretMatches := secretPat.FindAllStringSubmatch(dataStr, -1) - for _, match := range matches { - if len(match) != 2 { + for _, keyMatch := range keyMatches { + if len(keyMatch) != 2 { continue } - resMatch := strings.TrimSpace(match[1]) + resMatch := strings.TrimSpace(keyMatch[1]) - for _, secret := range secretMatches { - if len(secret) != 2 { + for _, secretMatch := range secretMatches { + if len(secretMatch) != 2 { + continue + } + + resSecret := strings.TrimSpace(secretMatch[1]) + + /* + as both agora key and secretMatch has same regex, the set of strings keyMatch for both probably me same. + we need to avoid the scenario where key is same as secretMatch. This will reduce the number of matches we process. + */ + if resMatch == resSecret { continue } - resSecret := strings.TrimSpace(secret[1]) s1 := detectors.Result{ DetectorType: detectorspb.DetectorType_Agora, diff --git a/pkg/detectors/agora/agora_test.go b/pkg/detectors/agora/agora_test.go index 4a16637fea33..d515b8d0d004 100644 --- a/pkg/detectors/agora/agora_test.go +++ b/pkg/detectors/agora/agora_test.go @@ -3,7 +3,6 @@ package agora import ( "context" "fmt" - "strings" "testing" "github.com/google/go-cmp/cmp" @@ -13,7 +12,15 @@ import ( ) var ( - validPattern = "asdf0987mnbv1234qsxojb6ygb2wsx0o/beqr7215fr4g6bfjkmnvxrtygb2wsxap" + validKeyPattern = "asdf0987mnbv1234qsxojb6ygb2wsx0o" + validSecretPattern = "beqr7215fr4g6bfjkmnvxrtygb2wsxap" + complexPattern = `agora credentials + these are some example credentails for login. + use these to login. + key: asdf0987mnbv1234qsxojb6ygb2wsx0o + secret: beqr7215fr4g6bfjkmnvxrtygb2wsxap + loginUrl: https://www.agora.com/example_login + ` invalidPattern = "asdf0987mNbv1234qsxojb6ygb2w$x0o/beqr7215fr4g6bfjkmnVxrtygb2wsxap" ) @@ -28,23 +35,28 @@ func TestAgora_Pattern(t *testing.T) { }{ { name: "valid pattern", - input: fmt.Sprintf("agora = '%s'", validPattern), - want: []string{"asdf0987mnbv1234qsxojb6ygb2wsx0oasdf0987mnbv1234qsxojb6ygb2wsx0o"}, + input: fmt.Sprintf("agora key='%s' - secret='%s'", validKeyPattern, validSecretPattern), + want: []string{validKeyPattern + validSecretPattern}, + }, + { + name: "valid complex pattern", + input: fmt.Sprintf("agora data='%s'", complexPattern), + want: []string{validKeyPattern + validSecretPattern}, }, { name: "valid pattern - out of prefix range", - input: fmt.Sprintf("agora keyword is not close to the real key and secret = '%s'", validPattern), + input: fmt.Sprintf("agora keyword is not close to the real key or secret = '%s|%s'", validKeyPattern, validSecretPattern), want: nil, }, { name: "valid pattern - only key", - input: fmt.Sprintf("agora %s", strings.Split(validPattern, "/")[0]), - want: []string{"asdf0987mnbv1234qsxojb6ygb2wsx0oasdf0987mnbv1234qsxojb6ygb2wsx0o"}, + input: fmt.Sprintf("agora key%s", validKeyPattern), + want: nil, }, { name: "valid pattern - only secret", - input: fmt.Sprintf("agora %s", strings.Split(validPattern, "/")[1]), - want: []string{"beqr7215fr4g6bfjkmnvxrtygb2wsxapbeqr7215fr4g6bfjkmnvxrtygb2wsxap"}, + input: fmt.Sprintf("agora secret%s", validSecretPattern), + want: nil, }, { name: "invalid pattern", From ce5da505a72d2d9a7fed0e825bb312ae24ef3d74 Mon Sep 17 00:00:00 2001 From: Kashif Khan <70996046+kashifkhan0771@users.noreply.github.com> Date: Mon, 7 Oct 2024 22:00:45 +0500 Subject: [PATCH 02/76] Added Cisco Meraki API Key detector (#3367) * Added cisco meraki apikey detector * addressed the comments * handled api response and saving orgs data in extra data * fixed linter --------- Co-authored-by: Zachary Rice --- pkg/detectors/meraki/meraki.go | 135 ++ .../meraki/meraki_integration_test.go | 158 ++ pkg/detectors/meraki/meraki_test.go | 102 + pkg/engine/defaults.go | 2 + pkg/pb/detectorspb/detectors.pb.go | 2009 +++++++++-------- proto/detectors.proto | 1 + 6 files changed, 1404 insertions(+), 1003 deletions(-) create mode 100644 pkg/detectors/meraki/meraki.go create mode 100644 pkg/detectors/meraki/meraki_integration_test.go create mode 100644 pkg/detectors/meraki/meraki_test.go diff --git a/pkg/detectors/meraki/meraki.go b/pkg/detectors/meraki/meraki.go new file mode 100644 index 000000000000..9aed559f4861 --- /dev/null +++ b/pkg/detectors/meraki/meraki.go @@ -0,0 +1,135 @@ +package meraki + +import ( + "context" + "encoding/json" + "fmt" + regexp "github.com/wasilibs/go-re2" + "io" + "net/http" + + "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 { + client *http.Client +} + +// merakiOrganizations is the partial response from the /organizations api of cisco Meraki. +// api docs: https://developer.cisco.com/meraki/api-v1/get-organizations/ +type merakiOrganizations struct { + ID string `json:"id"` + Name string `json:"name"` +} + +// Ensure the Scanner satisfies the interface at compile time. +var _ detectors.Detector = (*Scanner)(nil) + +var ( + defaultClient = common.SaneHttpClient() + + apiKey = regexp.MustCompile(detectors.PrefixRegex([]string{"meraki"}) + `([0-9a-f]{40})`) +) + +func (s Scanner) getClient() *http.Client { + if s.client != nil { + return s.client + } + + return defaultClient +} + +// 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{"meraki"} +} + +func (s Scanner) Description() string { + return "Cisco Meraki is a cloud-managed IT solution that provides networking, security, and device management through an easy-to-use interface." + + "Meraki APIs make it possible to rapidly deploy and manage networks at scale, build on a platform of intelligent, cloud-connected IT products, and engage with users in powerful new ways." +} + +// FromData will find and optionally verify Meraki API Key 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) + + // uniqueMatches will hold unique match values and ensure we only process unique matches found in the data string + var uniqueMatches = make(map[string]struct{}) + + for _, match := range apiKey.FindAllStringSubmatch(dataStr, -1) { + uniqueMatches[match[1]] = struct{}{} + } + + for match := range uniqueMatches { + s1 := detectors.Result{ + DetectorType: detectorspb.DetectorType_Meraki, + Raw: []byte(match), + ExtraData: make(map[string]string), + } + + if verify { + client := s.getClient() + organizations, isVerified, verificationErr := verifyMerakiApiKey(ctx, client, match) + s1.Verified = isVerified + if verificationErr != nil { + s1.SetVerificationError(verificationErr) + } + + // if organizations are not nil, which means token was verified. + for _, org := range organizations { + // format: ExtraData{"organization_1": "Example", organization_2": "Example"} + s1.ExtraData[fmt.Sprintf("organization_%s", org.ID)] = org.Name + } + + } + + results = append(results, s1) + } + + return results, nil +} + +func (s Scanner) Type() detectorspb.DetectorType { + return detectorspb.DetectorType_Meraki +} + +/* +verifyMerakiApiKey verifies if the passed matched api key for meraki is active or not. +docs: https://developer.cisco.com/meraki/api-v1/authorization/#authorization +*/ +func verifyMerakiApiKey(ctx context.Context, client *http.Client, match string) ([]merakiOrganizations, bool, error) { + req, err := http.NewRequestWithContext(ctx, "GET", "https://api.meraki.com/api/v1/organizations", http.NoBody) + if err != nil { + return nil, false, err + } + + // set the required auth header + req.Header.Set("X-Cisco-Meraki-API-Key", match) + + resp, err := client.Do(req) + if err != nil { + return nil, false, err + } + defer func() { + _, _ = io.Copy(io.Discard, resp.Body) + _ = resp.Body.Close() + }() + + switch resp.StatusCode { + case http.StatusOK: + // in case token is verified, capture the organization id's and name which are accessible via token. + var organizations []merakiOrganizations + if err = json.NewDecoder(resp.Body).Decode(&organizations); err != nil { + return nil, false, err + } + + return organizations, true, nil + case http.StatusUnauthorized: + return nil, false, nil + default: + return nil, false, fmt.Errorf("unexpected status code: %d", resp.StatusCode) + } +} diff --git a/pkg/detectors/meraki/meraki_integration_test.go b/pkg/detectors/meraki/meraki_integration_test.go new file mode 100644 index 000000000000..030a9dfcf8ee --- /dev/null +++ b/pkg/detectors/meraki/meraki_integration_test.go @@ -0,0 +1,158 @@ +package meraki + +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 TestMeraki_FromChunk(t *testing.T) { + ctx, cancel := context.WithTimeout(context.Background(), time.Second*5) + defer cancel() + testSecrets, err := common.GetSecret(ctx, "trufflehog-testing", "detectors5") + if err != nil { + t.Fatalf("could not get test secrets from GCP: %s", err) + } + secret := testSecrets.MustGetField("MERAKI") + inactiveSecret := testSecrets.MustGetField("MERAKI_INACTIVE") + + 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", + s: Scanner{}, + args: args{ + ctx: ctx, + data: []byte(fmt.Sprintf("You can find a meraki apikey %s within", secret)), + verify: true, + }, + want: []detectors.Result{ + { + DetectorType: detectorspb.DetectorType_Meraki, + Verified: true, + }, + }, + wantErr: false, + wantVerificationErr: false, + }, + { + name: "found, unverified", + s: Scanner{}, + args: args{ + ctx: ctx, + data: []byte(fmt.Sprintf("You can find a meraki apikey secret %s within but not valid", inactiveSecret)), // the secret would satisfy the regex but not pass validation + verify: true, + }, + want: []detectors.Result{ + { + DetectorType: detectorspb.DetectorType_Meraki, + Verified: false, + }, + }, + wantErr: false, + wantVerificationErr: false, + }, + { + name: "not found", + s: Scanner{}, + args: args{ + ctx: context.Background(), + data: []byte("You cannot find the secret within"), + verify: true, + }, + want: nil, + wantErr: false, + wantVerificationErr: false, + }, + { + name: "found, would be verified if not for timeout", + s: Scanner{client: common.SaneHttpClientTimeOut(1 * time.Microsecond)}, + args: args{ + ctx: context.Background(), + data: []byte(fmt.Sprintf("You can find a meraki apikey %s within", secret)), + verify: true, + }, + want: []detectors.Result{ + { + DetectorType: detectorspb.DetectorType_Meraki, + Verified: false, + }, + }, + wantErr: false, + wantVerificationErr: true, + }, + { + name: "found, verified but unexpected api surface", + s: Scanner{client: common.ConstantResponseHttpClient(500, "")}, + args: args{ + ctx: context.Background(), + data: []byte(fmt.Sprintf("You can find a meraki secret %s within", secret)), + verify: true, + }, + want: []detectors.Result{ + { + DetectorType: detectorspb.DetectorType_Meraki, + Verified: false, + }, + }, + wantErr: false, + wantVerificationErr: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := tt.s.FromData(tt.args.ctx, tt.args.verify, tt.args.data) + if (err != nil) != tt.wantErr { + t.Errorf("Meraki.FromData() error = %v, wantErr %v", err, tt.wantErr) + return + } + 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.Fatalf("wantVerificationError = %v, verification error = %v", tt.wantVerificationErr, got[i].VerificationError()) + } + } + ignoreOpts := cmpopts.IgnoreFields(detectors.Result{}, "Raw", "verificationError") + if diff := cmp.Diff(got, tt.want, ignoreOpts); diff != "" { + t.Errorf("Meraki.FromData() %s diff: (-got +want)\n%s", tt.name, diff) + } + }) + } +} + +func BenchmarkFromData(benchmark *testing.B) { + ctx := context.Background() + s := Scanner{} + for name, data := range detectors.MustGetBenchmarkData() { + benchmark.Run(name, func(b *testing.B) { + b.ResetTimer() + for n := 0; n < b.N; n++ { + _, err := s.FromData(ctx, false, data) + if err != nil { + b.Fatal(err) + } + } + }) + } +} diff --git a/pkg/detectors/meraki/meraki_test.go b/pkg/detectors/meraki/meraki_test.go new file mode 100644 index 000000000000..d59e5e9c82c6 --- /dev/null +++ b/pkg/detectors/meraki/meraki_test.go @@ -0,0 +1,102 @@ +package meraki + +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 ( + // example picked from: https://github.com/CiscoLearning/ciscolive-ltrcrt-1100/blob/cd0b8f14883ccd70e2db370f8f7a36534bdfe073/02-intro-python/code/meraki_api_info.md?plain=1#L8 + validPattern = `Information used in API calls for meraki +Variable name | Initial Value +apiKey |e9e0f062f587b423bb6cc6328eb786d75b45783e +baseUrl |https://api.meraki.com/api/v1 +organizationId |646829496481091262 +networkId |L_646829496481117067 +serial |` + + validPatternWithNoKeyword = `Information used in API calls +Variable name | Initial Value +apiKey |e9e0f062f587b423bb6cc6328eb786d75b45783e +baseUrl |https://api.meraki.com/api/v1 +organizationId |646829496481091262 +networkId |L_646829496481117067 +serial |` + + invalidPattern = "001A1E0092C7a711d7679d%d0d442d59b05ce65D" +) + +func TestMeraki_Pattern(t *testing.T) { + d := Scanner{} + ahoCorasickCore := ahocorasick.NewAhoCorasickCore([]detectors.Detector{d}) + + tests := []struct { + name string + input string + want []string + }{ + { + name: "valid pattern", + input: fmt.Sprintf("meraki token = '%s'", validPattern), + want: []string{"e9e0f062f587b423bb6cc6328eb786d75b45783e"}, + }, + { + name: "valid pattern - out of prefix range", + input: fmt.Sprintf("meraki token keyword is not close to the real token = '%s'", validPatternWithNoKeyword), + want: nil, + }, + { + name: "invalid pattern", + input: fmt.Sprintf("meraki = '%s'", invalidPattern), + want: nil, + }, + } + + 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.go b/pkg/engine/defaults.go index 7bebe8197f63..16529d3a3102 100644 --- a/pkg/engine/defaults.go +++ b/pkg/engine/defaults.go @@ -428,6 +428,7 @@ import ( "github.com/trufflesecurity/trufflehog/v3/pkg/detectors/meaningcloud" "github.com/trufflesecurity/trufflehog/v3/pkg/detectors/mediastack" "github.com/trufflesecurity/trufflehog/v3/pkg/detectors/meistertask" + "github.com/trufflesecurity/trufflehog/v3/pkg/detectors/meraki" "github.com/trufflesecurity/trufflehog/v3/pkg/detectors/mesibo" "github.com/trufflesecurity/trufflehog/v3/pkg/detectors/messagebird" "github.com/trufflesecurity/trufflehog/v3/pkg/detectors/metaapi" @@ -1634,6 +1635,7 @@ func DefaultDetectors() []detectors.Detector { robinhoodcrypto.Scanner{}, nvapi.Scanner{}, railwayapp.Scanner{}, + meraki.Scanner{}, } // Automatically initialize all detectors that implement diff --git a/pkg/pb/detectorspb/detectors.pb.go b/pkg/pb/detectorspb/detectors.pb.go index c5263a63fd38..bf7cd9fc0350 100644 --- a/pkg/pb/detectorspb/detectors.pb.go +++ b/pkg/pb/detectorspb/detectors.pb.go @@ -1101,1007 +1101,1009 @@ const ( DetectorType_NVAPI DetectorType = 997 DetectorType_PyPI DetectorType = 998 DetectorType_RailwayApp DetectorType = 999 + DetectorType_Meraki DetectorType = 1000 ) // Enum value maps for DetectorType. var ( DetectorType_name = map[int32]string{ - 0: "Alibaba", - 1: "AMQP", - 2: "AWS", - 3: "Azure", - 4: "Circle", - 5: "Coinbase", - 6: "GCP", - 7: "Generic", - 8: "Github", - 9: "Gitlab", - 10: "JDBC", - 11: "RazorPay", - 12: "SendGrid", - 13: "Slack", - 14: "Square", - 15: "PrivateKey", - 16: "Stripe", - 17: "URI", - 18: "Dropbox", - 19: "Heroku", - 20: "Mailchimp", - 21: "Okta", - 22: "OneLogin", - 23: "PivotalTracker", - 25: "SquareApp", - 26: "Twilio", - 27: "Test", - 29: "TravisCI", - 30: "SlackWebhook", - 31: "PaypalOauth", - 32: "PagerDutyApiKey", - 33: "Firebase", - 34: "Mailgun", - 35: "HubSpot", - 36: "GitHubApp", - 37: "CircleCI", - 38: "WpEngine", - 39: "DatadogToken", - 40: "FacebookOAuth", - 41: "AsanaPersonalAccessToken", - 42: "AmplitudeApiKey", - 43: "BitLyAccessToken", - 44: "CalendlyApiKey", - 45: "ZapierWebhook", - 46: "YoutubeApiKey", - 47: "SalesforceOauth2", - 48: "TwitterApiSecret", - 49: "NpmToken", - 50: "NewRelicPersonalApiKey", - 51: "AirtableApiKey", - 52: "AkamaiToken", - 53: "AmazonMWS", - 54: "KubeConfig", - 55: "Auth0oauth", - 56: "Bitfinex", - 57: "Clarifai", - 58: "CloudflareGlobalApiKey", - 59: "CloudflareCaKey", - 60: "Confluent", - 61: "ContentfulDelivery", - 62: "DatabricksToken", - 63: "DigitalOceanSpaces", - 64: "DigitalOceanToken", - 65: "DiscordBotToken", - 66: "DiscordWebhook", - 67: "EtsyApiKey", - 68: "FastlyPersonalToken", - 69: "GoogleOauth2", - 70: "ReCAPTCHA", - 71: "GoogleApiKey", - 72: "Hunter", - 73: "IbmCloudUserKey", - 74: "Netlify", - 75: "Vonage", - 76: "EquinixOauth", - 77: "Paystack", - 78: "PlaidToken", - 79: "PlaidKey", - 80: "Plivo", - 81: "Postmark", - 82: "PubNubPublishKey", - 83: "PubNubSubscriptionKey", - 84: "PusherChannelKey", - 85: "ScalewayKey", - 86: "SendinBlueV2", - 87: "SentryToken", - 88: "ShodanKey", - 89: "SnykKey", - 90: "SpotifyKey", - 91: "TelegramBotToken", - 92: "TencentCloudKey", - 93: "TerraformCloudPersonalToken", - 94: "TrelloApiKey", - 95: "ZendeskApi", - 96: "MaxMindLicense", - 97: "AirtableMetadataApiKey", - 98: "AsanaOauth", - 99: "RapidApi", - 100: "CloudflareApiToken", - 101: "Webex", - 102: "FirebaseCloudMessaging", - 103: "ContentfulPersonalAccessToken", - 104: "MapBox", - 105: "MailJetBasicAuth", - 106: "MailJetSMS", - 107: "HubSpotApiKey", - 108: "HubSpotOauth", - 109: "SslMate", - 110: "Auth0ManagementApiToken", - 111: "MessageBird", - 112: "ElasticEmail", - 113: "FigmaPersonalAccessToken", - 114: "MicrosoftTeamsWebhook", - 115: "GitHubOld", - 116: "VultrApiKey", - 117: "Pepipost", - 118: "Postman", - 119: "CloudsightKey", - 120: "JiraToken", - 121: "NexmoApiKey", - 122: "SegmentApiKey", - 123: "SumoLogicKey", - 124: "PushBulletApiKey", - 125: "AirbrakeProjectKey", - 126: "AirbrakeUserKey", - 127: "PendoIntegrationKey", - 128: "SplunkOberservabilityToken", - 129: "LokaliseToken", - 130: "Calendarific", - 131: "Jumpcloud", - 133: "IpStack", - 134: "Notion", - 135: "DroneCI", - 136: "AdobeIO", - 137: "TwelveData", - 138: "D7Network", - 139: "ScrapingBee", - 140: "KeenIO", - 141: "Wakatime", - 142: "Buildkite", - 143: "Verimail", - 144: "Zerobounce", - 145: "Mailboxlayer", - 146: "Fastspring", - 147: "Paddle", - 148: "Sellfy", - 149: "FixerIO", - 150: "ButterCMS", - 151: "Taxjar", - 152: "Avalara", - 153: "Helpscout", - 154: "ElasticPath", - 155: "Zeplin", - 156: "Intercom", - 157: "Mailmodo", - 158: "CannyIo", - 159: "Pipedrive", - 160: "Vercel", - 161: "PosthogApp", - 162: "SinchMessage", - 163: "Ayrshare", - 164: "HelpCrunch", - 165: "LiveAgent", - 166: "Beamer", - 167: "WeChatAppKey", - 168: "LineMessaging", - 169: "UberServerToken", - 170: "AlgoliaAdminKey", - 171: "FullContact", - 172: "Mandrill", - 173: "Flutterwave", - 174: "MattermostPersonalToken", - 175: "Cloudant", - 176: "LineNotify", - 177: "LinearAPI", - 178: "Ubidots", - 179: "Anypoint", - 180: "Dwolla", - 181: "ArtifactoryAccessToken", - 182: "Surge", - 183: "Sparkpost", - 184: "GoCardless", - 185: "Codacy", - 186: "Kraken", - 187: "Checkout", - 188: "Kairos", - 189: "ClockworkSMS", - 190: "Atlassian", - 191: "LaunchDarkly", - 192: "Coveralls", - 193: "Linode", - 194: "WePay", - 195: "PlanetScale", - 196: "Doppler", - 197: "Agora", - 198: "Samsara", - 199: "FrameIO", - 200: "RubyGems", - 201: "OpenAI", - 202: "SurveySparrow", - 203: "Simvoly", - 204: "Survicate", - 205: "Omnisend", - 206: "Groovehq", - 207: "Newsapi", - 208: "Chatbot", - 209: "ClickSendsms", - 210: "Getgist", - 211: "CustomerIO", - 212: "ApiDeck", - 213: "Nftport", - 214: "Copper", - 215: "Close", - 216: "Myfreshworks", - 217: "Salesflare", - 218: "Webflow", - 219: "Duda", - 220: "Yext", - 221: "ContentStack", - 222: "Storyblok", - 223: "GraphCMS", - 224: "Checkmarket", - 225: "Convertkit", - 226: "CustomerGuru", - 227: "Kaleyra", - 228: "Mailerlite", - 229: "Qualaroo", - 230: "SatismeterProjectkey", - 231: "SatismeterWritekey", - 232: "Simplesat", - 233: "SurveyAnyplace", - 234: "SurveyBot", - 235: "Webengage", - 236: "ZonkaFeedback", - 237: "Delighted", - 238: "Feedier", - 239: "Abbysale", - 240: "Magnetic", - 241: "Nytimes", - 242: "Polygon", - 243: "Powrbot", - 244: "ProspectIO", - 245: "Skrappio", - 246: "Monday", - 247: "Smartsheets", - 248: "Wrike", - 249: "Float", - 250: "Imagekit", - 251: "Integromat", - 252: "Salesblink", - 253: "Bored", - 254: "Campayn", - 255: "Clinchpad", - 256: "CompanyHub", - 257: "Debounce", - 258: "Dyspatch", - 259: "Guardianapi", - 260: "Harvest", - 261: "Moosend", - 262: "OpenWeather", - 263: "Siteleaf", - 264: "Squarespace", - 265: "FlowFlu", - 266: "Nimble", - 267: "LessAnnoyingCRM", - 268: "Nethunt", - 269: "Apptivo", - 270: "CapsuleCRM", - 271: "Insightly", - 272: "Kylas", - 273: "OnepageCRM", - 274: "User", - 275: "ProspectCRM", - 276: "ReallySimpleSystems", - 277: "Airship", - 278: "Artsy", - 279: "Yandex", - 280: "Clockify", - 281: "Dnscheck", - 282: "EasyInsight", - 283: "Ethplorer", - 284: "Everhour", - 285: "Fulcrum", - 286: "GeoIpifi", - 287: "Jotform", - 288: "Refiner", - 289: "Timezoneapi", - 290: "TogglTrack", - 291: "Vpnapi", - 292: "Workstack", - 293: "Apollo", - 294: "Eversign", - 295: "Juro", - 296: "KarmaCRM", - 297: "Metrilo", - 298: "Pandadoc", - 299: "RevampCRM", - 300: "Salescookie", - 301: "Alconost", - 302: "Blogger", - 303: "Accuweather", - 304: "Opengraphr", - 305: "Rawg", - 306: "Riotgames", - 307: "RoninApp", - 308: "Stormglass", - 309: "Tomtom", - 310: "Twitch", - 311: "Documo", - 312: "Cloudways", - 313: "Veevavault", - 314: "KiteConnect", - 315: "ShopeeOpenPlatform", - 316: "TeamViewer", - 317: "Bulbul", - 318: "CentralStationCRM", - 319: "Teamgate", - 320: "Axonaut", - 321: "Tyntec", - 322: "Appcues", - 323: "Autoklose", - 324: "Cloudplan", - 325: "Dotmailer", - 326: "GetEmail", - 327: "GetEmails", - 328: "Kontent", - 329: "Leadfeeder", - 330: "Raven", - 331: "RocketReach", - 332: "Uplead", - 333: "Brandfetch", - 334: "Clearbit", - 335: "Crowdin", - 336: "Mapquest", - 337: "Noticeable", - 338: "Onbuka", - 339: "Todoist", - 340: "Storychief", - 341: "LinkedIn", - 342: "YouSign", - 343: "Docker", - 344: "Telesign", - 345: "Spoonacular", - 346: "Aerisweather", - 347: "Alphavantage", - 348: "Imgur", - 349: "Imagga", - 350: "SMSApi", - 351: "Distribusion", - 352: "Blablabus", - 353: "WordsApi", - 354: "Currencylayer", - 355: "Html2Pdf", - 356: "IPGeolocation", - 357: "Owlbot", - 358: "Cloudmersive", - 359: "Dynalist", - 360: "ExchangeRateAPI", - 361: "HolidayAPI", - 362: "Ipapi", - 363: "Marketstack", - 364: "Nutritionix", - 365: "Swell", - 366: "ClickupPersonalToken", - 367: "Nitro", - 368: "Rev", - 369: "RunRunIt", - 370: "Typeform", - 371: "Mixpanel", - 372: "Tradier", - 373: "Verifier", - 374: "Vouchery", - 375: "Alegra", - 376: "Audd", - 377: "Baremetrics", - 378: "Coinlib", - 379: "ExchangeRatesAPI", - 380: "CurrencyScoop", - 381: "FXMarket", - 382: "CurrencyCloud", - 383: "GetGeoAPI", - 384: "Abstract", - 385: "Billomat", - 386: "Dovico", - 387: "Bitbar", - 388: "Bugsnag", - 389: "AssemblyAI", - 390: "AdafruitIO", - 391: "Apify", - 392: "CoinGecko", - 393: "CryptoCompare", - 394: "Fullstory", - 395: "HelloSign", - 396: "Loyverse", - 397: "NetCore", - 398: "SauceLabs", - 399: "AlienVault", - 401: "Apiflash", - 402: "Coinlayer", - 403: "CurrentsAPI", - 404: "DataGov", - 405: "Enigma", - 406: "FinancialModelingPrep", - 407: "Geocodio", - 408: "HereAPI", - 409: "Macaddress", - 410: "OOPSpam", - 411: "ProtocolsIO", - 412: "ScraperAPI", - 413: "SecurityTrails", - 414: "TomorrowIO", - 415: "WorldCoinIndex", - 416: "FacePlusPlus", - 417: "Voicegain", - 418: "Deepgram", - 419: "VisualCrossing", - 420: "Finnhub", - 421: "Tiingo", - 422: "RingCentral", - 423: "Finage", - 424: "Edamam", - 425: "HypeAuditor", - 426: "Gengo", - 427: "Front", - 428: "Fleetbase", - 429: "Bubble", - 430: "Bannerbear", - 431: "Adzuna", - 432: "BitcoinAverage", - 433: "CommerceJS", - 434: "DetectLanguage", - 435: "FakeJSON", - 436: "Graphhopper", - 437: "Lexigram", - 438: "LinkPreview", - 439: "Numverify", - 440: "ProxyCrawl", - 441: "ZipCodeAPI", - 442: "Cometchat", - 443: "Keygen", - 444: "Mixcloud", - 445: "TatumIO", - 446: "Tmetric", - 447: "Lastfm", - 448: "Browshot", - 449: "JSONbin", - 450: "LocationIQ", - 451: "ScreenshotAPI", - 452: "WeatherStack", - 453: "Amadeus", - 454: "FourSquare", - 455: "Flickr", - 456: "ClickHelp", - 457: "Ambee", - 458: "Api2Cart", - 459: "Hypertrack", - 460: "KakaoTalk", - 461: "RiteKit", - 462: "Shutterstock", - 463: "Text2Data", - 464: "YouNeedABudget", - 465: "Cricket", - 466: "Filestack", - 467: "Gyazo", - 468: "Mavenlink", - 469: "Sheety", - 470: "Sportsmonk", - 471: "Stockdata", - 472: "Unsplash", - 473: "Allsports", - 474: "CalorieNinja", - 475: "WalkScore", - 476: "Strava", - 477: "Cicero", - 478: "IPQuality", - 479: "ParallelDots", - 480: "Roaring", - 481: "Mailsac", - 482: "Whoxy", - 483: "WorldWeather", - 484: "ApiFonica", - 485: "Aylien", - 486: "Geocode", - 487: "IconFinder", - 488: "Ipify", - 489: "LanguageLayer", - 490: "Lob", - 491: "OnWaterIO", - 492: "Pastebin", - 493: "PdfLayer", - 494: "Pixabay", - 495: "ReadMe", - 496: "VatLayer", - 497: "VirusTotal", - 498: "AirVisual", - 499: "Currencyfreaks", - 500: "Duffel", - 501: "FlatIO", - 502: "M3o", - 503: "Mesibo", - 504: "Openuv", - 505: "Snipcart", - 506: "Besttime", - 507: "Happyscribe", - 508: "Humanity", - 509: "Impala", - 510: "Loginradius", - 511: "AutoPilot", - 512: "Bitmex", - 513: "ClustDoc", - 514: "Messari", - 515: "PdfShift", - 516: "Poloniex", - 517: "RestpackHtmlToPdfAPI", - 518: "RestpackScreenshotAPI", - 519: "ShutterstockOAuth", - 520: "SkyBiometry", - 521: "AbuseIPDB", - 522: "AletheiaApi", - 523: "BlitApp", - 524: "Censys", - 525: "Cloverly", - 526: "CountryLayer", - 527: "FileIO", - 528: "FlightApi", - 529: "Geoapify", - 530: "IPinfoDB", - 531: "MediaStack", - 532: "NasdaqDataLink", - 533: "OpenCageData", - 534: "Paymongo", - 535: "PositionStack", - 536: "Rebrandly", - 537: "ScreenshotLayer", - 538: "Stytch", - 539: "Unplugg", - 540: "UPCDatabase", - 541: "UserStack", - 542: "Geocodify", - 543: "Newscatcher", - 544: "Nicereply", - 545: "Partnerstack", - 546: "Route4me", - 547: "Scrapeowl", - 548: "ScrapingDog", - 549: "Streak", - 550: "Veriphone", - 551: "Webscraping", - 552: "Zenscrape", - 553: "Zenserp", - 554: "CoinApi", - 555: "Gitter", - 556: "Host", - 557: "Iexcloud", - 558: "Restpack", - 559: "ScraperBox", - 560: "ScrapingAnt", - 561: "SerpStack", - 562: "SmartyStreets", - 563: "TicketMaster", - 564: "AviationStack", - 565: "BombBomb", - 566: "Commodities", - 567: "Dfuse", - 568: "EdenAI", - 569: "Glassnode", - 570: "Guru", - 571: "Hive", - 572: "Hiveage", - 573: "Kickbox", - 574: "Passbase", - 575: "PostageApp", - 576: "PureStake", - 577: "Qubole", - 578: "CarbonInterface", - 579: "Intrinio", - 580: "QuickMetrics", - 581: "ScrapeStack", - 582: "TechnicalAnalysisApi", - 583: "Urlscan", - 584: "BaseApiIO", - 585: "DailyCO", - 586: "TLy", - 587: "Shortcut", - 588: "Appfollow", - 589: "Thinkific", - 590: "Feedly", - 591: "Stitchdata", - 592: "Fetchrss", - 593: "Signupgenius", - 594: "Signaturit", - 595: "Optimizely", - 596: "OcrSpace", - 597: "WeatherBit", - 598: "BuddyNS", - 599: "ZipAPI", - 600: "ZipBooks", - 601: "Onedesk", - 602: "Bugherd", - 603: "Blazemeter", - 604: "Autodesk", - 605: "Tru", - 606: "UnifyID", - 607: "Trimble", - 608: "Smooch", - 609: "Semaphore", - 610: "Telnyx", - 611: "Signalwire", - 612: "Textmagic", - 613: "Serphouse", - 614: "Planyo", - 615: "Simplybook", - 616: "Vyte", - 617: "Nylas", - 618: "Squareup", - 619: "Dandelion", - 620: "DataFire", - 621: "DeepAI", - 622: "MeaningCloud", - 623: "NeutrinoApi", - 624: "Storecove", - 625: "Shipday", - 626: "Sentiment", - 627: "StreamChatMessaging", - 628: "TeamworkCRM", - 629: "TeamworkDesk", - 630: "TeamworkSpaces", - 631: "TheOddsApi", - 632: "Apacta", - 633: "GetSandbox", - 634: "Happi", - 635: "Oanda", - 636: "FastForex", - 637: "APIMatic", - 638: "VersionEye", - 639: "EagleEyeNetworks", - 640: "ThousandEyes", - 641: "SelectPDF", - 642: "Flightstats", - 643: "ChecIO", - 644: "Manifest", - 645: "ApiScience", - 646: "AppSynergy", - 647: "Caflou", - 648: "Caspio", - 649: "ChecklyHQ", - 650: "CloudElements", - 651: "DronaHQ", - 652: "Enablex", - 653: "Fmfw", - 654: "GoodDay", - 655: "Luno", - 656: "Meistertask", - 657: "Mindmeister", - 658: "PeopleDataLabs", - 659: "ScraperSite", - 660: "Scrapfly", - 661: "SimplyNoted", - 662: "TravelPayouts", - 663: "WebScraper", - 664: "Convier", - 665: "Courier", - 666: "Ditto", - 667: "Findl", - 668: "Lendflow", - 669: "Moderation", - 670: "Opendatasoft", - 671: "Podio", - 672: "Rockset", - 673: "Rownd", - 674: "Shotstack", - 675: "Swiftype", - 676: "Twitter", - 677: "Honey", - 678: "Freshdesk", - 679: "Upwave", - 680: "Fountain", - 681: "Freshbooks", - 682: "Mite", - 683: "Deputy", - 684: "Beebole", - 685: "Cashboard", - 686: "Kanban", - 687: "Worksnaps", - 688: "MyIntervals", - 689: "InvoiceOcean", - 690: "Sherpadesk", - 691: "Mrticktock", - 692: "Chatfule", - 693: "Aeroworkflow", - 694: "Emailoctopus", - 695: "Fusebill", - 696: "Geckoboard", - 697: "Gosquared", - 698: "Moonclerk", - 699: "Paymoapp", - 700: "Mixmax", - 701: "Processst", - 702: "Repairshopr", - 703: "Goshippo", - 704: "Sigopt", - 705: "Sugester", - 706: "Viewneo", - 707: "BoostNote", - 708: "CaptainData", - 709: "Checkvist", - 710: "Cliengo", - 711: "Cloze", - 712: "FormIO", - 713: "FormBucket", - 714: "GoCanvas", - 715: "MadKudu", - 716: "NozbeTeams", - 717: "Papyrs", - 718: "SuperNotesAPI", - 719: "Tallyfy", - 720: "ZenkitAPI", - 721: "CloudImage", - 722: "UploadCare", - 723: "Borgbase", - 724: "Pipedream", - 725: "Sirv", - 726: "Diffbot", - 727: "EightxEight", - 728: "Sendoso", - 729: "Printfection", - 730: "Authorize", - 731: "PandaScore", - 732: "Paymo", - 733: "AvazaPersonalAccessToken", - 734: "PlanviewLeanKit", - 735: "Livestorm", - 736: "KuCoin", - 737: "MetaAPI", - 738: "NiceHash", - 739: "CexIO", - 740: "Klipfolio", - 741: "Dynatrace", - 742: "MollieAPIKey", - 743: "MollieAccessToken", - 744: "BasisTheory", - 745: "Nordigen", - 746: "FlagsmithEnvironmentKey", - 747: "FlagsmithToken", - 748: "Mux", - 749: "Column", - 750: "Sendbird", - 751: "SendbirdOrganizationAPI", - 752: "Midise", - 753: "Mockaroo", - 754: "Image4", - 755: "Pinata", - 756: "BrowserStack", - 757: "CrossBrowserTesting", - 758: "Loadmill", - 759: "TestingBot", - 760: "KnapsackPro", - 761: "Qase", - 762: "Dareboost", - 763: "GTMetrix", - 764: "Holistic", - 765: "Parsers", - 766: "ScrutinizerCi", - 767: "SonarCloud", - 768: "APITemplate", - 769: "ConversionTools", - 770: "CraftMyPDF", - 771: "ExportSDK", - 772: "GlitterlyAPI", - 773: "Hybiscus", - 774: "Miro", - 775: "Statuspage", - 776: "Statuspal", - 777: "Teletype", - 778: "TimeCamp", - 779: "Userflow", - 780: "Wistia", - 781: "SportRadar", - 782: "UptimeRobot", - 783: "Codequiry", - 784: "ExtractorAPI", - 785: "Signable", - 786: "MagicBell", - 787: "Stormboard", - 788: "Apilayer", - 789: "Disqus", - 790: "Woopra", - 791: "Paperform", - 792: "Gumroad", - 793: "Paydirtapp", - 794: "Detectify", - 795: "Statuscake", - 796: "Jumpseller", - 797: "LunchMoney", - 798: "Rosette", - 799: "Yelp", - 800: "Atera", - 801: "EcoStruxureIT", - 802: "Aha", - 803: "Parsehub", - 804: "PackageCloud", - 805: "Cloudsmith", - 806: "Flowdash", - 807: "Flowdock", - 808: "Fibery", - 809: "Typetalk", - 810: "VoodooSMS", - 811: "ZulipChat", - 812: "Formcraft", - 813: "Iexapis", - 814: "Reachmail", - 815: "Chartmogul", - 816: "Appointedd", - 817: "Wit", - 818: "RechargePayments", - 819: "Diggernaut", - 820: "MonkeyLearn", - 821: "Duply", - 822: "Postbacks", - 823: "Collect2", - 824: "ZenRows", - 825: "Zipcodebase", - 826: "Tefter", - 827: "Twist", - 828: "BraintreePayments", - 829: "CloudConvert", - 830: "Grafana", - 831: "ConvertApi", - 832: "Transferwise", - 833: "Bulksms", - 834: "Databox", - 835: "Onesignal", - 836: "Rentman", - 837: "Parseur", - 838: "Docparser", - 839: "Formsite", - 840: "Tickettailor", - 841: "Lemlist", - 842: "Prodpad", - 843: "Formstack", - 844: "Codeclimate", - 845: "Codemagic", - 846: "Vbout", - 847: "Nightfall", - 848: "FlightLabs", - 849: "SpeechTextAI", - 850: "PollsAPI", - 851: "SimFin", - 852: "Scalr", - 853: "Kanbantool", - 854: "Brightlocal", - 855: "Hotwire", - 856: "Instabot", - 857: "Timekit", - 858: "Interseller", - 859: "Mojohelpdesk", - 860: "Createsend", - 861: "Getresponse", - 862: "Dynadot", - 863: "Demio", - 864: "Tokeet", - 865: "Myexperiment", - 866: "Copyscape", - 867: "Besnappy", - 868: "Salesmate", - 869: "Heatmapapi", - 870: "Websitepulse", - 871: "Uclassify", - 872: "Convert", - 873: "PDFmyURL", - 874: "Api2Convert", - 875: "Opsgenie", - 876: "Gemini", - 877: "Honeycomb", - 878: "KalturaAppToken", - 879: "KalturaSession", - 880: "BitGo", - 881: "Optidash", - 882: "Imgix", - 883: "ImageToText", - 884: "Page2Images", - 885: "Quickbase", - 886: "Redbooth", - 887: "Nubela", - 888: "Infobip", - 889: "Uproc", - 890: "Supportbee", - 891: "Aftership", - 892: "Edusign", - 893: "Teamup", - 894: "Workday", - 895: "MongoDB", - 896: "NGC", - 897: "DigitalOceanV2", - 898: "SQLServer", - 899: "FTP", - 900: "Redis", - 901: "LDAP", - 902: "Shopify", - 903: "RabbitMQ", - 904: "CustomRegex", - 905: "Etherscan", - 906: "Infura", - 907: "Alchemy", - 908: "BlockNative", - 909: "Moralis", - 910: "BscScan", - 911: "CoinMarketCap", - 912: "Percy", - 913: "TinesWebhook", - 914: "Pulumi", - 915: "SupabaseToken", - 916: "NuGetApiKey", - 917: "Aiven", - 918: "Prefect", - 919: "Docusign", - 920: "Couchbase", - 921: "Dockerhub", - 922: "TrufflehogEnterprise", - 923: "EnvoyApiKey", - 924: "GitHubOauth2", - 925: "Salesforce", - 926: "HuggingFace", - 927: "Snowflake", - 928: "Sourcegraph", - 929: "Tailscale", - 930: "Web3Storage", - 931: "AzureStorage", - 932: "PlanetScaleDb", - 933: "Anthropic", - 934: "Ramp", - 935: "Klaviyo", - 936: "SourcegraphCody", - 937: "Voiceflow", - 938: "Privacy", - 939: "IPInfo", - 940: "Ip2location", - 941: "Instamojo", - 942: "Portainer", - 943: "PortainerToken", - 944: "Loggly", - 945: "OpenVpn", - 946: "VagrantCloudPersonalToken", - 947: "BetterStack", - 948: "ZeroTier", - 949: "AppOptics", - 950: "Metabase", - 951: "CoinbaseWaaS", - 952: "LemonSqueezy", - 953: "Budibase", - 954: "DenoDeploy", - 955: "Stripo", - 956: "ReplyIO", - 957: "AzureBatch", - 958: "AzureContainerRegistry", - 959: "AWSSessionKey", - 960: "Coda", - 961: "LogzIO", - 962: "Eventbrite", - 963: "GrafanaServiceAccount", - 964: "RequestFinance", - 965: "Overloop", - 966: "Ngrok", - 967: "Replicate", - 968: "Postgres", - 969: "AzureActiveDirectoryApplicationSecret", - 970: "AzureCacheForRedisAccessKey", - 971: "AzureCosmosDBKeyIdentifiable", - 972: "AzureDevopsPersonalAccessToken", - 973: "AzureFunctionKey", - 974: "AzureMLWebServiceClassicIdentifiableKey", - 975: "AzureSasToken", - 976: "AzureSearchAdminKey", - 977: "AzureSearchQueryKey", - 978: "AzureManagementCertificate", - 979: "AzureSQL", - 980: "FlyIO", - 981: "BuiltWith", - 982: "JupiterOne", - 983: "GCPApplicationDefaultCredentials", - 984: "Wiz", - 985: "Pagarme", - 986: "Onfleet", - 987: "Intra42", - 988: "Groq", - 989: "TwitterConsumerkey", - 990: "Eraser", - 991: "LarkSuite", - 992: "LarkSuiteApiKey", - 993: "EndorLabs", - 994: "ElevenLabs", - 995: "Netsuite", - 996: "RobinhoodCrypto", - 997: "NVAPI", - 998: "PyPI", - 999: "RailwayApp", + 0: "Alibaba", + 1: "AMQP", + 2: "AWS", + 3: "Azure", + 4: "Circle", + 5: "Coinbase", + 6: "GCP", + 7: "Generic", + 8: "Github", + 9: "Gitlab", + 10: "JDBC", + 11: "RazorPay", + 12: "SendGrid", + 13: "Slack", + 14: "Square", + 15: "PrivateKey", + 16: "Stripe", + 17: "URI", + 18: "Dropbox", + 19: "Heroku", + 20: "Mailchimp", + 21: "Okta", + 22: "OneLogin", + 23: "PivotalTracker", + 25: "SquareApp", + 26: "Twilio", + 27: "Test", + 29: "TravisCI", + 30: "SlackWebhook", + 31: "PaypalOauth", + 32: "PagerDutyApiKey", + 33: "Firebase", + 34: "Mailgun", + 35: "HubSpot", + 36: "GitHubApp", + 37: "CircleCI", + 38: "WpEngine", + 39: "DatadogToken", + 40: "FacebookOAuth", + 41: "AsanaPersonalAccessToken", + 42: "AmplitudeApiKey", + 43: "BitLyAccessToken", + 44: "CalendlyApiKey", + 45: "ZapierWebhook", + 46: "YoutubeApiKey", + 47: "SalesforceOauth2", + 48: "TwitterApiSecret", + 49: "NpmToken", + 50: "NewRelicPersonalApiKey", + 51: "AirtableApiKey", + 52: "AkamaiToken", + 53: "AmazonMWS", + 54: "KubeConfig", + 55: "Auth0oauth", + 56: "Bitfinex", + 57: "Clarifai", + 58: "CloudflareGlobalApiKey", + 59: "CloudflareCaKey", + 60: "Confluent", + 61: "ContentfulDelivery", + 62: "DatabricksToken", + 63: "DigitalOceanSpaces", + 64: "DigitalOceanToken", + 65: "DiscordBotToken", + 66: "DiscordWebhook", + 67: "EtsyApiKey", + 68: "FastlyPersonalToken", + 69: "GoogleOauth2", + 70: "ReCAPTCHA", + 71: "GoogleApiKey", + 72: "Hunter", + 73: "IbmCloudUserKey", + 74: "Netlify", + 75: "Vonage", + 76: "EquinixOauth", + 77: "Paystack", + 78: "PlaidToken", + 79: "PlaidKey", + 80: "Plivo", + 81: "Postmark", + 82: "PubNubPublishKey", + 83: "PubNubSubscriptionKey", + 84: "PusherChannelKey", + 85: "ScalewayKey", + 86: "SendinBlueV2", + 87: "SentryToken", + 88: "ShodanKey", + 89: "SnykKey", + 90: "SpotifyKey", + 91: "TelegramBotToken", + 92: "TencentCloudKey", + 93: "TerraformCloudPersonalToken", + 94: "TrelloApiKey", + 95: "ZendeskApi", + 96: "MaxMindLicense", + 97: "AirtableMetadataApiKey", + 98: "AsanaOauth", + 99: "RapidApi", + 100: "CloudflareApiToken", + 101: "Webex", + 102: "FirebaseCloudMessaging", + 103: "ContentfulPersonalAccessToken", + 104: "MapBox", + 105: "MailJetBasicAuth", + 106: "MailJetSMS", + 107: "HubSpotApiKey", + 108: "HubSpotOauth", + 109: "SslMate", + 110: "Auth0ManagementApiToken", + 111: "MessageBird", + 112: "ElasticEmail", + 113: "FigmaPersonalAccessToken", + 114: "MicrosoftTeamsWebhook", + 115: "GitHubOld", + 116: "VultrApiKey", + 117: "Pepipost", + 118: "Postman", + 119: "CloudsightKey", + 120: "JiraToken", + 121: "NexmoApiKey", + 122: "SegmentApiKey", + 123: "SumoLogicKey", + 124: "PushBulletApiKey", + 125: "AirbrakeProjectKey", + 126: "AirbrakeUserKey", + 127: "PendoIntegrationKey", + 128: "SplunkOberservabilityToken", + 129: "LokaliseToken", + 130: "Calendarific", + 131: "Jumpcloud", + 133: "IpStack", + 134: "Notion", + 135: "DroneCI", + 136: "AdobeIO", + 137: "TwelveData", + 138: "D7Network", + 139: "ScrapingBee", + 140: "KeenIO", + 141: "Wakatime", + 142: "Buildkite", + 143: "Verimail", + 144: "Zerobounce", + 145: "Mailboxlayer", + 146: "Fastspring", + 147: "Paddle", + 148: "Sellfy", + 149: "FixerIO", + 150: "ButterCMS", + 151: "Taxjar", + 152: "Avalara", + 153: "Helpscout", + 154: "ElasticPath", + 155: "Zeplin", + 156: "Intercom", + 157: "Mailmodo", + 158: "CannyIo", + 159: "Pipedrive", + 160: "Vercel", + 161: "PosthogApp", + 162: "SinchMessage", + 163: "Ayrshare", + 164: "HelpCrunch", + 165: "LiveAgent", + 166: "Beamer", + 167: "WeChatAppKey", + 168: "LineMessaging", + 169: "UberServerToken", + 170: "AlgoliaAdminKey", + 171: "FullContact", + 172: "Mandrill", + 173: "Flutterwave", + 174: "MattermostPersonalToken", + 175: "Cloudant", + 176: "LineNotify", + 177: "LinearAPI", + 178: "Ubidots", + 179: "Anypoint", + 180: "Dwolla", + 181: "ArtifactoryAccessToken", + 182: "Surge", + 183: "Sparkpost", + 184: "GoCardless", + 185: "Codacy", + 186: "Kraken", + 187: "Checkout", + 188: "Kairos", + 189: "ClockworkSMS", + 190: "Atlassian", + 191: "LaunchDarkly", + 192: "Coveralls", + 193: "Linode", + 194: "WePay", + 195: "PlanetScale", + 196: "Doppler", + 197: "Agora", + 198: "Samsara", + 199: "FrameIO", + 200: "RubyGems", + 201: "OpenAI", + 202: "SurveySparrow", + 203: "Simvoly", + 204: "Survicate", + 205: "Omnisend", + 206: "Groovehq", + 207: "Newsapi", + 208: "Chatbot", + 209: "ClickSendsms", + 210: "Getgist", + 211: "CustomerIO", + 212: "ApiDeck", + 213: "Nftport", + 214: "Copper", + 215: "Close", + 216: "Myfreshworks", + 217: "Salesflare", + 218: "Webflow", + 219: "Duda", + 220: "Yext", + 221: "ContentStack", + 222: "Storyblok", + 223: "GraphCMS", + 224: "Checkmarket", + 225: "Convertkit", + 226: "CustomerGuru", + 227: "Kaleyra", + 228: "Mailerlite", + 229: "Qualaroo", + 230: "SatismeterProjectkey", + 231: "SatismeterWritekey", + 232: "Simplesat", + 233: "SurveyAnyplace", + 234: "SurveyBot", + 235: "Webengage", + 236: "ZonkaFeedback", + 237: "Delighted", + 238: "Feedier", + 239: "Abbysale", + 240: "Magnetic", + 241: "Nytimes", + 242: "Polygon", + 243: "Powrbot", + 244: "ProspectIO", + 245: "Skrappio", + 246: "Monday", + 247: "Smartsheets", + 248: "Wrike", + 249: "Float", + 250: "Imagekit", + 251: "Integromat", + 252: "Salesblink", + 253: "Bored", + 254: "Campayn", + 255: "Clinchpad", + 256: "CompanyHub", + 257: "Debounce", + 258: "Dyspatch", + 259: "Guardianapi", + 260: "Harvest", + 261: "Moosend", + 262: "OpenWeather", + 263: "Siteleaf", + 264: "Squarespace", + 265: "FlowFlu", + 266: "Nimble", + 267: "LessAnnoyingCRM", + 268: "Nethunt", + 269: "Apptivo", + 270: "CapsuleCRM", + 271: "Insightly", + 272: "Kylas", + 273: "OnepageCRM", + 274: "User", + 275: "ProspectCRM", + 276: "ReallySimpleSystems", + 277: "Airship", + 278: "Artsy", + 279: "Yandex", + 280: "Clockify", + 281: "Dnscheck", + 282: "EasyInsight", + 283: "Ethplorer", + 284: "Everhour", + 285: "Fulcrum", + 286: "GeoIpifi", + 287: "Jotform", + 288: "Refiner", + 289: "Timezoneapi", + 290: "TogglTrack", + 291: "Vpnapi", + 292: "Workstack", + 293: "Apollo", + 294: "Eversign", + 295: "Juro", + 296: "KarmaCRM", + 297: "Metrilo", + 298: "Pandadoc", + 299: "RevampCRM", + 300: "Salescookie", + 301: "Alconost", + 302: "Blogger", + 303: "Accuweather", + 304: "Opengraphr", + 305: "Rawg", + 306: "Riotgames", + 307: "RoninApp", + 308: "Stormglass", + 309: "Tomtom", + 310: "Twitch", + 311: "Documo", + 312: "Cloudways", + 313: "Veevavault", + 314: "KiteConnect", + 315: "ShopeeOpenPlatform", + 316: "TeamViewer", + 317: "Bulbul", + 318: "CentralStationCRM", + 319: "Teamgate", + 320: "Axonaut", + 321: "Tyntec", + 322: "Appcues", + 323: "Autoklose", + 324: "Cloudplan", + 325: "Dotmailer", + 326: "GetEmail", + 327: "GetEmails", + 328: "Kontent", + 329: "Leadfeeder", + 330: "Raven", + 331: "RocketReach", + 332: "Uplead", + 333: "Brandfetch", + 334: "Clearbit", + 335: "Crowdin", + 336: "Mapquest", + 337: "Noticeable", + 338: "Onbuka", + 339: "Todoist", + 340: "Storychief", + 341: "LinkedIn", + 342: "YouSign", + 343: "Docker", + 344: "Telesign", + 345: "Spoonacular", + 346: "Aerisweather", + 347: "Alphavantage", + 348: "Imgur", + 349: "Imagga", + 350: "SMSApi", + 351: "Distribusion", + 352: "Blablabus", + 353: "WordsApi", + 354: "Currencylayer", + 355: "Html2Pdf", + 356: "IPGeolocation", + 357: "Owlbot", + 358: "Cloudmersive", + 359: "Dynalist", + 360: "ExchangeRateAPI", + 361: "HolidayAPI", + 362: "Ipapi", + 363: "Marketstack", + 364: "Nutritionix", + 365: "Swell", + 366: "ClickupPersonalToken", + 367: "Nitro", + 368: "Rev", + 369: "RunRunIt", + 370: "Typeform", + 371: "Mixpanel", + 372: "Tradier", + 373: "Verifier", + 374: "Vouchery", + 375: "Alegra", + 376: "Audd", + 377: "Baremetrics", + 378: "Coinlib", + 379: "ExchangeRatesAPI", + 380: "CurrencyScoop", + 381: "FXMarket", + 382: "CurrencyCloud", + 383: "GetGeoAPI", + 384: "Abstract", + 385: "Billomat", + 386: "Dovico", + 387: "Bitbar", + 388: "Bugsnag", + 389: "AssemblyAI", + 390: "AdafruitIO", + 391: "Apify", + 392: "CoinGecko", + 393: "CryptoCompare", + 394: "Fullstory", + 395: "HelloSign", + 396: "Loyverse", + 397: "NetCore", + 398: "SauceLabs", + 399: "AlienVault", + 401: "Apiflash", + 402: "Coinlayer", + 403: "CurrentsAPI", + 404: "DataGov", + 405: "Enigma", + 406: "FinancialModelingPrep", + 407: "Geocodio", + 408: "HereAPI", + 409: "Macaddress", + 410: "OOPSpam", + 411: "ProtocolsIO", + 412: "ScraperAPI", + 413: "SecurityTrails", + 414: "TomorrowIO", + 415: "WorldCoinIndex", + 416: "FacePlusPlus", + 417: "Voicegain", + 418: "Deepgram", + 419: "VisualCrossing", + 420: "Finnhub", + 421: "Tiingo", + 422: "RingCentral", + 423: "Finage", + 424: "Edamam", + 425: "HypeAuditor", + 426: "Gengo", + 427: "Front", + 428: "Fleetbase", + 429: "Bubble", + 430: "Bannerbear", + 431: "Adzuna", + 432: "BitcoinAverage", + 433: "CommerceJS", + 434: "DetectLanguage", + 435: "FakeJSON", + 436: "Graphhopper", + 437: "Lexigram", + 438: "LinkPreview", + 439: "Numverify", + 440: "ProxyCrawl", + 441: "ZipCodeAPI", + 442: "Cometchat", + 443: "Keygen", + 444: "Mixcloud", + 445: "TatumIO", + 446: "Tmetric", + 447: "Lastfm", + 448: "Browshot", + 449: "JSONbin", + 450: "LocationIQ", + 451: "ScreenshotAPI", + 452: "WeatherStack", + 453: "Amadeus", + 454: "FourSquare", + 455: "Flickr", + 456: "ClickHelp", + 457: "Ambee", + 458: "Api2Cart", + 459: "Hypertrack", + 460: "KakaoTalk", + 461: "RiteKit", + 462: "Shutterstock", + 463: "Text2Data", + 464: "YouNeedABudget", + 465: "Cricket", + 466: "Filestack", + 467: "Gyazo", + 468: "Mavenlink", + 469: "Sheety", + 470: "Sportsmonk", + 471: "Stockdata", + 472: "Unsplash", + 473: "Allsports", + 474: "CalorieNinja", + 475: "WalkScore", + 476: "Strava", + 477: "Cicero", + 478: "IPQuality", + 479: "ParallelDots", + 480: "Roaring", + 481: "Mailsac", + 482: "Whoxy", + 483: "WorldWeather", + 484: "ApiFonica", + 485: "Aylien", + 486: "Geocode", + 487: "IconFinder", + 488: "Ipify", + 489: "LanguageLayer", + 490: "Lob", + 491: "OnWaterIO", + 492: "Pastebin", + 493: "PdfLayer", + 494: "Pixabay", + 495: "ReadMe", + 496: "VatLayer", + 497: "VirusTotal", + 498: "AirVisual", + 499: "Currencyfreaks", + 500: "Duffel", + 501: "FlatIO", + 502: "M3o", + 503: "Mesibo", + 504: "Openuv", + 505: "Snipcart", + 506: "Besttime", + 507: "Happyscribe", + 508: "Humanity", + 509: "Impala", + 510: "Loginradius", + 511: "AutoPilot", + 512: "Bitmex", + 513: "ClustDoc", + 514: "Messari", + 515: "PdfShift", + 516: "Poloniex", + 517: "RestpackHtmlToPdfAPI", + 518: "RestpackScreenshotAPI", + 519: "ShutterstockOAuth", + 520: "SkyBiometry", + 521: "AbuseIPDB", + 522: "AletheiaApi", + 523: "BlitApp", + 524: "Censys", + 525: "Cloverly", + 526: "CountryLayer", + 527: "FileIO", + 528: "FlightApi", + 529: "Geoapify", + 530: "IPinfoDB", + 531: "MediaStack", + 532: "NasdaqDataLink", + 533: "OpenCageData", + 534: "Paymongo", + 535: "PositionStack", + 536: "Rebrandly", + 537: "ScreenshotLayer", + 538: "Stytch", + 539: "Unplugg", + 540: "UPCDatabase", + 541: "UserStack", + 542: "Geocodify", + 543: "Newscatcher", + 544: "Nicereply", + 545: "Partnerstack", + 546: "Route4me", + 547: "Scrapeowl", + 548: "ScrapingDog", + 549: "Streak", + 550: "Veriphone", + 551: "Webscraping", + 552: "Zenscrape", + 553: "Zenserp", + 554: "CoinApi", + 555: "Gitter", + 556: "Host", + 557: "Iexcloud", + 558: "Restpack", + 559: "ScraperBox", + 560: "ScrapingAnt", + 561: "SerpStack", + 562: "SmartyStreets", + 563: "TicketMaster", + 564: "AviationStack", + 565: "BombBomb", + 566: "Commodities", + 567: "Dfuse", + 568: "EdenAI", + 569: "Glassnode", + 570: "Guru", + 571: "Hive", + 572: "Hiveage", + 573: "Kickbox", + 574: "Passbase", + 575: "PostageApp", + 576: "PureStake", + 577: "Qubole", + 578: "CarbonInterface", + 579: "Intrinio", + 580: "QuickMetrics", + 581: "ScrapeStack", + 582: "TechnicalAnalysisApi", + 583: "Urlscan", + 584: "BaseApiIO", + 585: "DailyCO", + 586: "TLy", + 587: "Shortcut", + 588: "Appfollow", + 589: "Thinkific", + 590: "Feedly", + 591: "Stitchdata", + 592: "Fetchrss", + 593: "Signupgenius", + 594: "Signaturit", + 595: "Optimizely", + 596: "OcrSpace", + 597: "WeatherBit", + 598: "BuddyNS", + 599: "ZipAPI", + 600: "ZipBooks", + 601: "Onedesk", + 602: "Bugherd", + 603: "Blazemeter", + 604: "Autodesk", + 605: "Tru", + 606: "UnifyID", + 607: "Trimble", + 608: "Smooch", + 609: "Semaphore", + 610: "Telnyx", + 611: "Signalwire", + 612: "Textmagic", + 613: "Serphouse", + 614: "Planyo", + 615: "Simplybook", + 616: "Vyte", + 617: "Nylas", + 618: "Squareup", + 619: "Dandelion", + 620: "DataFire", + 621: "DeepAI", + 622: "MeaningCloud", + 623: "NeutrinoApi", + 624: "Storecove", + 625: "Shipday", + 626: "Sentiment", + 627: "StreamChatMessaging", + 628: "TeamworkCRM", + 629: "TeamworkDesk", + 630: "TeamworkSpaces", + 631: "TheOddsApi", + 632: "Apacta", + 633: "GetSandbox", + 634: "Happi", + 635: "Oanda", + 636: "FastForex", + 637: "APIMatic", + 638: "VersionEye", + 639: "EagleEyeNetworks", + 640: "ThousandEyes", + 641: "SelectPDF", + 642: "Flightstats", + 643: "ChecIO", + 644: "Manifest", + 645: "ApiScience", + 646: "AppSynergy", + 647: "Caflou", + 648: "Caspio", + 649: "ChecklyHQ", + 650: "CloudElements", + 651: "DronaHQ", + 652: "Enablex", + 653: "Fmfw", + 654: "GoodDay", + 655: "Luno", + 656: "Meistertask", + 657: "Mindmeister", + 658: "PeopleDataLabs", + 659: "ScraperSite", + 660: "Scrapfly", + 661: "SimplyNoted", + 662: "TravelPayouts", + 663: "WebScraper", + 664: "Convier", + 665: "Courier", + 666: "Ditto", + 667: "Findl", + 668: "Lendflow", + 669: "Moderation", + 670: "Opendatasoft", + 671: "Podio", + 672: "Rockset", + 673: "Rownd", + 674: "Shotstack", + 675: "Swiftype", + 676: "Twitter", + 677: "Honey", + 678: "Freshdesk", + 679: "Upwave", + 680: "Fountain", + 681: "Freshbooks", + 682: "Mite", + 683: "Deputy", + 684: "Beebole", + 685: "Cashboard", + 686: "Kanban", + 687: "Worksnaps", + 688: "MyIntervals", + 689: "InvoiceOcean", + 690: "Sherpadesk", + 691: "Mrticktock", + 692: "Chatfule", + 693: "Aeroworkflow", + 694: "Emailoctopus", + 695: "Fusebill", + 696: "Geckoboard", + 697: "Gosquared", + 698: "Moonclerk", + 699: "Paymoapp", + 700: "Mixmax", + 701: "Processst", + 702: "Repairshopr", + 703: "Goshippo", + 704: "Sigopt", + 705: "Sugester", + 706: "Viewneo", + 707: "BoostNote", + 708: "CaptainData", + 709: "Checkvist", + 710: "Cliengo", + 711: "Cloze", + 712: "FormIO", + 713: "FormBucket", + 714: "GoCanvas", + 715: "MadKudu", + 716: "NozbeTeams", + 717: "Papyrs", + 718: "SuperNotesAPI", + 719: "Tallyfy", + 720: "ZenkitAPI", + 721: "CloudImage", + 722: "UploadCare", + 723: "Borgbase", + 724: "Pipedream", + 725: "Sirv", + 726: "Diffbot", + 727: "EightxEight", + 728: "Sendoso", + 729: "Printfection", + 730: "Authorize", + 731: "PandaScore", + 732: "Paymo", + 733: "AvazaPersonalAccessToken", + 734: "PlanviewLeanKit", + 735: "Livestorm", + 736: "KuCoin", + 737: "MetaAPI", + 738: "NiceHash", + 739: "CexIO", + 740: "Klipfolio", + 741: "Dynatrace", + 742: "MollieAPIKey", + 743: "MollieAccessToken", + 744: "BasisTheory", + 745: "Nordigen", + 746: "FlagsmithEnvironmentKey", + 747: "FlagsmithToken", + 748: "Mux", + 749: "Column", + 750: "Sendbird", + 751: "SendbirdOrganizationAPI", + 752: "Midise", + 753: "Mockaroo", + 754: "Image4", + 755: "Pinata", + 756: "BrowserStack", + 757: "CrossBrowserTesting", + 758: "Loadmill", + 759: "TestingBot", + 760: "KnapsackPro", + 761: "Qase", + 762: "Dareboost", + 763: "GTMetrix", + 764: "Holistic", + 765: "Parsers", + 766: "ScrutinizerCi", + 767: "SonarCloud", + 768: "APITemplate", + 769: "ConversionTools", + 770: "CraftMyPDF", + 771: "ExportSDK", + 772: "GlitterlyAPI", + 773: "Hybiscus", + 774: "Miro", + 775: "Statuspage", + 776: "Statuspal", + 777: "Teletype", + 778: "TimeCamp", + 779: "Userflow", + 780: "Wistia", + 781: "SportRadar", + 782: "UptimeRobot", + 783: "Codequiry", + 784: "ExtractorAPI", + 785: "Signable", + 786: "MagicBell", + 787: "Stormboard", + 788: "Apilayer", + 789: "Disqus", + 790: "Woopra", + 791: "Paperform", + 792: "Gumroad", + 793: "Paydirtapp", + 794: "Detectify", + 795: "Statuscake", + 796: "Jumpseller", + 797: "LunchMoney", + 798: "Rosette", + 799: "Yelp", + 800: "Atera", + 801: "EcoStruxureIT", + 802: "Aha", + 803: "Parsehub", + 804: "PackageCloud", + 805: "Cloudsmith", + 806: "Flowdash", + 807: "Flowdock", + 808: "Fibery", + 809: "Typetalk", + 810: "VoodooSMS", + 811: "ZulipChat", + 812: "Formcraft", + 813: "Iexapis", + 814: "Reachmail", + 815: "Chartmogul", + 816: "Appointedd", + 817: "Wit", + 818: "RechargePayments", + 819: "Diggernaut", + 820: "MonkeyLearn", + 821: "Duply", + 822: "Postbacks", + 823: "Collect2", + 824: "ZenRows", + 825: "Zipcodebase", + 826: "Tefter", + 827: "Twist", + 828: "BraintreePayments", + 829: "CloudConvert", + 830: "Grafana", + 831: "ConvertApi", + 832: "Transferwise", + 833: "Bulksms", + 834: "Databox", + 835: "Onesignal", + 836: "Rentman", + 837: "Parseur", + 838: "Docparser", + 839: "Formsite", + 840: "Tickettailor", + 841: "Lemlist", + 842: "Prodpad", + 843: "Formstack", + 844: "Codeclimate", + 845: "Codemagic", + 846: "Vbout", + 847: "Nightfall", + 848: "FlightLabs", + 849: "SpeechTextAI", + 850: "PollsAPI", + 851: "SimFin", + 852: "Scalr", + 853: "Kanbantool", + 854: "Brightlocal", + 855: "Hotwire", + 856: "Instabot", + 857: "Timekit", + 858: "Interseller", + 859: "Mojohelpdesk", + 860: "Createsend", + 861: "Getresponse", + 862: "Dynadot", + 863: "Demio", + 864: "Tokeet", + 865: "Myexperiment", + 866: "Copyscape", + 867: "Besnappy", + 868: "Salesmate", + 869: "Heatmapapi", + 870: "Websitepulse", + 871: "Uclassify", + 872: "Convert", + 873: "PDFmyURL", + 874: "Api2Convert", + 875: "Opsgenie", + 876: "Gemini", + 877: "Honeycomb", + 878: "KalturaAppToken", + 879: "KalturaSession", + 880: "BitGo", + 881: "Optidash", + 882: "Imgix", + 883: "ImageToText", + 884: "Page2Images", + 885: "Quickbase", + 886: "Redbooth", + 887: "Nubela", + 888: "Infobip", + 889: "Uproc", + 890: "Supportbee", + 891: "Aftership", + 892: "Edusign", + 893: "Teamup", + 894: "Workday", + 895: "MongoDB", + 896: "NGC", + 897: "DigitalOceanV2", + 898: "SQLServer", + 899: "FTP", + 900: "Redis", + 901: "LDAP", + 902: "Shopify", + 903: "RabbitMQ", + 904: "CustomRegex", + 905: "Etherscan", + 906: "Infura", + 907: "Alchemy", + 908: "BlockNative", + 909: "Moralis", + 910: "BscScan", + 911: "CoinMarketCap", + 912: "Percy", + 913: "TinesWebhook", + 914: "Pulumi", + 915: "SupabaseToken", + 916: "NuGetApiKey", + 917: "Aiven", + 918: "Prefect", + 919: "Docusign", + 920: "Couchbase", + 921: "Dockerhub", + 922: "TrufflehogEnterprise", + 923: "EnvoyApiKey", + 924: "GitHubOauth2", + 925: "Salesforce", + 926: "HuggingFace", + 927: "Snowflake", + 928: "Sourcegraph", + 929: "Tailscale", + 930: "Web3Storage", + 931: "AzureStorage", + 932: "PlanetScaleDb", + 933: "Anthropic", + 934: "Ramp", + 935: "Klaviyo", + 936: "SourcegraphCody", + 937: "Voiceflow", + 938: "Privacy", + 939: "IPInfo", + 940: "Ip2location", + 941: "Instamojo", + 942: "Portainer", + 943: "PortainerToken", + 944: "Loggly", + 945: "OpenVpn", + 946: "VagrantCloudPersonalToken", + 947: "BetterStack", + 948: "ZeroTier", + 949: "AppOptics", + 950: "Metabase", + 951: "CoinbaseWaaS", + 952: "LemonSqueezy", + 953: "Budibase", + 954: "DenoDeploy", + 955: "Stripo", + 956: "ReplyIO", + 957: "AzureBatch", + 958: "AzureContainerRegistry", + 959: "AWSSessionKey", + 960: "Coda", + 961: "LogzIO", + 962: "Eventbrite", + 963: "GrafanaServiceAccount", + 964: "RequestFinance", + 965: "Overloop", + 966: "Ngrok", + 967: "Replicate", + 968: "Postgres", + 969: "AzureActiveDirectoryApplicationSecret", + 970: "AzureCacheForRedisAccessKey", + 971: "AzureCosmosDBKeyIdentifiable", + 972: "AzureDevopsPersonalAccessToken", + 973: "AzureFunctionKey", + 974: "AzureMLWebServiceClassicIdentifiableKey", + 975: "AzureSasToken", + 976: "AzureSearchAdminKey", + 977: "AzureSearchQueryKey", + 978: "AzureManagementCertificate", + 979: "AzureSQL", + 980: "FlyIO", + 981: "BuiltWith", + 982: "JupiterOne", + 983: "GCPApplicationDefaultCredentials", + 984: "Wiz", + 985: "Pagarme", + 986: "Onfleet", + 987: "Intra42", + 988: "Groq", + 989: "TwitterConsumerkey", + 990: "Eraser", + 991: "LarkSuite", + 992: "LarkSuiteApiKey", + 993: "EndorLabs", + 994: "ElevenLabs", + 995: "Netsuite", + 996: "RobinhoodCrypto", + 997: "NVAPI", + 998: "PyPI", + 999: "RailwayApp", + 1000: "Meraki", } DetectorType_value = map[string]int32{ "Alibaba": 0, @@ -3100,6 +3102,7 @@ var ( "NVAPI": 997, "PyPI": 998, "RailwayApp": 999, + "Meraki": 1000, } ) @@ -3553,7 +3556,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, 0xd6, 0x7f, 0x0a, 0x0c, 0x44, 0x65, 0x74, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x54, + 0x10, 0x04, 0x2a, 0xe3, 0x7f, 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, 0x0a, @@ -4574,12 +4577,12 @@ var file_detectors_proto_rawDesc = []byte{ 0x0f, 0x52, 0x6f, 0x62, 0x69, 0x6e, 0x68, 0x6f, 0x6f, 0x64, 0x43, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x10, 0xe4, 0x07, 0x12, 0x0a, 0x0a, 0x05, 0x4e, 0x56, 0x41, 0x50, 0x49, 0x10, 0xe5, 0x07, 0x12, 0x09, 0x0a, 0x04, 0x50, 0x79, 0x50, 0x49, 0x10, 0xe6, 0x07, 0x12, 0x0f, 0x0a, 0x0a, 0x52, 0x61, - 0x69, 0x6c, 0x77, 0x61, 0x79, 0x41, 0x70, 0x70, 0x10, 0xe7, 0x07, 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, + 0x69, 0x6c, 0x77, 0x61, 0x79, 0x41, 0x70, 0x70, 0x10, 0xe7, 0x07, 0x12, 0x0b, 0x0a, 0x06, 0x4d, + 0x65, 0x72, 0x61, 0x6b, 0x69, 0x10, 0xe8, 0x07, 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 65bc6189337c..371a71d7251d 100644 --- a/proto/detectors.proto +++ b/proto/detectors.proto @@ -1009,6 +1009,7 @@ enum DetectorType { NVAPI = 997; PyPI = 998; RailwayApp = 999; + Meraki = 1000; } message Result { From 57802abf5276961426482ace808057016c714958 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 7 Oct 2024 10:32:24 -0700 Subject: [PATCH 03/76] fix(deps): update module google.golang.org/protobuf to v1.35.1 (#3382) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- go.mod | 2 +- go.sum | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/go.mod b/go.mod index d92348eb2c31..d46ea5a55ac0 100644 --- a/go.mod +++ b/go.mod @@ -109,7 +109,7 @@ require ( golang.org/x/sync v0.8.0 golang.org/x/text v0.19.0 google.golang.org/api v0.199.0 - google.golang.org/protobuf v1.34.2 + google.golang.org/protobuf v1.35.1 gopkg.in/h2non/gock.v1 v1.1.2 gopkg.in/yaml.v2 v2.4.0 gopkg.in/yaml.v3 v3.0.1 diff --git a/go.sum b/go.sum index a714a32478c1..b5a7242cb774 100644 --- a/go.sum +++ b/go.sum @@ -1158,6 +1158,8 @@ google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpAD google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= +google.golang.org/protobuf v1.35.1 h1:m3LfL6/Ca+fqnjnlqQXNpFPABW1UD7mjh8KO2mKFytA= +google.golang.org/protobuf v1.35.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= From 59c615a5e9001224d1dd4049f92f046ca620498c Mon Sep 17 00:00:00 2001 From: Dustin Decker Date: Mon, 7 Oct 2024 15:55:07 -0500 Subject: [PATCH 04/76] Fix git binary handling and add a smoke test (#3379) * Fix git binary handling and add a smoke test * hide stdout * add failure case to smoke test * run again with deadlock fix * Add logic to drain reader in the event of an error * add tests * be picky * set author identity * suppress linter --------- Co-authored-by: Ahrav Dutta --- .github/workflows/smoke.yml | 37 +++++- pkg/handlers/default.go | 3 + pkg/handlers/handlers.go | 16 ++- pkg/handlers/handlers_test.go | 205 ++++++++++++++++++++++++++++++++++ pkg/sources/git/git.go | 33 +----- 5 files changed, 263 insertions(+), 31 deletions(-) diff --git a/.github/workflows/smoke.yml b/.github/workflows/smoke.yml index 68f6f91b0c05..a36b0f590c62 100644 --- a/.github/workflows/smoke.yml +++ b/.github/workflows/smoke.yml @@ -16,5 +16,38 @@ jobs: - name: Smoke run: | set -e - go run . git https://github.com/dustin-decker/secretsandstuff.git - go run . github --repo https://github.com/dustin-decker/secretsandstuff.git + go run . git https://github.com/dustin-decker/secretsandstuff.git > /dev/null + go run . github --repo https://github.com/dustin-decker/secretsandstuff.git > /dev/null + zombies: + runs-on: ubuntu-latest + timeout-minutes: 5 + steps: + - name: Install Go + uses: actions/setup-go@v5 + with: + go-version: "1.23" + - name: Checkout code + uses: actions/checkout@v4 + - name: Run trufflehog + run: | + set -e + go run . git --no-verification file://. > /dev/null + # This case previously had a deadlock issue and left zombies after trufflehog exited #3379 + go run . git --no-verification https://github.com/git-test-fixtures/binary.git > /dev/null + - name: Check for running git processes and zombies + run: | + if pgrep -x "git" > /dev/null + then + echo "Git processes are still running" + exit 1 + else + echo "No git processes found" + fi + + if ps -A -ostat,ppid | grep -e '[zZ]' > /dev/null + then + echo "Zombie processes found" + exit 1 + else + echo "No zombie processes found" + fi diff --git a/pkg/handlers/default.go b/pkg/handlers/default.go index 33a75acd4a4e..84e58f07b2c4 100644 --- a/pkg/handlers/default.go +++ b/pkg/handlers/default.go @@ -3,6 +3,7 @@ package handlers import ( "context" "errors" + "io" "time" "github.com/trufflesecurity/trufflehog/v3/pkg/common" @@ -77,6 +78,8 @@ func (h *defaultHandler) handleNonArchiveContent(ctx logContext.Context, reader if common.SkipFile(mimeExt) || common.IsBinary(mimeExt) { ctx.Logger().V(5).Info("skipping file", "ext", mimeExt) h.metrics.incFilesSkipped() + // Make sure we consume the reader to avoid potentially blocking indefinitely. + _, _ = io.Copy(io.Discard, reader) return nil } diff --git a/pkg/handlers/handlers.go b/pkg/handlers/handlers.go index dd3d43144c52..8f1f5e106bef 100644 --- a/pkg/handlers/handlers.go +++ b/pkg/handlers/handlers.go @@ -283,7 +283,21 @@ func HandleFile( } return fmt.Errorf("error creating custom reader: %w", err) } - defer rdr.Close() + defer func() { + // Ensure all data is read to prevent broken pipe. + _, copyErr := io.Copy(io.Discard, rdr) + if copyErr != nil { + err = fmt.Errorf("error discarding remaining data: %w", copyErr) + } + closeErr := rdr.Close() + if closeErr != nil { + if err != nil { + err = fmt.Errorf("%v; error closing reader: %w", err, closeErr) + } else { + err = fmt.Errorf("error closing reader: %w", closeErr) + } + } + }() ctx = logContext.WithValues(ctx, "mime", rdr.mime.String()) diff --git a/pkg/handlers/handlers_test.go b/pkg/handlers/handlers_test.go index e9e0e5f73b86..418a54db8517 100644 --- a/pkg/handlers/handlers_test.go +++ b/pkg/handlers/handlers_test.go @@ -1,10 +1,14 @@ package handlers import ( + "archive/zip" + "bytes" + "fmt" "io" "net/http" "os" "os/exec" + "path/filepath" "strings" "testing" "time" @@ -475,3 +479,204 @@ func TestHandleZipCommandStdoutPipe(t *testing.T) { assert.Equal(t, wantCount, count) } + +func TestHandleGitCatFile(t *testing.T) { + tests := []struct { + name string + fileName string + fileSize int + supportedType bool + expectedChunks int + }{ + { + name: "LargeBlob", + fileName: "largefile.bin", + fileSize: 50 * 1024 * 1024, // 50 MB + supportedType: true, + expectedChunks: 5120, + }, + { + name: "UnsupportedType", + fileName: "unsupported.so", + fileSize: 1024 * 1024, // 1 MB + supportedType: false, + expectedChunks: 0, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + // Set up a temporary git repository with the specified file. + var gitDir string + if tt.supportedType { + gitDir = setupTempGitRepo(t, tt.fileName, tt.fileSize) + } else { + gitDir = setupTempGitRepoWithUnsupportedFile(t, tt.fileName, tt.fileSize) + } + defer os.RemoveAll(gitDir) + + cmd := exec.Command("git", "-C", gitDir, "rev-parse", "HEAD") + hashBytes, err := cmd.Output() + assert.NoError(t, err, "Failed to get commit hash") + commitHash := strings.TrimSpace(string(hashBytes)) + + // Create a pipe to simulate the git cat-file stdout. + cmd = exec.Command("git", "-C", gitDir, "cat-file", "blob", fmt.Sprintf("%s:%s", commitHash, tt.fileName)) + + var stderr bytes.Buffer + cmd.Stderr = &stderr + + stdout, err := cmd.StdoutPipe() + assert.NoError(t, err, "Failed to create stdout pipe") + + err = cmd.Start() + assert.NoError(t, err, "Failed to start git cat-file command") + + ctx, cancel := context.WithTimeout(context.Background(), 20*time.Second) + defer cancel() + + chunkCh := make(chan *sources.Chunk, 1000) + + go func() { + defer close(chunkCh) + err := HandleFile(ctx, stdout, &sources.Chunk{}, sources.ChanReporter{Ch: chunkCh}, WithSkipArchives(false)) + assert.NoError(t, err, "HandleFile should not return an error") + }() + + err = cmd.Wait() + assert.NoError(t, err, "git cat-file command should complete without error") + + count := 0 + for range chunkCh { + count++ + } + + assert.Equal(t, tt.expectedChunks, count, "Number of chunks should match the expected value") + }) + } +} + +func setupTempGitRepoWithUnsupportedFile(t *testing.T, fileName string, fileSize int) string { + t.Helper() + return setupTempGitRepoCommon(t, fileName, fileSize, true) +} + +func setupTempGitRepo(t *testing.T, archiveName string, fileSize int) string { + t.Helper() + return setupTempGitRepoCommon(t, archiveName, fileSize, false) +} + +func setupTempGitRepoCommon(t *testing.T, fileName string, fileSize int, isUnsupported bool) string { + t.Helper() + + tempDir := t.TempDir() + + cmd := exec.Command("git", "init", tempDir) + var initStderr bytes.Buffer + cmd.Stderr = &initStderr + err := cmd.Run() + if err != nil { + t.Fatalf("Failed to initialize git repository: %v, stderr: %s", err, initStderr.String()) + } + + cmds := [][]string{ + {"git", "-C", tempDir, "config", "user.name", "Test User"}, + {"git", "-C", tempDir, "config", "user.email", "test@example.com"}, + } + + for _, cmdArgs := range cmds { + cmd := exec.Command(cmdArgs[0], cmdArgs[1:]...) //nolint:gosec + var cmdStderr bytes.Buffer + cmd.Stderr = &cmdStderr + err := cmd.Run() + if err != nil { + t.Fatalf("Failed to set git config: %v, stderr: %s", err, cmdStderr.String()) + } + } + + filePath := filepath.Join(tempDir, fileName) + + // Create the file with appropriate content. + f, err := os.Create(filePath) + if err != nil { + t.Fatalf("Failed to create file: %v", err) + } + defer f.Close() + + if isUnsupported { + // Write ELF header for unsupported file. + // https://refspecs.linuxfoundation.org/elf/gabi4+/ch4.eheader.html + elfHeader := []byte{ + 0x7f, 'E', 'L', 'F', // ELF magic number + 2, // 64-bit format + 1, // Little endian + 1, // Current version of ELF + 0, // Target OS ABI + 0, // ABI Version + 0, 0, 0, 0, 0, 0, 0, // 7 bytes of padding + 3, 0, // Relocatable file + 0x3e, 0, // AMD x86-64 architecture + 1, 0, 0, 0, // ELF version + 0, 0, 0, 0, 0, 0, 0, 0, // Entry point + 0, 0, 0, 0, 0, 0, 0, 0, // Program header offset + 0, 0, 0, 0, 0, 0, 0, 0, // Section header offset + } + _, err = f.Write(elfHeader) + if err != nil { + t.Fatalf("Failed to write ELF header: %v", err) + } + } else { + // Write ZIP content for supported file. + zipWriter := zip.NewWriter(f) + header := &zip.FileHeader{ + Name: "largefile.txt", + Method: zip.Store, // No compression + } + zipFileWriter, err := zipWriter.CreateHeader(header) + if err != nil { + t.Fatalf("Failed to create file in ZIP archive: %v", err) + } + + dataChunk := bytes.Repeat([]byte("A"), 1024) // 1KB chunk + totalWritten := 0 + for totalWritten < fileSize { + remaining := fileSize - totalWritten + if remaining < len(dataChunk) { + _, err = zipFileWriter.Write(dataChunk[:remaining]) + if err != nil { + t.Fatalf("Failed to write to inner file in ZIP archive: %v", err) + } + totalWritten += remaining + } else { + _, err = zipFileWriter.Write(dataChunk) + if err != nil { + t.Fatalf("Failed to write to inner file in ZIP archive: %v", err) + } + totalWritten += len(dataChunk) + } + } + + if err := zipWriter.Close(); err != nil { + t.Fatalf("Failed to close ZIP writer: %v", err) + } + } + + // Add and commit the file to Git. + cmd = exec.Command("git", "-C", tempDir, "add", fileName) + var addStderr bytes.Buffer + cmd.Stderr = &addStderr + err = cmd.Run() + if err != nil { + t.Fatalf("Failed to add file to git: %v, stderr: %s", err, addStderr.String()) + } + + cmd = exec.Command("git", "-C", tempDir, "commit", "-m", "Add file") + var commitStderr bytes.Buffer + cmd.Stderr = &commitStderr + err = cmd.Run() + if err != nil { + t.Fatalf("Failed to commit file to git: %v, stderr: %s", err, commitStderr.String()) + } + + return tempDir +} diff --git a/pkg/sources/git/git.go b/pkg/sources/git/git.go index 5843f49b83a2..d9992dadecfd 100644 --- a/pkg/sources/git/git.go +++ b/pkg/sources/git/git.go @@ -1241,44 +1241,21 @@ func (s *Git) handleBinary(ctx context.Context, gitDir string, reporter sources. } cmd := exec.Command("git", "-C", gitDir, "cat-file", "blob", commitHash.String()+":"+path) - stdout, catCmd, err := s.executeCatFileCmd(cmd) - if err != nil { - return err - } - // Wait must be called after closing the pipe (defer is a stack, so first defer is executed last) - defer func() { - _ = catCmd.Wait() - }() - defer stdout.Close() - - err = handlers.HandleFile(ctx, stdout, chunkSkel, reporter, handlers.WithSkipArchives(s.skipArchives)) - - // Always call Wait() to ensure the process is properly cleaned up - waitErr := cmd.Wait() - - // If there was an error in HandleFile, return that error - if err != nil { - return err - } - - // If Wait() resulted in an error, return that error - return waitErr -} - -func (s *Git) executeCatFileCmd(cmd *exec.Cmd) (io.ReadCloser, *exec.Cmd, error) { var stderr bytes.Buffer cmd.Stderr = &stderr stdout, err := cmd.StdoutPipe() if err != nil { - return nil, nil, fmt.Errorf("error running git cat-file: %w\n%s", err, stderr.Bytes()) + return fmt.Errorf("error running git cat-file: %w\n%s", err, stderr.Bytes()) } if err := cmd.Start(); err != nil { - return nil, nil, fmt.Errorf("error starting git cat-file: %w\n%s", err, stderr.Bytes()) + return fmt.Errorf("error starting git cat-file: %w\n%s", err, stderr.Bytes()) } - return stdout, cmd, nil + defer func() { _ = cmd.Wait() }() + + return handlers.HandleFile(ctx, stdout, chunkSkel, reporter, handlers.WithSkipArchives(s.skipArchives)) } func (s *Source) Enumerate(ctx context.Context, reporter sources.UnitReporter) error { From dcf8363eaa78aab4242849351c7a53f93662420e Mon Sep 17 00:00:00 2001 From: Richard Gomez <32133502+rgmz@users.noreply.github.com> Date: Mon, 7 Oct 2024 19:30:02 -0400 Subject: [PATCH 05/76] build: update retracted bluemonday ver (#3369) Co-authored-by: Zachary Rice --- go.mod | 4 ++-- go.sum | 4 ++++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/go.mod b/go.mod index d46ea5a55ac0..ef3a66d31e95 100644 --- a/go.mod +++ b/go.mod @@ -221,7 +221,7 @@ require ( github.com/google/pprof v0.0.0-20240227163752-401108e1b7e7 // indirect github.com/google/s2a-go v0.1.8 // indirect github.com/googleapis/enterprise-certificate-proxy v0.3.4 // indirect - github.com/gorilla/css v1.0.0 // indirect + github.com/gorilla/css v1.0.1 // indirect github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 // indirect github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0 // indirect github.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c // indirect @@ -242,7 +242,7 @@ require ( github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-localereader v0.0.1 // indirect github.com/mattn/go-runewidth v0.0.16 // indirect - github.com/microcosm-cc/bluemonday v1.0.25 // indirect + github.com/microcosm-cc/bluemonday v1.0.27 // indirect github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db // indirect github.com/mitchellh/go-homedir v1.1.0 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect diff --git a/go.sum b/go.sum index b5a7242cb774..4a6dd03d3156 100644 --- a/go.sum +++ b/go.sum @@ -440,6 +440,8 @@ github.com/googleapis/gax-go/v2 v2.13.0 h1:yitjD5f7jQHhyDsnhKEBU52NdvvdSeGzlAnDP github.com/googleapis/gax-go/v2 v2.13.0/go.mod h1:Z/fvTZXF8/uw7Xu5GuslPw+bplx6SS338j1Is2S+B7A= github.com/gorilla/css v1.0.0 h1:BQqNyPTi50JCFMTw/b67hByjMVXZRwGha6wxVGkeihY= github.com/gorilla/css v1.0.0/go.mod h1:Dn721qIggHpt4+EFCcTLTU/vk5ySda2ReITrtgBl60c= +github.com/gorilla/css v1.0.1 h1:ntNaBIghp6JmvWnxbZKANoLyuXTPZ4cAMlo6RyhlbO8= +github.com/gorilla/css v1.0.1/go.mod h1:BvnYkspnSzMmwRK+b8/xgNPLiIuNZr6vbZBTPQ2A3b0= github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4= github.com/gorilla/sessions v1.2.1/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM= github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= @@ -572,6 +574,8 @@ github.com/mholt/archiver/v4 v4.0.0-alpha.8.0.20240408183022-de08bfa4c558 h1:mm8 github.com/mholt/archiver/v4 v4.0.0-alpha.8.0.20240408183022-de08bfa4c558/go.mod h1:/PrlQ8Ei1tfloDN9iyxK26Z++5EX1M29t6eEEvHKoIo= github.com/microcosm-cc/bluemonday v1.0.25 h1:4NEwSfiJ+Wva0VxN5B8OwMicaJvD8r9tlJWm9rtloEg= github.com/microcosm-cc/bluemonday v1.0.25/go.mod h1:ZIOjCQp1OrzBBPIJmfX4qDYFuhU02nx4bn030ixfHLE= +github.com/microcosm-cc/bluemonday v1.0.27 h1:MpEUotklkwCSLeH+Qdx1VJgNqLlpY2KXwXFM08ygZfk= +github.com/microcosm-cc/bluemonday v1.0.27/go.mod h1:jFi9vgW+H7c3V0lb6nR74Ib/DIB5OBs92Dimizgw2cA= github.com/microsoft/go-mssqldb v1.7.2 h1:CHkFJiObW7ItKTJfHo1QX7QBBD1iV+mn1eOyRP3b/PA= github.com/microsoft/go-mssqldb v1.7.2/go.mod h1:kOvZKUdrhhFQmxLZqbwUV0rHkNkZpthMITIb2Ko1IoA= github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db h1:62I3jR2EmQ4l5rM/4FEfDWcRD+abF5XlKShorW5LRoQ= From 23afcd77ee6d368027a3c756a5b6c691ed6a81e0 Mon Sep 17 00:00:00 2001 From: Richard Gomez <32133502+rgmz@users.noreply.github.com> Date: Mon, 7 Oct 2024 23:39:06 -0400 Subject: [PATCH 06/76] Log skipped files on debug level (#3383) --- pkg/engine/engine.go | 2 +- pkg/handlers/archive.go | 8 ++++---- pkg/handlers/default.go | 2 +- pkg/sources/docker/docker.go | 2 +- pkg/sources/github/github.go | 10 ---------- 5 files changed, 7 insertions(+), 17 deletions(-) diff --git a/pkg/engine/engine.go b/pkg/engine/engine.go index 454330d52d52..4e0ee318df07 100644 --- a/pkg/engine/engine.go +++ b/pkg/engine/engine.go @@ -773,7 +773,7 @@ func (e *Engine) scannerWorker(ctx context.Context) { decodeLatency.WithLabelValues(decoder.Type().String(), chunk.SourceName).Observe(float64(decodeTime)) if decoded == nil { - ctx.Logger().V(4).Info("decoder not applicable for chunk", "decoder", decoder.Type().String(), "chunk", chunk) + ctx.Logger().V(5).Info("decoder not applicable for chunk", "decoder", decoder.Type().String(), "chunk", chunk) continue } diff --git a/pkg/handlers/archive.go b/pkg/handlers/archive.go index d33329f76e89..f5777fa52b6c 100644 --- a/pkg/handlers/archive.go +++ b/pkg/handlers/archive.go @@ -154,10 +154,10 @@ func (h *archiveHandler) extractorHandler(archiveChan chan []byte) func(context. "filename", file.Name(), "size", file.Size(), ) - lCtx.Logger().V(5).Info("Handling extracted file.") + lCtx.Logger().V(3).Info("Handling extracted file.") if file.IsDir() || file.LinkTarget != "" { - lCtx.Logger().V(5).Info("skipping directory or symlink") + lCtx.Logger().V(3).Info("skipping directory or symlink") return nil } @@ -172,13 +172,13 @@ func (h *archiveHandler) extractorHandler(archiveChan chan []byte) func(context. fileSize := file.Size() if int(fileSize) > maxSize { - lCtx.Logger().V(3).Info("skipping file due to size", "size", fileSize) + lCtx.Logger().V(2).Info("skipping file: size exceeds max allowed", "size", fileSize, "limit", maxSize) h.metrics.incFilesSkipped() return nil } if common.SkipFile(file.Name()) || common.IsBinary(file.Name()) { - lCtx.Logger().V(5).Info("skipping file") + lCtx.Logger().V(2).Info("skipping file: extension is ignored") h.metrics.incFilesSkipped() return nil } diff --git a/pkg/handlers/default.go b/pkg/handlers/default.go index 84e58f07b2c4..31ebbf8b4162 100644 --- a/pkg/handlers/default.go +++ b/pkg/handlers/default.go @@ -76,7 +76,7 @@ func (h *defaultHandler) handleNonArchiveContent(ctx logContext.Context, reader mimeExt := reader.mimeExt if common.SkipFile(mimeExt) || common.IsBinary(mimeExt) { - ctx.Logger().V(5).Info("skipping file", "ext", mimeExt) + ctx.Logger().V(2).Info("skipping file: extension is ignored", "ext", mimeExt) h.metrics.incFilesSkipped() // Make sure we consume the reader to avoid potentially blocking indefinitely. _, _ = io.Copy(io.Discard, reader) diff --git a/pkg/sources/docker/docker.go b/pkg/sources/docker/docker.go index 88cc971a8e57..473131e0a078 100644 --- a/pkg/sources/docker/docker.go +++ b/pkg/sources/docker/docker.go @@ -345,7 +345,7 @@ type chunkProcessingInfo struct { func (s *Source) processChunk(ctx context.Context, info chunkProcessingInfo, chunksChan chan *sources.Chunk) error { const filesizeLimitBytes int64 = 50 * 1024 * 1024 // 50MB if info.size > filesizeLimitBytes { - ctx.Logger().V(4).Info("skipping large file", "file", info.name, "size", info.size) + ctx.Logger().V(2).Info("skipping file: size exceeds max allowed", "file", info.name, "size", info.size, "limit", filesizeLimitBytes) return nil } diff --git a/pkg/sources/github/github.go b/pkg/sources/github/github.go index 043df01c52bf..e3e492bba359 100644 --- a/pkg/sources/github/github.go +++ b/pkg/sources/github/github.go @@ -13,7 +13,6 @@ import ( "sync/atomic" "time" - "github.com/go-logr/logr" "github.com/gobwas/glob" "github.com/google/go-github/v63/github" "golang.org/x/exp/rand" @@ -726,15 +725,6 @@ func (s *Source) cloneAndScanRepo(ctx context.Context, repoURL string, repoInfo // TODO: Can this be set once or does it need to be set on every iteration? Is |s.scanOptions| set every clone? s.setScanOptions(s.conn.Base, s.conn.Head) - // Repo size is not collected for wikis. - var logger logr.Logger - if !strings.HasSuffix(repoURL, ".wiki.git") && repoInfo.size > 0 { - logger = ctx.Logger().WithValues("repo_size_kb", repoInfo.size) - } else { - logger = ctx.Logger() - } - logger.V(2).Info("scanning repo") - start := time.Now() if err = s.git.ScanRepo(ctx, repo, path, s.scanOptions, reporter); err != nil { return duration, fmt.Errorf("error scanning repo %s: %w", repoURL, err) From 321813fe752341fde57cacec35ce6b60664a4c4a Mon Sep 17 00:00:00 2001 From: Kashif Khan <70996046+kashifkhan0771@users.noreply.github.com> Date: Wed, 9 Oct 2024 19:52:28 +0500 Subject: [PATCH 07/76] Enhanced the easyinsight detector (#3384) * Enhanced the easyinsight detector * restructured verification code and resolved comments * resolved comments * added basic auth * updated statuscode logic --- pkg/detectors/easyinsight/easyinsight.go | 96 +++++++---- .../easyinsight_integration_test.go | 121 +++++++++++++ pkg/detectors/easyinsight/easyinsight_test.go | 163 ++++++++---------- 3 files changed, 258 insertions(+), 122 deletions(-) create mode 100644 pkg/detectors/easyinsight/easyinsight_integration_test.go diff --git a/pkg/detectors/easyinsight/easyinsight.go b/pkg/detectors/easyinsight/easyinsight.go index 60ad7f5640f4..79b40d118771 100644 --- a/pkg/detectors/easyinsight/easyinsight.go +++ b/pkg/detectors/easyinsight/easyinsight.go @@ -2,18 +2,17 @@ package easyinsight import ( "context" - b64 "encoding/base64" "fmt" regexp "github.com/wasilibs/go-re2" + "io" "net/http" - "strings" "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{ +type Scanner struct { detectors.DefaultMultiPartCredentialProvider } @@ -24,8 +23,8 @@ var ( client = common.SaneHttpClient() // Make sure that your group is surrounded in boundary characters such as below to reduce false positives. - keyPat = regexp.MustCompile(detectors.PrefixRegex([]string{"easyinsight", "easy-insight"}) + `\b([0-9Aa-zA-Z]{20})\b`) - idPat = regexp.MustCompile(detectors.PrefixRegex([]string{"easyinsight", "easy-insight"}) + `\b([a-zA-Z0-9]{20})\b`) + keyPat = regexp.MustCompile(detectors.PrefixRegex([]string{"easyinsight", "easy-insight", "key"}) + `\b([0-9a-zA-Z]{20})\b`) + idPat = regexp.MustCompile(detectors.PrefixRegex([]string{"easyinsight", "easy-insight", "id"}) + `\b([a-zA-Z0-9]{20})\b`) ) // Keywords are used for efficiently pre-filtering chunks. @@ -38,49 +37,45 @@ func (s Scanner) Keywords() []string { func (s Scanner) FromData(ctx context.Context, verify bool, data []byte) (results []detectors.Result, err error) { dataStr := string(data) - matches := keyPat.FindAllStringSubmatch(dataStr, -1) + var keyMatches, idMatches = make(map[string]struct{}), make(map[string]struct{}) - idmatches := idPat.FindAllStringSubmatch(dataStr, -1) + // get unique key and id matches + for _, matches := range keyPat.FindAllStringSubmatch(dataStr, -1) { + keyMatches[matches[1]] = struct{}{} + } - for _, match := range matches { - if len(match) != 2 { - continue - } - resMatch := strings.TrimSpace(match[1]) - for _, idmatch := range idmatches { - if len(idmatch) != 2 { + for _, matches := range idPat.FindAllStringSubmatch(dataStr, -1) { + idMatches[matches[1]] = struct{}{} + } + + for keyMatch := range keyMatches { + for idMatch := range idMatches { + //as key and id regex are same, the strings captured by both regex will be same. + //avoid processing when key is same as id. This will allow detector to process only different combinations + if keyMatch == idMatch { continue } - resIdMatch := strings.TrimSpace(idmatch[1]) s1 := detectors.Result{ DetectorType: detectorspb.DetectorType_EasyInsight, - Raw: []byte(resMatch), - RawV2: []byte(resMatch + resIdMatch), + Raw: []byte(keyMatch), + RawV2: []byte(keyMatch + idMatch), } if verify { - data := fmt.Sprintf("%s:%s", resIdMatch, resMatch) - sEnc := b64.StdEncoding.EncodeToString([]byte(data)) - req, err := http.NewRequestWithContext(ctx, "GET", "https://www.easy-insight.com/app/api/users.json", nil) - if err != nil { - continue - } - req.Header.Add("Content-Type", "application/json") - req.Header.Add("Accept", "application/json") - req.Header.Add("Authorization", fmt.Sprintf("Basic %s", sEnc)) - res, err := client.Do(req) - if err == nil { - defer res.Body.Close() - if res.StatusCode >= 200 && res.StatusCode < 300 { - s1.Verified = true - } + verified, verificationErr := verifyEasyInsight(ctx, idMatch, keyMatch) + s1.Verified = verified + if verificationErr != nil { + s1.SetVerificationError(verificationErr) } } results = append(results, s1) + // if key id combination is verified, skip other idMatches for that key + if s1.Verified { + break + } } - } return results, nil @@ -93,3 +88,38 @@ func (s Scanner) Type() detectorspb.DetectorType { func (s Scanner) Description() string { return "EasyInsight is a business intelligence tool that provides data visualization and reporting. EasyInsight API keys can be used to access and manage data within the platform." } + +func verifyEasyInsight(ctx context.Context, id, key string) (bool, error) { + // docs: https://www.easy-insight.com/api/users.html + req, err := http.NewRequestWithContext(ctx, "GET", "https://www.easy-insight.com/app/api/users.json", nil) + if err != nil { + return false, err + } + + // add required headers to the request + req.Header.Add("Content-Type", "application/json") + req.Header.Add("Accept", "application/json") + // set basic auth for the request + req.SetBasicAuth(id, key) + + res, reqErr := client.Do(req) + if reqErr != nil { + return false, reqErr + } + defer func() { + _, _ = io.Copy(io.Discard, res.Body) + _ = res.Body.Close() + }() + + switch res.StatusCode { + // id, key verified + case http.StatusOK: + return true, nil + // id, key unverified + case http.StatusUnauthorized: + return false, nil + // something invalid + default: + return false, fmt.Errorf("unexpected status code: %d", res.StatusCode) + } +} diff --git a/pkg/detectors/easyinsight/easyinsight_integration_test.go b/pkg/detectors/easyinsight/easyinsight_integration_test.go new file mode 100644 index 000000000000..098b8a3a3954 --- /dev/null +++ b/pkg/detectors/easyinsight/easyinsight_integration_test.go @@ -0,0 +1,121 @@ +//go:build detectors +// +build detectors + +package easyinsight + +import ( + "context" + "fmt" + "testing" + "time" + + "github.com/kylelemons/godebug/pretty" + + "github.com/trufflesecurity/trufflehog/v3/pkg/common" + "github.com/trufflesecurity/trufflehog/v3/pkg/detectors" + "github.com/trufflesecurity/trufflehog/v3/pkg/pb/detectorspb" +) + +func TestEasyInsight_FromChunk(t *testing.T) { + ctx, cancel := context.WithTimeout(context.Background(), time.Second*5) + defer cancel() + testSecrets, err := common.GetSecret(ctx, "trufflehog-testing", "detectors1") + if err != nil { + t.Fatalf("could not get test secrets from GCP: %s", err) + } + secret := testSecrets.MustGetField("EASYINSIGHT") + inactiveSecret := testSecrets.MustGetField("EASYINSIGHT_INACTIVE") + id := testSecrets.MustGetField("EASYINSIGHT_ID") + + type args struct { + ctx context.Context + data []byte + verify bool + } + tests := []struct { + name string + s Scanner + args args + want []detectors.Result + wantErr bool + }{ + { + name: "found, verified", + s: Scanner{}, + args: args{ + ctx: context.Background(), + data: []byte(fmt.Sprintf("You can find a easyinsight secret %s within easyid %s", secret, id)), + verify: true, + }, + want: []detectors.Result{ + { + DetectorType: detectorspb.DetectorType_EasyInsight, + Verified: true, + }, + }, + wantErr: false, + }, + { + name: "found, unverified", + s: Scanner{}, + args: args{ + ctx: context.Background(), + data: []byte(fmt.Sprintf("You can find a easyinsight secret %s within easyid %s but not valid", inactiveSecret, id)), // the secret would satisfy the regex but not pass validation + verify: true, + }, + want: []detectors.Result{ + { + DetectorType: detectorspb.DetectorType_EasyInsight, + Verified: false, + }, + }, + wantErr: false, + }, + { + name: "not found", + s: Scanner{}, + args: args{ + ctx: context.Background(), + data: []byte("You cannot find the secret within"), + verify: true, + }, + want: nil, + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + s := Scanner{} + got, err := s.FromData(tt.args.ctx, tt.args.verify, tt.args.data) + if (err != nil) != tt.wantErr { + t.Errorf("EasyInsight.FromData() error = %v, wantErr %v", err, tt.wantErr) + return + } + for i := range got { + if len(got[i].Raw) == 0 { + t.Fatalf("no raw secret present: \n %+v", got[i]) + } + got[i].Raw = nil + } + if diff := pretty.Compare(got, tt.want); diff != "" { + t.Errorf("EasyInsight.FromData() %s diff: (-got +want)\n%s", tt.name, diff) + } + }) + } +} + +func BenchmarkFromData(benchmark *testing.B) { + ctx := context.Background() + s := Scanner{} + for name, data := range detectors.MustGetBenchmarkData() { + benchmark.Run(name, func(b *testing.B) { + b.ResetTimer() + for n := 0; n < b.N; n++ { + _, err := s.FromData(ctx, false, data) + if err != nil { + b.Fatal(err) + } + } + }) + } +} diff --git a/pkg/detectors/easyinsight/easyinsight_test.go b/pkg/detectors/easyinsight/easyinsight_test.go index 098b8a3a3954..00ef59366d40 100644 --- a/pkg/detectors/easyinsight/easyinsight_test.go +++ b/pkg/detectors/easyinsight/easyinsight_test.go @@ -1,121 +1,106 @@ -//go:build detectors -// +build detectors - package easyinsight import ( "context" "fmt" "testing" - "time" - "github.com/kylelemons/godebug/pretty" + "github.com/google/go-cmp/cmp" - "github.com/trufflesecurity/trufflehog/v3/pkg/common" "github.com/trufflesecurity/trufflehog/v3/pkg/detectors" - "github.com/trufflesecurity/trufflehog/v3/pkg/pb/detectorspb" + "github.com/trufflesecurity/trufflehog/v3/pkg/engine/ahocorasick" ) -func TestEasyInsight_FromChunk(t *testing.T) { - ctx, cancel := context.WithTimeout(context.Background(), time.Second*5) - defer cancel() - testSecrets, err := common.GetSecret(ctx, "trufflehog-testing", "detectors1") - if err != nil { - t.Fatalf("could not get test secrets from GCP: %s", err) - } - secret := testSecrets.MustGetField("EASYINSIGHT") - inactiveSecret := testSecrets.MustGetField("EASYINSIGHT_INACTIVE") - id := testSecrets.MustGetField("EASYINSIGHT_ID") +var ( + validKeyPattern = "987ahjjdasgUcaaraAdd" + validIDPattern = "poiuy76RaEf90ertgh0K" + // this should result in 4 combinations + complexPattern = `easyinsight credentials + these credentials are for testing a pattern + key: A876AcaraTsaAKcae09a + id: chECk12345ChecK12345 + ------------------------- + second credentials: + key: B874CDaraTsaAKVBe08A + id: CHECK12345ChecK09876` + invalidPattern = "poiuy76=a_$90ertgh0K" +) + +func TestEasyInsight_Pattern(t *testing.T) { + d := Scanner{} + ahoCorasickCore := ahocorasick.NewAhoCorasickCore([]detectors.Detector{d}) - type args struct { - ctx context.Context - data []byte - verify bool - } tests := []struct { - name string - s Scanner - args args - want []detectors.Result - wantErr bool + name string + input string + want []string }{ { - name: "found, verified", - s: Scanner{}, - args: args{ - ctx: context.Background(), - data: []byte(fmt.Sprintf("You can find a easyinsight secret %s within easyid %s", secret, id)), - verify: true, - }, - want: []detectors.Result{ - { - DetectorType: detectorspb.DetectorType_EasyInsight, - Verified: true, - }, - }, - wantErr: false, + name: "valid pattern", + input: fmt.Sprintf("easyinsight key = '%s' easy-insight id = '%s", validKeyPattern, validIDPattern), + want: []string{validKeyPattern + validIDPattern, validIDPattern + validKeyPattern}, }, { - name: "found, unverified", - s: Scanner{}, - args: args{ - ctx: context.Background(), - data: []byte(fmt.Sprintf("You can find a easyinsight secret %s within easyid %s but not valid", inactiveSecret, id)), // the secret would satisfy the regex but not pass validation - verify: true, - }, - want: []detectors.Result{ - { - DetectorType: detectorspb.DetectorType_EasyInsight, - Verified: false, - }, + name: "valid pattern - complex", + input: fmt.Sprintf("easyinsight token = '%s'", complexPattern), + want: []string{ + "A876AcaraTsaAKcae09achECk12345ChecK12345", + "A876AcaraTsaAKcae09aCHECK12345ChecK09876", + "B874CDaraTsaAKVBe08ACHECK12345ChecK09876", + "B874CDaraTsaAKVBe08AchECk12345ChecK12345", }, - wantErr: false, }, { - name: "not found", - s: Scanner{}, - args: args{ - ctx: context.Background(), - data: []byte("You cannot find the secret within"), - verify: true, - }, - want: nil, - wantErr: false, + name: "valid pattern - out of prefix range", + input: fmt.Sprintf("easyinsight key and id keyword is not close to the real token = '%s|%s'", validKeyPattern, validIDPattern), + want: nil, + }, + { + name: "invalid pattern", + input: fmt.Sprintf("easyinsight = '%s|%s'", invalidPattern, invalidPattern), + want: nil, }, } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - s := Scanner{} - got, err := s.FromData(tt.args.ctx, tt.args.verify, tt.args.data) - if (err != nil) != tt.wantErr { - t.Errorf("EasyInsight.FromData() error = %v, wantErr %v", err, tt.wantErr) + + 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 } - for i := range got { - if len(got[i].Raw) == 0 { - t.Fatalf("no raw secret present: \n %+v", got[i]) - } - got[i].Raw = nil + + results, err := d.FromData(context.Background(), false, []byte(test.input)) + if err != nil { + t.Errorf("error = %v", err) + return } - if diff := pretty.Compare(got, tt.want); diff != "" { - t.Errorf("EasyInsight.FromData() %s diff: (-got +want)\n%s", tt.name, diff) + + 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 } - }) - } -} -func BenchmarkFromData(benchmark *testing.B) { - ctx := context.Background() - s := Scanner{} - for name, data := range detectors.MustGetBenchmarkData() { - benchmark.Run(name, func(b *testing.B) { - b.ResetTimer() - for n := 0; n < b.N; n++ { - _, err := s.FromData(ctx, false, data) - if err != nil { - b.Fatal(err) + 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) + } }) } } From 76ca1717651642065349057847fe5592485cdc1d Mon Sep 17 00:00:00 2001 From: Abdul Basit Date: Wed, 9 Oct 2024 19:54:14 +0500 Subject: [PATCH 08/76] [Fix] Snowflake privatelink Support (#3286) * [Fixes] - handling of `.privatelink` in account identifier - added unit test for pattern detection. - fixes hard coded account and username in test. * variable name fixes --- go.sum | 40 +------ pkg/detectors/snowflake/snowflake.go | 15 +-- pkg/detectors/snowflake/snowflake_test.go | 131 +++++++++++++++++++--- 3 files changed, 128 insertions(+), 58 deletions(-) diff --git a/go.sum b/go.sum index 4a6dd03d3156..298186b894d1 100644 --- a/go.sum +++ b/go.sum @@ -20,12 +20,10 @@ cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNF cloud.google.com/go/compute/metadata v0.5.2 h1:UxK4uu/Tn+I3p2dYWTfiX4wva7aYlKixAHn3fyqngqo= cloud.google.com/go/compute/metadata v0.5.2/go.mod h1:C66sj2AluDcIqakBq/M8lw8/ybHgOZqin2obFxa/E5k= cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= -cloud.google.com/go/iam v1.2.0 h1:kZKMKVNk/IsSSc/udOb83K0hL/Yh/Gcqpz+oAkoIFN8= -cloud.google.com/go/iam v1.2.0/go.mod h1:zITGuWgsLZxd8OwAlX+eMFgZDXzBm7icj1PVTYG766Q= cloud.google.com/go/iam v1.2.1 h1:QFct02HRb7H12J/3utj0qf5tobFh9V4vR6h9eX5EBRU= cloud.google.com/go/iam v1.2.1/go.mod h1:3VUIJDPpwT6p/amXRC5GY8fCCh70lxPygguVtI0Z4/g= -cloud.google.com/go/longrunning v0.6.0 h1:mM1ZmaNsQsnb+5n1DNPeL0KwQd9jQRqSqSDEkBZr+aI= -cloud.google.com/go/longrunning v0.6.0/go.mod h1:uHzSZqW89h7/pasCWNYdUpwGz3PcVWhrWupreVPYLts= +cloud.google.com/go/logging v1.11.0 h1:v3ktVzXMV7CwHq1MBF65wcqLMA7i+z3YxbUsoK7mOKs= +cloud.google.com/go/logging v1.11.0/go.mod h1:5LDiJC/RxTt+fHc1LAt20R9TKiUTReDg6RuuFOZ67+A= cloud.google.com/go/longrunning v0.6.1 h1:lOLTFxYpr8hcRtcwWir5ITh1PAKUD/sG2lKrTSYjyMc= cloud.google.com/go/longrunning v0.6.1/go.mod h1:nHISoOZpBcmlwbJmiVk5oDRz0qG/ZxPynEGs1iZ79s0= cloud.google.com/go/monitoring v1.21.0 h1:EMc0tB+d3lUewT2NzKC/hr8cSR9WsUieVywzIHetGro= @@ -36,10 +34,10 @@ cloud.google.com/go/secretmanager v1.14.1 h1:xlWSIg8rtBn5qCr2f3XtQP19+5COyf/ll49 cloud.google.com/go/secretmanager v1.14.1/go.mod h1:L+gO+u2JA9CCyXpSR8gDH0o8EV7i/f0jdBOrUXcIV0U= cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= -cloud.google.com/go/storage v1.43.0 h1:CcxnSohZwizt4LCzQHWvBf1/kvtHUn7gk9QERXPyXFs= -cloud.google.com/go/storage v1.43.0/go.mod h1:ajvxEa7WmZS1PxvKRq4bq0tFT3vMd502JwstCcYv0Q0= cloud.google.com/go/storage v1.44.0 h1:abBzXf4UJKMmQ04xxJf9dYM/fNl24KHoTuBjyJDX2AI= cloud.google.com/go/storage v1.44.0/go.mod h1:wpPblkIuMP5jCB/E48Pz9zIo2S/zD8g+ITmxKkPCITE= +cloud.google.com/go/trace v1.11.0 h1:UHX6cOJm45Zw/KIbqHe4kII8PupLt/V5tscZUkeiJVI= +cloud.google.com/go/trace v1.11.0/go.mod h1:Aiemdi52635dBR7o3zuc9lLjXo3BwGaChEjCa3tJNmM= dario.cat/mergo v1.0.0 h1:AGCNq9Evsj31mOgNPcLyXc+4PNABt905YmuqPYYpBWk= dario.cat/mergo v1.0.0/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= @@ -98,6 +96,8 @@ github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.24.1 github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.24.1/go.mod h1:itPGVDKf9cC/ov4MdvJ2QZ0khw4bfoo9jzwTJlaxy2k= github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.48.1 h1:UQ0AhxogsIRZDkElkblfnwjc3IaltCm2HUMvezQaL7s= github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.48.1/go.mod h1:jyqM3eLpJ3IbIFDTKVz2rF9T/xWGW0rIriGwnz8l9Tk= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/cloudmock v0.48.1 h1:oTX4vsorBZo/Zdum6OKPA4o7544hm6smoRv1QjpTwGo= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/cloudmock v0.48.1/go.mod h1:0wEl7vrAD8mehJyohS9HZy+WyEOaQO2mJx86Cvh93kM= github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.48.1 h1:8nn+rsCvTq9axyEh382S0PFLBeaFwNsT43IrPWzctRU= github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.48.1/go.mod h1:viRWSEhtMZqz1rhwmOVKkWl6SwmVowfL9O2YR5gI2PE= github.com/JohnCGriffin/overflow v0.0.0-20211019200055-46fa312c352c h1:RGWPOewvKIROun94nF7v2cua9qP+thov/7M50KEoeSU= @@ -438,8 +438,6 @@ github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+ github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/googleapis/gax-go/v2 v2.13.0 h1:yitjD5f7jQHhyDsnhKEBU52NdvvdSeGzlAnDPT0hH1s= github.com/googleapis/gax-go/v2 v2.13.0/go.mod h1:Z/fvTZXF8/uw7Xu5GuslPw+bplx6SS338j1Is2S+B7A= -github.com/gorilla/css v1.0.0 h1:BQqNyPTi50JCFMTw/b67hByjMVXZRwGha6wxVGkeihY= -github.com/gorilla/css v1.0.0/go.mod h1:Dn721qIggHpt4+EFCcTLTU/vk5ySda2ReITrtgBl60c= github.com/gorilla/css v1.0.1 h1:ntNaBIghp6JmvWnxbZKANoLyuXTPZ4cAMlo6RyhlbO8= github.com/gorilla/css v1.0.1/go.mod h1:BvnYkspnSzMmwRK+b8/xgNPLiIuNZr6vbZBTPQ2A3b0= github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4= @@ -500,8 +498,6 @@ github.com/jcmturner/rpc/v2 v2.0.3 h1:7FXXj8Ti1IaVFpSAziCZWNzbNuZmnvw/i6CqLNdWfZ github.com/jcmturner/rpc/v2 v2.0.3/go.mod h1:VUJYCIDm3PVOEHw8sgt091/20OJjskO/YJki3ELg/Hc= github.com/jedib0t/go-pretty v4.3.0+incompatible h1:CGs8AVhEKg/n9YbUenWmNStRW2PHJzaeDodcfvRAbIo= github.com/jedib0t/go-pretty v4.3.0+incompatible/go.mod h1:XemHduiw8R651AF9Pt4FwCTKeG3oo7hrHJAoznj9nag= -github.com/jedib0t/go-pretty/v6 v6.5.9 h1:ACteMBRrrmm1gMsXe9PSTOClQ63IXDUt03H5U+UV8OU= -github.com/jedib0t/go-pretty/v6 v6.5.9/go.mod h1:zbn98qrYlh95FIhwwsbIip0LYpwSG8SUOScs+v9/t0E= github.com/jedib0t/go-pretty/v6 v6.6.0 h1:wmZVuAcEkZRT+Aq1xXpE8IGat4vE5WXOMmBpbQqERXw= github.com/jedib0t/go-pretty/v6 v6.6.0/go.mod h1:zbn98qrYlh95FIhwwsbIip0LYpwSG8SUOScs+v9/t0E= github.com/jlaffaye/ftp v0.2.0 h1:lXNvW7cBu7R/68bknOX3MrRIIqZ61zELs1P2RAiA3lg= @@ -572,8 +568,6 @@ github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6T github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= github.com/mholt/archiver/v4 v4.0.0-alpha.8.0.20240408183022-de08bfa4c558 h1:mm89WXPE/mac3dHr0uNa6rfuJ3xAwveCv7a+lrfszHQ= github.com/mholt/archiver/v4 v4.0.0-alpha.8.0.20240408183022-de08bfa4c558/go.mod h1:/PrlQ8Ei1tfloDN9iyxK26Z++5EX1M29t6eEEvHKoIo= -github.com/microcosm-cc/bluemonday v1.0.25 h1:4NEwSfiJ+Wva0VxN5B8OwMicaJvD8r9tlJWm9rtloEg= -github.com/microcosm-cc/bluemonday v1.0.25/go.mod h1:ZIOjCQp1OrzBBPIJmfX4qDYFuhU02nx4bn030ixfHLE= github.com/microcosm-cc/bluemonday v1.0.27 h1:MpEUotklkwCSLeH+Qdx1VJgNqLlpY2KXwXFM08ygZfk= github.com/microcosm-cc/bluemonday v1.0.27/go.mod h1:jFi9vgW+H7c3V0lb6nR74Ib/DIB5OBs92Dimizgw2cA= github.com/microsoft/go-mssqldb v1.7.2 h1:CHkFJiObW7ItKTJfHo1QX7QBBD1iV+mn1eOyRP3b/PA= @@ -689,8 +683,6 @@ github.com/sahilm/fuzzy v0.1.1-0.20230530133925-c48e322e2a8f h1:MvTmaQdww/z0Q4wr github.com/sahilm/fuzzy v0.1.1-0.20230530133925-c48e322e2a8f/go.mod h1:VFvziUEIMCrT6A6tw2RFIXPXXmzXbOsSHF0DOI8ZK9Y= github.com/sassoftware/go-rpmutils v0.4.0 h1:ojND82NYBxgwrV+mX1CWsd5QJvvEZTKddtCdFLPWhpg= github.com/sassoftware/go-rpmutils v0.4.0/go.mod h1:3goNWi7PGAT3/dlql2lv3+MSN5jNYPjT5mVcQcIsYzI= -github.com/schollz/progressbar/v3 v3.16.0 h1:+MbBim/cE9DqDb8UXRfLJ6RZdyDkXG1BDy/sWc5s0Mc= -github.com/schollz/progressbar/v3 v3.16.0/go.mod h1:lLiKjKJ9/yzc9Q8jk+sVLfxWxgXKsktvUf6TO+4Y2nw= github.com/schollz/progressbar/v3 v3.16.1 h1:RnF1neWZFzLCoGx8yp1yF7SDl4AzNDI5y4I0aUJRrZQ= github.com/schollz/progressbar/v3 v3.16.1/go.mod h1:I2ILR76gz5VXqYMIY/LdLecvMHDPVcQm3W/MSKi1TME= github.com/sendgrid/rest v2.6.9+incompatible h1:1EyIcsNdn9KIisLW50MKwmSRSK+ekueiEMJ7NEoxJo0= @@ -782,8 +774,6 @@ github.com/wasilibs/nottinygc v0.4.0 h1:h1TJMihMC4neN6Zq+WKpLxgd9xCFMw7O9ETLwY2e github.com/wasilibs/nottinygc v0.4.0/go.mod h1:oDcIotskuYNMpqMF23l7Z8uzD4TC0WXHK8jetlB3HIo= github.com/wasilibs/wazero-helpers v0.0.0-20240620070341-3dff1577cd52 h1:OvLBa8SqJnZ6P+mjlzc2K7PM22rRUPE1x32G9DTPrC4= github.com/wasilibs/wazero-helpers v0.0.0-20240620070341-3dff1577cd52/go.mod h1:jMeV4Vpbi8osrE/pKUxRZkVaA0EX7NZN0A9/oRzgpgY= -github.com/xanzy/go-gitlab v0.109.0 h1:RcRme5w8VpLXTSTTMZdVoQWY37qTJWg+gwdQl4aAttE= -github.com/xanzy/go-gitlab v0.109.0/go.mod h1:wKNKh3GkYDMOsGmnfuX+ITCmDuSDWFO0G+C4AygL9RY= github.com/xanzy/go-gitlab v0.110.0 h1:hsFIFp01v/0D0sdUXoZfRk6CROzZbHQplk6NzKSFKhc= github.com/xanzy/go-gitlab v0.110.0/go.mod h1:wKNKh3GkYDMOsGmnfuX+ITCmDuSDWFO0G+C4AygL9RY= github.com/xanzy/ssh-agent v0.3.3 h1:+/15pJfg/RsTxqYcX6fHqOXZwwMP+2VyYWJeWM2qQFM= @@ -821,8 +811,6 @@ github.com/zeebo/xxh3 v1.0.2 h1:xZmwmqxHZA8AI603jOQ0tMqmBr9lPeFwGg6d+xy9DC0= github.com/zeebo/xxh3 v1.0.2/go.mod h1:5NWz9Sef7zIDm2JHfFlcQvNekmcEl9ekUZQQKCYaDcA= go.einride.tech/aip v0.60.0 h1:h6bgabZ5BCfAptbGex8jbh3VvPBRLa6xq+pQ1CAjHYw= go.einride.tech/aip v0.60.0/go.mod h1:SdLbSbgSU60Xkb4TMkmsZEQPHeEWx0ikBoq5QnqZvdg= -go.mongodb.org/mongo-driver v1.17.0 h1:Hp4q2MCjvY19ViwimTs00wHi7G4yzxh4/2+nTx8r40k= -go.mongodb.org/mongo-driver v1.17.0/go.mod h1:wwWm/+BuOddhcq3n68LKRmgk2wXzmF6s0SFOa0GINL4= go.mongodb.org/mongo-driver v1.17.1 h1:Wic5cJIwJgSpBhe3lx3+/RybR5PiYRMpVFgO7cOHyIM= go.mongodb.org/mongo-driver v1.17.1/go.mod h1:wwWm/+BuOddhcq3n68LKRmgk2wXzmF6s0SFOa0GINL4= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= @@ -883,8 +871,6 @@ golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs= -golang.org/x/crypto v0.27.0 h1:GXm2NjJrPaiv/h1tb2UH8QfgC/hOf/+z0p6PT8o1w7A= -golang.org/x/crypto v0.27.0/go.mod h1:1Xngt8kV6Dvbssa53Ziq6Eqn0HqbZi5Z6R0ZpwQzt70= golang.org/x/crypto v0.28.0 h1:GBDwsMXVQi34v5CCYUm2jkJvu4cbtru2U4TN2PSyQnw= golang.org/x/crypto v0.28.0/go.mod h1:rmgy+3RHxRZMyY0jjAJShp2zgEdOqj2AO7U0pYmeQ7U= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= @@ -895,8 +881,6 @@ golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= -golang.org/x/exp v0.0.0-20240909161429-701f63a606c0 h1:e66Fs6Z+fZTbFBAxKfP3PALWBtpfqks2bwGcexMxgtk= -golang.org/x/exp v0.0.0-20240909161429-701f63a606c0/go.mod h1:2TbTHSBQa924w8M6Xs1QcRcFwyucIwBGpK1p2f1YFFY= golang.org/x/exp v0.0.0-20241004190924-225e2abe05e6 h1:1wqE9dj9NpSm04INVsJhhEUzhuDVjbcyKH91sVyPATw= golang.org/x/exp v0.0.0-20241004190924-225e2abe05e6/go.mod h1:NQtJDoLvd6faHhE7m4T/1IY708gDefGGjR/iUW8yQQ8= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= @@ -951,8 +935,6 @@ golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= golang.org/x/net v0.22.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= -golang.org/x/net v0.29.0 h1:5ORfpBpCs4HzDYoodCDBbwHzdR5UrLBZ3sOnUJmFoHo= -golang.org/x/net v0.29.0/go.mod h1:gLkgy8jTGERgjzMic6DS9+SP0ajcu6Xu3Orq/SpETg0= golang.org/x/net v0.30.0 h1:AcW1SDZMkb8IpzCdQUaIq2sP4sZ4zw+55h6ynffypl4= golang.org/x/net v0.30.0/go.mod h1:2wGyMJ5iFasEhkwi13ChkO/t1ECNC4X4eBKkVFyYFlU= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= @@ -1020,8 +1002,6 @@ golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34= -golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.26.0 h1:KHjCJyddX0LoSTb3J+vWpupP9p0oznkqVk/IfjymZbo= golang.org/x/sys v0.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= @@ -1033,8 +1013,6 @@ golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= golang.org/x/term v0.15.0/go.mod h1:BDl952bC7+uMoWR75FIrCDx79TPU9oHkTZ9yRbYOrX0= golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk= golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58= -golang.org/x/term v0.24.0 h1:Mh5cbb+Zk2hqqXNO7S1iTjEphVL+jb8ZWaqh/g+JWkM= -golang.org/x/term v0.24.0/go.mod h1:lOBK/LVxemqiMij05LGJ0tzNr8xlmwBRJ81PX6wVLH8= golang.org/x/term v0.25.0 h1:WtHI/ltw4NvSUig5KARz9h521QvRC8RmF/cuYqifU24= golang.org/x/term v0.25.0/go.mod h1:RPyXicDX+6vLxogjjRxjgD2TKtmAO6NZBsBRfrOLu7M= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -1050,8 +1028,6 @@ golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= -golang.org/x/text v0.18.0 h1:XvMDiNzPAl0jr17s6W9lcaIhGUfUORdGCNsuLmPG224= -golang.org/x/text v0.18.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= golang.org/x/text v0.19.0 h1:kTxAhCbGbxhK0IwgSKiMO5awPoDQ0RpfiVYBfK860YM= golang.org/x/text v0.19.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -1089,8 +1065,6 @@ golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4f golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= -golang.org/x/tools v0.25.0 h1:oFU9pkj/iJgs+0DT+VMHrx+oBKs/LJMV+Uvg78sl+fE= -golang.org/x/tools v0.25.0/go.mod h1:/vtpO8WL1N9cQC3FN5zPqb//fRXskFHbLKk4OW1Q7rg= golang.org/x/tools v0.26.0 h1:v/60pFQmzmT9ExmjDv2gGIfi3OqfKoEP6I5+umXlbnQ= golang.org/x/tools v0.26.0/go.mod h1:TPVVj70c7JJ3WCazhD8OdXcZg/og+b9+tH/KxylGwH0= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -1160,8 +1134,6 @@ google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2 google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= -google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= -google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= google.golang.org/protobuf v1.35.1 h1:m3LfL6/Ca+fqnjnlqQXNpFPABW1UD7mjh8KO2mKFytA= google.golang.org/protobuf v1.35.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= diff --git a/pkg/detectors/snowflake/snowflake.go b/pkg/detectors/snowflake/snowflake.go index 720ba235429a..189c30708927 100644 --- a/pkg/detectors/snowflake/snowflake.go +++ b/pkg/detectors/snowflake/snowflake.go @@ -24,7 +24,7 @@ type Scanner struct { var _ detectors.Detector = (*Scanner)(nil) var ( - accountIdentifierPat = regexp.MustCompile(detectors.PrefixRegex([]string{"account"}) + `\b([a-zA-Z]{7}-[0-9a-zA-Z]{7})\b`) + accountIdentifierPat = regexp.MustCompile(detectors.PrefixRegex([]string{"account"}) + `\b([a-zA-Z]{7}-[0-9a-zA-Z-_]{1,255}(.privatelink)?)\b`) usernameExclusionPat = `!@#$%^&*{}:<>,.;?()/\+=\s\n` ) @@ -71,7 +71,10 @@ func meetsSnowflakePasswordRequirements(password string) (string, bool) { func (s Scanner) FromData(ctx context.Context, verify bool, data []byte) (results []detectors.Result, err error) { dataStr := string(data) - accountMatches := accountIdentifierPat.FindAllStringSubmatch(dataStr, -1) + uniqueAccountMatches := make(map[string]struct{}) + for _, match := range accountIdentifierPat.FindAllStringSubmatch(dataStr, -1) { + uniqueAccountMatches[strings.TrimSpace(match[1])] = struct{}{} + } usernameRegexState := common.UsernameRegexCheck(usernameExclusionPat) usernameMatches := usernameRegexState.Matches(data) @@ -79,14 +82,8 @@ func (s Scanner) FromData(ctx context.Context, verify bool, data []byte) (result passwordRegexState := common.PasswordRegexCheck(" ") // No explicit character exclusions by Snowflake for passwords passwordMatches := passwordRegexState.Matches(data) - for _, accountMatch := range accountMatches { - if len(accountMatch) != 2 { - continue - } - resAccountMatch := strings.TrimSpace(accountMatch[1]) - + for resAccountMatch := range uniqueAccountMatches { for _, resUsernameMatch := range usernameMatches { - for _, resPasswordMatch := range passwordMatches { _, metPasswordRequirements := meetsSnowflakePasswordRequirements(resPasswordMatch) diff --git a/pkg/detectors/snowflake/snowflake_test.go b/pkg/detectors/snowflake/snowflake_test.go index 322d679b1867..f06a872fde00 100644 --- a/pkg/detectors/snowflake/snowflake_test.go +++ b/pkg/detectors/snowflake/snowflake_test.go @@ -9,15 +9,102 @@ import ( "testing" "time" + "github.com/brianvoe/gofakeit/v7" "github.com/google/go-cmp/cmp" "github.com/google/go-cmp/cmp/cmpopts" - - "github.com/trufflesecurity/trufflehog/v3/pkg/detectors" - "github.com/trufflesecurity/trufflehog/v3/pkg/common" + "github.com/trufflesecurity/trufflehog/v3/pkg/detectors" + "github.com/trufflesecurity/trufflehog/v3/pkg/engine/ahocorasick" "github.com/trufflesecurity/trufflehog/v3/pkg/pb/detectorspb" ) +func TestSnowflake_Pattern(t *testing.T) { + username := gofakeit.Username() + password := gofakeit.Password(true, true, true, false, false, 10) + + d := Scanner{} + ahoCorasickCore := ahocorasick.NewAhoCorasickCore([]detectors.Detector{d}) + tests := []struct { + name string + input string + want [][]string + }{ + { + name: "Snowflake Credentials", + input: fmt.Sprintf("snowflake: \n account=%s \n username=%s \n password=%s \n database=SNOWFLAKE", "tuacoip-zt74995", username, password), + want: [][]string{ + []string{"tuacoip-zt74995", username, password}, + }, + }, + { + name: "Private Snowflake Credentials", + input: fmt.Sprintf("snowflake: \n account=%s \n username=%s \n password=%s \n database=SNOWFLAKE", "tuacoip-zt74995.privatelink", username, password), + want: [][]string{ + []string{"tuacoip-zt74995.privatelink", username, password}, + }, + }, + + { + name: "Snowflake Credentials - Single Character account", + input: fmt.Sprintf("snowflake: \n account=%s \n username=%s \n password=%s \n database=SNOWFLAKE", "tuacoip-z", username, password), + want: [][]string{ + []string{"tuacoip-z", username, password}, + }, + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + detectorMatches := ahoCorasickCore.FindDetectorMatches([]byte(test.input)) + if len(detectorMatches) == 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 + } + + resultsArray := make([][]string, len(results)) + for i, r := range results { + resultsArray[i] = []string{r.ExtraData["account"], r.ExtraData["username"], string(r.Raw)} + } + + 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{}{} + } + actual[r.ExtraData["account"]] = struct{}{} + actual[r.ExtraData["username"]] = struct{}{} + } + expected := make(map[string]struct{}, len(test.want)) + for _, v := range test.want { + for _, value := range v { + expected[value] = struct{}{} + } + } + + if diff := cmp.Diff(expected, actual); diff != "" { + t.Errorf("%s diff: (-want +got)\n%s", test.name, diff) + } + }) + } +} + func TestSnowflake_FromChunk(t *testing.T) { ctx, cancel := context.WithTimeout(context.Background(), time.Second*5) defer cancel() @@ -26,8 +113,10 @@ func TestSnowflake_FromChunk(t *testing.T) { t.Fatalf("could not get test secrets from GCP: %s", err) } - secret := testSecrets.MustGetField("SNOWFLAKE_PASS") - inactiveSecret := testSecrets.MustGetField("SNOWFLAKE_PASS_INACTIVE") + accountIdentifier := testSecrets.MustGetField("SNOWFLAKE_ACCOUNT") + username := testSecrets.MustGetField("SNOWFLAKE_USERNAME") + password := testSecrets.MustGetField("SNOWFLAKE_PASS") + inactivePassword := testSecrets.MustGetField("SNOWFLAKE_PASS_INACTIVE") // Create a context with a past deadline to simulate DeadlineExceeded error pastTime := time.Now().Add(-time.Second) // Set the deadline in the past @@ -52,7 +141,7 @@ func TestSnowflake_FromChunk(t *testing.T) { s: Scanner{}, args: args{ ctx: context.Background(), - data: []byte(fmt.Sprintf("snowflake: \n account=tuacoip-zt74995 \n username=zubairkhan14 \n password=%s \n database=SNOWFLAKE", secret)), + data: []byte(fmt.Sprintf("snowflake: \n account=%s \n username=%s \n password=%s \n database=SNOWFLAKE", accountIdentifier, username, password)), verify: true, }, want: []detectors.Result{ @@ -60,9 +149,8 @@ func TestSnowflake_FromChunk(t *testing.T) { DetectorType: detectorspb.DetectorType_Snowflake, Verified: true, ExtraData: map[string]string{ - "account": "tuacoip-zt74995", - "databases": "SNOWFLAKE, SNOWFLAKE_SAMPLE_DATA", - "username": "zubairkhan14", + "account": accountIdentifier, + "username": username, }, }, }, @@ -74,7 +162,7 @@ func TestSnowflake_FromChunk(t *testing.T) { s: Scanner{}, args: args{ ctx: context.Background(), - data: []byte(fmt.Sprintf("snowflake: \n account=tuacoip-zt74995 \n username=zubairkhan14 \n password=%s \n database=SNOWFLAKE", inactiveSecret)), + data: []byte(fmt.Sprintf("snowflake: \n account=%s \n username=%s \n password=%s \n database=SNOWFLAKE", accountIdentifier, username, inactivePassword)), verify: true, }, want: []detectors.Result{ @@ -82,8 +170,8 @@ func TestSnowflake_FromChunk(t *testing.T) { DetectorType: detectorspb.DetectorType_Snowflake, Verified: false, ExtraData: map[string]string{ - "account": "tuacoip-zt74995", - "username": "zubairkhan14", + "account": accountIdentifier, + "username": username, }, }, }, @@ -107,15 +195,15 @@ func TestSnowflake_FromChunk(t *testing.T) { s: Scanner{}, args: args{ ctx: errorCtx, - data: []byte(fmt.Sprintf("snowflake: \n account=tuacoip-zt74995 \n username=zubairkhan14 \n password=%s \n database=SNOWFLAKE", secret)), + data: []byte(fmt.Sprintf("snowflake: \n account=%s \n username=%s \n password=%s \n database=SNOWFLAKE", accountIdentifier, username, password)), verify: true, }, want: []detectors.Result{ { DetectorType: detectorspb.DetectorType_Snowflake, ExtraData: map[string]string{ - "account": "tuacoip-zt74995", - "username": "zubairkhan14", + "account": accountIdentifier, + "username": username, }, }, }, @@ -130,6 +218,7 @@ func TestSnowflake_FromChunk(t *testing.T) { t.Errorf("Snowflake.FromData() error = %v, wantErr %v", err, tt.wantErr) return } + keysToCopy := []string{"account", "username"} for i := range got { if len(got[i].Raw) == 0 { t.Fatalf("no raw secret present: \n %+v", got[i]) @@ -137,6 +226,8 @@ func TestSnowflake_FromChunk(t *testing.T) { if (got[i].VerificationError() != nil) != tt.wantVerificationErr { t.Fatalf("wantVerificationError = %v, verification error = %v", tt.wantVerificationErr, got[i].VerificationError()) } + + got[i].ExtraData = newMap(got[i].ExtraData, keysToCopy) } ignoreOpts := cmpopts.IgnoreFields(detectors.Result{}, "Raw", "verificationError") if diff := cmp.Diff(got, tt.want, ignoreOpts); diff != "" { @@ -146,6 +237,16 @@ func TestSnowflake_FromChunk(t *testing.T) { } } +func newMap(extraMap map[string]string, keysToCopy []string) map[string]string { + newExtraDataMap := make(map[string]string) + for _, key := range keysToCopy { + if value, ok := extraMap[key]; ok { + newExtraDataMap[key] = value + } + } + return newExtraDataMap +} + func BenchmarkFromData(benchmark *testing.B) { ctx := context.Background() s := Scanner{} From 6f1a717d0e115f83b5a80e4ae518d64f42594eae Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 9 Oct 2024 17:54:09 -0700 Subject: [PATCH 09/76] fix(deps): update module google.golang.org/api to v0.200.0 (#3391) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- go.mod | 16 ++++++++-------- go.sum | 16 ++++++++++++++++ 2 files changed, 24 insertions(+), 8 deletions(-) diff --git a/go.mod b/go.mod index ef3a66d31e95..dcb8d22faaf4 100644 --- a/go.mod +++ b/go.mod @@ -108,7 +108,7 @@ require ( golang.org/x/oauth2 v0.23.0 golang.org/x/sync v0.8.0 golang.org/x/text v0.19.0 - google.golang.org/api v0.199.0 + google.golang.org/api v0.200.0 google.golang.org/protobuf v1.35.1 gopkg.in/h2non/gock.v1 v1.1.2 gopkg.in/yaml.v2 v2.4.0 @@ -121,12 +121,12 @@ require ( require ( cel.dev/expr v0.16.1 // indirect cloud.google.com/go v0.115.1 // indirect - cloud.google.com/go/auth v0.9.5 // indirect + cloud.google.com/go/auth v0.9.8 // indirect cloud.google.com/go/auth/oauth2adapt v0.2.4 // indirect cloud.google.com/go/compute/metadata v0.5.2 // indirect cloud.google.com/go/iam v1.2.1 // indirect cloud.google.com/go/longrunning v0.6.1 // indirect - cloud.google.com/go/monitoring v1.21.0 // indirect + cloud.google.com/go/monitoring v1.21.1 // indirect dario.cat/mergo v1.0.0 // indirect filippo.io/edwards25519 v1.1.0 // indirect github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4 // indirect @@ -316,13 +316,13 @@ require ( golang.org/x/mod v0.21.0 // indirect golang.org/x/sys v0.26.0 // indirect golang.org/x/term v0.25.0 // indirect - golang.org/x/time v0.6.0 // indirect + golang.org/x/time v0.7.0 // indirect golang.org/x/tools v0.26.0 // indirect golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 // indirect - google.golang.org/genproto v0.0.0-20240903143218-8af14fe29dc1 // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20240903143218-8af14fe29dc1 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1 // indirect - google.golang.org/grpc v1.67.0 // indirect + google.golang.org/genproto v0.0.0-20241007155032-5fefd90f89a9 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20240930140551-af27646dc61f // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20241007155032-5fefd90f89a9 // indirect + google.golang.org/grpc v1.67.1 // indirect google.golang.org/grpc/stats/opentelemetry v0.0.0-20240907200651-3ffb98b2c93a // indirect gopkg.in/warnings.v0 v0.1.2 // indirect pault.ag/go/topsort v0.1.1 // indirect diff --git a/go.sum b/go.sum index 298186b894d1..7d2f0f2eb29f 100644 --- a/go.sum +++ b/go.sum @@ -13,6 +13,8 @@ cloud.google.com/go v0.115.1 h1:Jo0SM9cQnSkYfp44+v+NQXHpcHqlnRJk2qxh6yvxxxQ= cloud.google.com/go v0.115.1/go.mod h1:DuujITeaufu3gL68/lOFIirVNJwQeyf5UXyi+Wbgknc= cloud.google.com/go/auth v0.9.5 h1:4CTn43Eynw40aFVr3GpPqsQponx2jv0BQpjvajsbbzw= cloud.google.com/go/auth v0.9.5/go.mod h1:Xo0n7n66eHyOWWCnitop6870Ilwo3PiZyodVkkH1xWM= +cloud.google.com/go/auth v0.9.8 h1:+CSJ0Gw9iVeSENVCKJoLHhdUykDgXSc4Qn+gu2BRtR8= +cloud.google.com/go/auth v0.9.8/go.mod h1:xxA5AqpDrvS+Gkmo9RqrGGRh6WSNKKOXhY3zNOr38tI= cloud.google.com/go/auth/oauth2adapt v0.2.4 h1:0GWE/FUsXhf6C+jAkWgYm7X9tK8cuEIfy19DBn6B6bY= cloud.google.com/go/auth/oauth2adapt v0.2.4/go.mod h1:jC/jOpwFP6JBxhB3P5Rr0a9HLMC/Pe3eaL4NmdvqPtc= cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= @@ -28,6 +30,8 @@ cloud.google.com/go/longrunning v0.6.1 h1:lOLTFxYpr8hcRtcwWir5ITh1PAKUD/sG2lKrTS cloud.google.com/go/longrunning v0.6.1/go.mod h1:nHISoOZpBcmlwbJmiVk5oDRz0qG/ZxPynEGs1iZ79s0= cloud.google.com/go/monitoring v1.21.0 h1:EMc0tB+d3lUewT2NzKC/hr8cSR9WsUieVywzIHetGro= cloud.google.com/go/monitoring v1.21.0/go.mod h1:tuJ+KNDdJbetSsbSGTqnaBvbauS5kr3Q/koy3Up6r+4= +cloud.google.com/go/monitoring v1.21.1 h1:zWtbIoBMnU5LP9A/fz8LmWMGHpk4skdfeiaa66QdFGc= +cloud.google.com/go/monitoring v1.21.1/go.mod h1:Rj++LKrlht9uBi8+Eb530dIrzG/cU/lB8mt+lbeFK1c= cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= cloud.google.com/go/secretmanager v1.14.1 h1:xlWSIg8rtBn5qCr2f3XtQP19+5COyf/ll49SEvi/0vM= @@ -1034,6 +1038,8 @@ golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxb golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.6.0 h1:eTDhh4ZXt5Qf0augr54TN6suAUudPcawVZeIAPU7D4U= golang.org/x/time v0.6.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= +golang.org/x/time v0.7.0 h1:ntUhktv3OPE6TgYxXWv9vKvUSJyIFJlyohwbkEwPrKQ= +golang.org/x/time v0.7.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= @@ -1085,6 +1091,8 @@ google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsb google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= google.golang.org/api v0.199.0 h1:aWUXClp+VFJmqE0JPvpZOK3LDQMyFKYIow4etYd9qxs= google.golang.org/api v0.199.0/go.mod h1:ohG4qSztDJmZdjK/Ar6MhbAmb/Rpi4JHOqagsh90K28= +google.golang.org/api v0.200.0 h1:0ytfNWn101is6e9VBoct2wrGDjOi5vn7jw5KtaQgDrU= +google.golang.org/api v0.200.0/go.mod h1:Tc5u9kcbjO7A8SwGlYj4IiVifJU01UqXtEgDMYmBmV8= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= @@ -1107,10 +1115,16 @@ google.golang.org/genproto v0.0.0-20200423170343-7949de9c1215/go.mod h1:55QSHmfG google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= google.golang.org/genproto v0.0.0-20240903143218-8af14fe29dc1 h1:BulPr26Jqjnd4eYDVe+YvyR7Yc2vJGkO5/0UxD0/jZU= google.golang.org/genproto v0.0.0-20240903143218-8af14fe29dc1/go.mod h1:hL97c3SYopEHblzpxRL4lSs523++l8DYxGM1FQiYmb4= +google.golang.org/genproto v0.0.0-20241007155032-5fefd90f89a9 h1:nFS3IivktIU5Mk6KQa+v6RKkHUpdQpphqGNLxqNnbEk= +google.golang.org/genproto v0.0.0-20241007155032-5fefd90f89a9/go.mod h1:tEzYTYZxbmVNOu0OAFH9HzdJtLn6h4Aj89zzlBCdHms= google.golang.org/genproto/googleapis/api v0.0.0-20240903143218-8af14fe29dc1 h1:hjSy6tcFQZ171igDaN5QHOw2n6vx40juYbC/x67CEhc= google.golang.org/genproto/googleapis/api v0.0.0-20240903143218-8af14fe29dc1/go.mod h1:qpvKtACPCQhAdu3PyQgV4l3LMXZEtft7y8QcarRsp9I= +google.golang.org/genproto/googleapis/api v0.0.0-20240930140551-af27646dc61f h1:jTm13A2itBi3La6yTGqn8bVSrc3ZZ1r8ENHlIXBfnRA= +google.golang.org/genproto/googleapis/api v0.0.0-20240930140551-af27646dc61f/go.mod h1:CLGoBuH1VHxAUXVPP8FfPwPEVJB6lz3URE5mY2SuayE= google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1 h1:pPJltXNxVzT4pK9yD8vR9X75DaWYYmLGMsEvBfFQZzQ= google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU= +google.golang.org/genproto/googleapis/rpc v0.0.0-20241007155032-5fefd90f89a9 h1:QCqS/PdaHTSWGvupk2F/ehwHtGc0/GYkT+3GAcR1CCc= +google.golang.org/genproto/googleapis/rpc v0.0.0-20241007155032-5fefd90f89a9/go.mod h1:GX3210XPVPUjJbTUbvwI8f2IpZDMZuPJWDzDuebbviI= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= @@ -1123,6 +1137,8 @@ google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3Iji google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= google.golang.org/grpc v1.67.0 h1:IdH9y6PF5MPSdAntIcpjQ+tXO41pcQsfZV2RxtQgVcw= google.golang.org/grpc v1.67.0/go.mod h1:1gLDyUQU7CTLJI90u3nXZ9ekeghjeM7pTDZlqFNg2AA= +google.golang.org/grpc v1.67.1 h1:zWnc1Vrcno+lHZCOofnIMvycFcc0QRGIzm9dhnDX68E= +google.golang.org/grpc v1.67.1/go.mod h1:1gLDyUQU7CTLJI90u3nXZ9ekeghjeM7pTDZlqFNg2AA= google.golang.org/grpc/stats/opentelemetry v0.0.0-20240907200651-3ffb98b2c93a h1:UIpYSuWdWHSzjwcAFRLjKcPXFZVVLXGEM23W+NWqipw= google.golang.org/grpc/stats/opentelemetry v0.0.0-20240907200651-3ffb98b2c93a/go.mod h1:9i1T9n4ZinTUZGgzENMi8MDDgbGC5mqTS75JAv6xN3A= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= From bc32592066bba3f9ddf4fa0f1da24e7121fa4bca Mon Sep 17 00:00:00 2001 From: Kashif Khan <70996046+kashifkhan0771@users.noreply.github.com> Date: Thu, 10 Oct 2024 17:50:30 +0500 Subject: [PATCH 10/76] Updated Fastly Personal Token Detector (#3386) * Updated verification API and enhanced the code for fastly personal token detector * fixed integration test cases and resolved comments * pass secret to SetVerificationError --- .../fastlypersonaltoken.go | 112 ++++++++----- .../fastlypersonaltoken_integration_test.go | 126 ++++++++++++++ .../fastlypersonaltoken_test.go | 158 ++++++++---------- 3 files changed, 261 insertions(+), 135 deletions(-) create mode 100644 pkg/detectors/fastlypersonaltoken/fastlypersonaltoken_integration_test.go diff --git a/pkg/detectors/fastlypersonaltoken/fastlypersonaltoken.go b/pkg/detectors/fastlypersonaltoken/fastlypersonaltoken.go index 11aaacd2adc7..9b2866195ae3 100644 --- a/pkg/detectors/fastlypersonaltoken/fastlypersonaltoken.go +++ b/pkg/detectors/fastlypersonaltoken/fastlypersonaltoken.go @@ -4,10 +4,10 @@ import ( "context" "encoding/json" "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" @@ -31,60 +31,34 @@ func (s Scanner) Keywords() []string { return []string{"fastly"} } -type fastlyUserRes struct { - Login string `json:"login"` - Name string `json:"name"` - Role string `json:"role"` - TwoFactorAuthEnabled bool `json:"two_factor_auth_enabled"` - Locked bool `json:"locked"` +type token struct { + TokenID string `json:"id"` + UserID string `json:"user_id"` + ExpiresAt string `json:"expires_at"` + Scope string `json:"scope"` } // FromData will find and optionally verify FastlyPersonalToken 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) + var uniqueMatches = make(map[string]struct{}) - for _, match := range matches { - if len(match) != 2 { - continue - } - resMatch := strings.TrimSpace(match[1]) + for _, matches := range keyPat.FindAllStringSubmatch(dataStr, -1) { + uniqueMatches[matches[1]] = struct{}{} + } + for match := range uniqueMatches { s1 := detectors.Result{ DetectorType: detectorspb.DetectorType_FastlyPersonalToken, - Raw: []byte(resMatch), + Raw: []byte(match), } if verify { - req, err := http.NewRequestWithContext(ctx, "GET", "https://api.fastly.com/current_user", nil) - if err != nil { - continue - } - req.Header.Add("Fastly-Key", resMatch) - res, err := client.Do(req) - if err == nil { - bodyBytes, err := io.ReadAll(res.Body) - if err != nil { - continue - } - defer res.Body.Close() - if res.StatusCode >= 200 && res.StatusCode < 300 { - var userRes fastlyUserRes - err = json.Unmarshal(bodyBytes, &userRes) - if err != nil { - continue - } - s1.Verified = true - s1.ExtraData = map[string]string{ - "username": userRes.Login, - "name": userRes.Name, - "role": userRes.Role, - "locked": fmt.Sprintf("%t", userRes.Locked), - "two_factor_auth_enabled": fmt.Sprintf("%t", userRes.TwoFactorAuthEnabled), - } - } - } + extraData, verified, verificationErr := verifyFastlyApiToken(ctx, match) + s1.Verified = verified + s1.ExtraData = extraData + s1.SetVerificationError(verificationErr, match) } results = append(results, s1) @@ -100,3 +74,55 @@ func (s Scanner) Type() detectorspb.DetectorType { func (s Scanner) Description() string { return "Fastly is a content delivery network (CDN) and cloud service provider. Fastly personal tokens can be used to authenticate API requests to Fastly services." } + +func verifyFastlyApiToken(ctx context.Context, apiToken string) (map[string]string, bool, error) { + // api-docs: https://www.fastly.com/documentation/reference/api/auth-tokens/user/ + req, err := http.NewRequestWithContext(ctx, "GET", "https://api.fastly.com/tokens/self", nil) + if err != nil { + return nil, false, err + } + + // add api key in the header + req.Header.Add("Fastly-Key", apiToken) + resp, err := client.Do(req) + if err != nil { + return nil, false, err + } + defer func() { + _, _ = io.Copy(io.Discard, resp.Body) + _ = resp.Body.Close() + }() + + switch resp.StatusCode { + case http.StatusOK: + var self token + if err = json.NewDecoder(resp.Body).Decode(&self); err != nil { + return nil, false, err + } + + // capture token details in the map + extraData := map[string]string{ + // token id is the alphanumeric string uniquely identifying a token + "token_id": self.TokenID, + // user id is the alphanumeric string uniquely identifying the user + "user_id": self.UserID, + // expires at is time-stamp (UTC) of when the token will expire + "token_expires_at": self.ExpiresAt, + // token scope is space-delimited list of authorization scope of the token + "token_scope": self.Scope, + } + + // if expires at is empty which mean token is set to never expire, add 'Never' as the value + if extraData["token_expires_at"] == "" { + extraData["token_expires_at"] = "never" + } + + return extraData, true, nil + case http.StatusUnauthorized, http.StatusForbidden: + // as per fastly documentation: An HTTP 401 response is returned on an expired token. An HTTP 403 response is returned on an invalid access token. + return nil, false, nil + default: + return nil, false, fmt.Errorf("unexpected status code: %d", resp.StatusCode) + + } +} diff --git a/pkg/detectors/fastlypersonaltoken/fastlypersonaltoken_integration_test.go b/pkg/detectors/fastlypersonaltoken/fastlypersonaltoken_integration_test.go new file mode 100644 index 000000000000..20eb25f7ef98 --- /dev/null +++ b/pkg/detectors/fastlypersonaltoken/fastlypersonaltoken_integration_test.go @@ -0,0 +1,126 @@ +//go:build detectors +// +build detectors + +package fastlypersonaltoken + +import ( + "context" + "fmt" + "testing" + "time" + + "github.com/kylelemons/godebug/pretty" + "github.com/trufflesecurity/trufflehog/v3/pkg/detectors" + + "github.com/trufflesecurity/trufflehog/v3/pkg/pb/detectorspb" +) + +func TestFastlyPersonalToken_FromChunk(t *testing.T) { + ctx, cancel := context.WithTimeout(context.Background(), time.Second*5) + defer cancel() + testSecrets, err := common.GetSecret(ctx, "trufflehog-testing", "detectors3") + if err != nil { + t.Fatalf("could not get test secrets from GCP: %s", err) + } + secret := testSecrets.MustGetField("FASTLYPERSONALTOKEN_TOKEN") + inactiveSecret := testSecrets.MustGetField("FASTLYPERSONALTOKEN_INACTIVE") + + type args struct { + ctx context.Context + data []byte + verify bool + } + tests := []struct { + name string + s Scanner + args args + want []detectors.Result + wantErr bool + }{ + { + name: "found, verified", + s: Scanner{}, + args: args{ + ctx: ctx, + data: []byte(fmt.Sprintf("You can find a fastlypersonaltoken secret %s within", secret)), + verify: true, + }, + want: []detectors.Result{ + { + DetectorType: detectorspb.DetectorType_FastlyPersonalToken, + Verified: true, + ExtraData: map[string]string{ + "token_id": "2GUTBVFzHG2zVOMGtEpi9q", + "user_id": "2j1UhHmRhefRMNNrlxcyf5", + "token_expires_at": "never", + "token_scope": "global:read", + }, + }, + }, + wantErr: false, + }, + { + name: "found, unverified", + s: Scanner{}, + args: args{ + ctx: context.Background(), + data: []byte(fmt.Sprintf("You can find a fastlypersonaltoken secret %s within but not valid", inactiveSecret)), // the secret would satisfy the regex but not pass validation + verify: true, + }, + want: []detectors.Result{ + { + DetectorType: detectorspb.DetectorType_FastlyPersonalToken, + Verified: false, + ExtraData: map[string]string{}, + }, + }, + wantErr: false, + }, + { + name: "not found", + s: Scanner{}, + args: args{ + ctx: context.Background(), + data: []byte("You cannot find the secret within"), + verify: true, + }, + want: nil, + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + s := Scanner{} + got, err := s.FromData(tt.args.ctx, tt.args.verify, tt.args.data) + if (err != nil) != tt.wantErr { + t.Errorf("FastlyPersonalToken.FromData() error = %v, wantErr %v", err, tt.wantErr) + return + } + for i := range got { + if len(got[i].Raw) == 0 { + t.Fatalf("no raw secret present: \n %+v", got[i]) + } + got[i].Raw = nil + } + if diff := pretty.Compare(got, tt.want); diff != "" { + t.Errorf("FastlyPersonalToken.FromData() %s diff: (-got +want)\n%s", tt.name, diff) + } + }) + } +} + +func BenchmarkFromData(benchmark *testing.B) { + ctx := context.Background() + s := Scanner{} + for name, data := range detectors.MustGetBenchmarkData() { + benchmark.Run(name, func(b *testing.B) { + b.ResetTimer() + for n := 0; n < b.N; n++ { + _, err := s.FromData(ctx, false, data) + if err != nil { + b.Fatal(err) + } + } + }) + } +} diff --git a/pkg/detectors/fastlypersonaltoken/fastlypersonaltoken_test.go b/pkg/detectors/fastlypersonaltoken/fastlypersonaltoken_test.go index cbf2c5426c62..0d14ddfeccd3 100644 --- a/pkg/detectors/fastlypersonaltoken/fastlypersonaltoken_test.go +++ b/pkg/detectors/fastlypersonaltoken/fastlypersonaltoken_test.go @@ -1,120 +1,94 @@ -//go:build detectors -// +build detectors - package fastlypersonaltoken import ( "context" - "fmt" "testing" - "time" - "github.com/kylelemons/godebug/pretty" + "github.com/google/go-cmp/cmp" + "github.com/trufflesecurity/trufflehog/v3/pkg/detectors" + "github.com/trufflesecurity/trufflehog/v3/pkg/engine/ahocorasick" +) - "github.com/trufflesecurity/trufflehog/v3/pkg/common" - "github.com/trufflesecurity/trufflehog/v3/pkg/pb/detectorspb" +var ( + // example picked from: https://github.com/ryan-miller/learn-go-with-tests/blob/181467c9e512f7e68d3f3cbcea89f0050982416c/fastly/users.go#L22 + validPattern = ` + // headers and header values + const fastlyKeyToken string = "Fastly-Key" + const fastlyKey string = "TVAWji0p7uDI6OP9DyWvmV-vgoUoXIuf" + const contentTypeToken string = "Content-Type" + const appJsonContentType = "application/json"` + + validPatternToken = "TVAWji0p7uDI6OP9DyWvmV-vgoUoXIuf" + + invalidPattern = ` + // headers and header values + const fastlyKeyToken string = "Fastly-Key" + const fastlyKey string = "$FASTLY_KEY" + const contentTypeToken string = "Content-Type" + const appJsonContentType = "application/json"` ) -func TestFastlyPersonalToken_FromChunk(t *testing.T) { - ctx, cancel := context.WithTimeout(context.Background(), time.Second*5) - defer cancel() - testSecrets, err := common.GetSecret(ctx, "trufflehog-testing", "detectors3") - if err != nil { - t.Fatalf("could not get test secrets from GCP: %s", err) - } - secret := testSecrets.MustGetField("FASTLYPERSONALTOKEN_TOKEN") - inactiveSecret := testSecrets.MustGetField("FASTLYPERSONALTOKEN_INACTIVE") +func TestFastlyPersonalToken_Pattern(t *testing.T) { + d := Scanner{} + ahoCorasickCore := ahocorasick.NewAhoCorasickCore([]detectors.Detector{d}) - type args struct { - ctx context.Context - data []byte - verify bool - } tests := []struct { - name string - s Scanner - args args - want []detectors.Result - wantErr bool + name string + input string + want []string }{ { - name: "found, verified", - s: Scanner{}, - args: args{ - ctx: context.Background(), - data: []byte(fmt.Sprintf("You can find a fastlypersonaltoken secret %s within", secret)), - verify: true, - }, - want: []detectors.Result{ - { - DetectorType: detectorspb.DetectorType_FastlyPersonalToken, - Verified: true, - }, - }, - wantErr: false, - }, - { - name: "found, unverified", - s: Scanner{}, - args: args{ - ctx: context.Background(), - data: []byte(fmt.Sprintf("You can find a fastlypersonaltoken secret %s within but not valid", inactiveSecret)), // the secret would satisfy the regex but not pass validation - verify: true, - }, - want: []detectors.Result{ - { - DetectorType: detectorspb.DetectorType_FastlyPersonalToken, - Verified: false, - }, - }, - wantErr: false, + name: "valid pattern", + input: validPattern, + want: []string{validPatternToken}, }, { - name: "not found", - s: Scanner{}, - args: args{ - ctx: context.Background(), - data: []byte("You cannot find the secret within"), - verify: true, - }, - want: nil, - wantErr: false, + name: "invalid pattern", + input: invalidPattern, + want: nil, }, } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - s := Scanner{} - got, err := s.FromData(tt.args.ctx, tt.args.verify, tt.args.data) - if (err != nil) != tt.wantErr { - t.Errorf("FastlyPersonalToken.FromData() error = %v, wantErr %v", err, tt.wantErr) + + 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 } - for i := range got { - if len(got[i].Raw) == 0 { - t.Fatalf("no raw secret present: \n %+v", got[i]) - } - got[i].Raw = nil + + results, err := d.FromData(context.Background(), false, []byte(test.input)) + if err != nil { + t.Errorf("error = %v", err) + return } - if diff := pretty.Compare(got, tt.want); diff != "" { - t.Errorf("FastlyPersonalToken.FromData() %s diff: (-got +want)\n%s", tt.name, diff) + + 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 } - }) - } -} -func BenchmarkFromData(benchmark *testing.B) { - ctx := context.Background() - s := Scanner{} - for name, data := range detectors.MustGetBenchmarkData() { - benchmark.Run(name, func(b *testing.B) { - b.ResetTimer() - for n := 0; n < b.N; n++ { - _, err := s.FromData(ctx, false, data) - if err != nil { - b.Fatal(err) + 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) + } }) } } From e57c712998694db42e0e4b788aa703f3a60492ea Mon Sep 17 00:00:00 2001 From: ahrav Date: Thu, 10 Oct 2024 06:16:40 -0700 Subject: [PATCH 11/76] Manually upgrade github dep (#3387) --- go.mod | 2 +- go.sum | 2 ++ pkg/analyzer/analyzers/github/classic/classictoken.go | 2 +- pkg/analyzer/analyzers/github/common/github.go | 2 +- pkg/analyzer/analyzers/github/finegrained/finegrained.go | 2 +- .../analyzers/github/finegrained/finegrained_test.go | 2 +- pkg/analyzer/analyzers/github/github.go | 2 +- pkg/sources/git/git.go | 2 +- pkg/sources/github/connector.go | 3 ++- pkg/sources/github/connector_app.go | 2 +- pkg/sources/github/connector_basicauth.go | 2 +- pkg/sources/github/connector_token.go | 2 +- pkg/sources/github/connector_unauthenticated.go | 3 ++- pkg/sources/github/github.go | 2 +- pkg/sources/github/github_test.go | 2 +- pkg/sources/github/repo.go | 2 +- pkg/sources/github_experimental/github_experimental.go | 2 +- pkg/sources/github_experimental/object_discovery.go | 5 +++-- pkg/sources/github_experimental/repo.go | 2 +- 19 files changed, 24 insertions(+), 19 deletions(-) diff --git a/go.mod b/go.mod index dcb8d22faaf4..aa0842bb8e7c 100644 --- a/go.mod +++ b/go.mod @@ -54,7 +54,7 @@ require ( github.com/golang-jwt/jwt/v4 v4.5.0 github.com/google/go-cmp v0.6.0 github.com/google/go-containerregistry v0.20.2 - github.com/google/go-github/v63 v63.0.0 + github.com/google/go-github/v66 v66.0.0 github.com/google/uuid v1.6.0 github.com/googleapis/gax-go/v2 v2.13.0 github.com/hashicorp/go-retryablehttp v0.7.7 diff --git a/go.sum b/go.sum index 7d2f0f2eb29f..6a68ae969777 100644 --- a/go.sum +++ b/go.sum @@ -418,6 +418,8 @@ github.com/google/go-github/v62 v62.0.0 h1:/6mGCaRywZz9MuHyw9gD1CwsbmBX8GWsbFkwM github.com/google/go-github/v62 v62.0.0/go.mod h1:EMxeUqGJq2xRu9DYBMwel/mr7kZrzUOfQmmpYrZn2a4= github.com/google/go-github/v63 v63.0.0 h1:13xwK/wk9alSokujB9lJkuzdmQuVn2QCPeck76wR3nE= github.com/google/go-github/v63 v63.0.0/go.mod h1:IqbcrgUmIcEaioWrGYei/09o+ge5vhffGOcxrO0AfmA= +github.com/google/go-github/v66 v66.0.0 h1:ADJsaXj9UotwdgK8/iFZtv7MLc8E8WBl62WLd/D/9+M= +github.com/google/go-github/v66 v66.0.0/go.mod h1:+4SO9Zkuyf8ytMj0csN1NR/5OTR+MfqPp8P8dVlcvY4= github.com/google/go-querystring v0.0.0-20170111101155-53e6ce116135/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8= github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU= diff --git a/pkg/analyzer/analyzers/github/classic/classictoken.go b/pkg/analyzer/analyzers/github/classic/classictoken.go index 49dfb98a08b0..fb9a3fbefc49 100644 --- a/pkg/analyzer/analyzers/github/classic/classictoken.go +++ b/pkg/analyzer/analyzers/github/classic/classictoken.go @@ -8,7 +8,7 @@ import ( "strings" "github.com/fatih/color" - gh "github.com/google/go-github/v63/github" + gh "github.com/google/go-github/v66/github" "github.com/jedib0t/go-pretty/v6/table" "github.com/trufflesecurity/trufflehog/v3/pkg/analyzer/analyzers" diff --git a/pkg/analyzer/analyzers/github/common/github.go b/pkg/analyzer/analyzers/github/common/github.go index 298e921b7850..f77767f05b45 100644 --- a/pkg/analyzer/analyzers/github/common/github.go +++ b/pkg/analyzer/analyzers/github/common/github.go @@ -8,7 +8,7 @@ import ( "time" "github.com/fatih/color" - gh "github.com/google/go-github/v63/github" + gh "github.com/google/go-github/v66/github" "github.com/jedib0t/go-pretty/table" "github.com/trufflesecurity/trufflehog/v3/pkg/analyzer/analyzers" diff --git a/pkg/analyzer/analyzers/github/finegrained/finegrained.go b/pkg/analyzer/analyzers/github/finegrained/finegrained.go index 20b46cf39b6a..fd2ee2d62f7e 100644 --- a/pkg/analyzer/analyzers/github/finegrained/finegrained.go +++ b/pkg/analyzer/analyzers/github/finegrained/finegrained.go @@ -11,7 +11,7 @@ import ( "strings" "github.com/fatih/color" - gh "github.com/google/go-github/v63/github" + gh "github.com/google/go-github/v66/github" "github.com/jedib0t/go-pretty/v6/table" "github.com/trufflesecurity/trufflehog/v3/pkg/analyzer/analyzers/github/common" diff --git a/pkg/analyzer/analyzers/github/finegrained/finegrained_test.go b/pkg/analyzer/analyzers/github/finegrained/finegrained_test.go index 2e2decc8af7a..42b4b18392bd 100644 --- a/pkg/analyzer/analyzers/github/finegrained/finegrained_test.go +++ b/pkg/analyzer/analyzers/github/finegrained/finegrained_test.go @@ -4,7 +4,7 @@ import ( "testing" "time" - gh "github.com/google/go-github/v63/github" + gh "github.com/google/go-github/v66/github" "github.com/trufflesecurity/trufflehog/v3/pkg/analyzer/analyzers" analyzerCommon "github.com/trufflesecurity/trufflehog/v3/pkg/analyzer/analyzers/github/common" diff --git a/pkg/analyzer/analyzers/github/github.go b/pkg/analyzer/analyzers/github/github.go index 08dbf5842017..d8b3e9c3d8aa 100644 --- a/pkg/analyzer/analyzers/github/github.go +++ b/pkg/analyzer/analyzers/github/github.go @@ -6,7 +6,7 @@ import ( "time" "github.com/fatih/color" - gh "github.com/google/go-github/v63/github" + gh "github.com/google/go-github/v66/github" "github.com/trufflesecurity/trufflehog/v3/pkg/analyzer/analyzers" "github.com/trufflesecurity/trufflehog/v3/pkg/analyzer/analyzers/github/classic" diff --git a/pkg/sources/git/git.go b/pkg/sources/git/git.go index d9992dadecfd..ca6f82f967b6 100644 --- a/pkg/sources/git/git.go +++ b/pkg/sources/git/git.go @@ -19,7 +19,7 @@ import ( "github.com/go-git/go-git/v5" "github.com/go-git/go-git/v5/plumbing" "github.com/go-git/go-git/v5/plumbing/object" - "github.com/google/go-github/v63/github" + "github.com/google/go-github/v66/github" "golang.org/x/oauth2" "golang.org/x/sync/semaphore" "google.golang.org/protobuf/proto" diff --git a/pkg/sources/github/connector.go b/pkg/sources/github/connector.go index 707c2fa7f062..215e16dfb988 100644 --- a/pkg/sources/github/connector.go +++ b/pkg/sources/github/connector.go @@ -4,7 +4,8 @@ import ( "fmt" gogit "github.com/go-git/go-git/v5" - "github.com/google/go-github/v63/github" + "github.com/google/go-github/v66/github" + "github.com/trufflesecurity/trufflehog/v3/pkg/context" "github.com/trufflesecurity/trufflehog/v3/pkg/pb/sourcespb" ) diff --git a/pkg/sources/github/connector_app.go b/pkg/sources/github/connector_app.go index 925c7748fce9..7b9b46280b62 100644 --- a/pkg/sources/github/connector_app.go +++ b/pkg/sources/github/connector_app.go @@ -6,7 +6,7 @@ import ( "github.com/bradleyfalzon/ghinstallation/v2" gogit "github.com/go-git/go-git/v5" - "github.com/google/go-github/v63/github" + "github.com/google/go-github/v66/github" "github.com/trufflesecurity/trufflehog/v3/pkg/common" "github.com/trufflesecurity/trufflehog/v3/pkg/context" "github.com/trufflesecurity/trufflehog/v3/pkg/pb/credentialspb" diff --git a/pkg/sources/github/connector_basicauth.go b/pkg/sources/github/connector_basicauth.go index eda81fa02753..ced74668f6b7 100644 --- a/pkg/sources/github/connector_basicauth.go +++ b/pkg/sources/github/connector_basicauth.go @@ -4,7 +4,7 @@ import ( "fmt" gogit "github.com/go-git/go-git/v5" - "github.com/google/go-github/v63/github" + "github.com/google/go-github/v66/github" "github.com/trufflesecurity/trufflehog/v3/pkg/common" "github.com/trufflesecurity/trufflehog/v3/pkg/context" "github.com/trufflesecurity/trufflehog/v3/pkg/pb/credentialspb" diff --git a/pkg/sources/github/connector_token.go b/pkg/sources/github/connector_token.go index f45ad9ca1233..d69221f7ed59 100644 --- a/pkg/sources/github/connector_token.go +++ b/pkg/sources/github/connector_token.go @@ -6,7 +6,7 @@ import ( "sync" gogit "github.com/go-git/go-git/v5" - "github.com/google/go-github/v63/github" + "github.com/google/go-github/v66/github" "github.com/trufflesecurity/trufflehog/v3/pkg/common" "github.com/trufflesecurity/trufflehog/v3/pkg/context" "github.com/trufflesecurity/trufflehog/v3/pkg/sources/git" diff --git a/pkg/sources/github/connector_unauthenticated.go b/pkg/sources/github/connector_unauthenticated.go index fb2b867154fa..ecc70a7a2065 100644 --- a/pkg/sources/github/connector_unauthenticated.go +++ b/pkg/sources/github/connector_unauthenticated.go @@ -4,7 +4,8 @@ import ( "fmt" gogit "github.com/go-git/go-git/v5" - "github.com/google/go-github/v63/github" + "github.com/google/go-github/v66/github" + "github.com/trufflesecurity/trufflehog/v3/pkg/common" "github.com/trufflesecurity/trufflehog/v3/pkg/context" "github.com/trufflesecurity/trufflehog/v3/pkg/sources/git" diff --git a/pkg/sources/github/github.go b/pkg/sources/github/github.go index e3e492bba359..b5d3ef90e487 100644 --- a/pkg/sources/github/github.go +++ b/pkg/sources/github/github.go @@ -14,7 +14,7 @@ import ( "time" "github.com/gobwas/glob" - "github.com/google/go-github/v63/github" + "github.com/google/go-github/v66/github" "golang.org/x/exp/rand" "golang.org/x/sync/errgroup" "google.golang.org/protobuf/proto" diff --git a/pkg/sources/github/github_test.go b/pkg/sources/github/github_test.go index edef61bb0873..2965bbf5cb3b 100644 --- a/pkg/sources/github/github_test.go +++ b/pkg/sources/github/github_test.go @@ -17,7 +17,7 @@ import ( "time" "github.com/google/go-cmp/cmp" - "github.com/google/go-github/v63/github" + "github.com/google/go-github/v66/github" "github.com/stretchr/testify/assert" "golang.org/x/sync/errgroup" "google.golang.org/protobuf/types/known/anypb" diff --git a/pkg/sources/github/repo.go b/pkg/sources/github/repo.go index 1f01291ea31f..3e23f64d4f46 100644 --- a/pkg/sources/github/repo.go +++ b/pkg/sources/github/repo.go @@ -9,7 +9,7 @@ import ( "sync" gogit "github.com/go-git/go-git/v5" - "github.com/google/go-github/v63/github" + "github.com/google/go-github/v66/github" "github.com/trufflesecurity/trufflehog/v3/pkg/context" "github.com/trufflesecurity/trufflehog/v3/pkg/giturl" diff --git a/pkg/sources/github_experimental/github_experimental.go b/pkg/sources/github_experimental/github_experimental.go index fecf5c273dd2..115a0a70b9e0 100644 --- a/pkg/sources/github_experimental/github_experimental.go +++ b/pkg/sources/github_experimental/github_experimental.go @@ -6,7 +6,7 @@ import ( "strings" "github.com/go-logr/logr" - "github.com/google/go-github/v63/github" + "github.com/google/go-github/v66/github" "google.golang.org/protobuf/proto" "google.golang.org/protobuf/types/known/anypb" diff --git a/pkg/sources/github_experimental/object_discovery.go b/pkg/sources/github_experimental/object_discovery.go index 10ef15e00c1e..db2c72ad6fa4 100644 --- a/pkg/sources/github_experimental/object_discovery.go +++ b/pkg/sources/github_experimental/object_discovery.go @@ -11,13 +11,14 @@ import ( "strings" "time" - "github.com/google/go-github/v63/github" + "github.com/google/go-github/v66/github" "github.com/k0kubun/go-ansi" "github.com/schollz/progressbar/v3" + "golang.org/x/oauth2" + "github.com/trufflesecurity/trufflehog/v3/pkg/context" "github.com/trufflesecurity/trufflehog/v3/pkg/sources" "github.com/trufflesecurity/trufflehog/v3/pkg/sources/git" - "golang.org/x/oauth2" ) // Assumption: sleeping for 60 seconds is enough to reset the secondary rate limit diff --git a/pkg/sources/github_experimental/repo.go b/pkg/sources/github_experimental/repo.go index bbe87ef38227..73d36f3d9c54 100644 --- a/pkg/sources/github_experimental/repo.go +++ b/pkg/sources/github_experimental/repo.go @@ -5,7 +5,7 @@ import ( "strings" "sync" - "github.com/google/go-github/v63/github" + "github.com/google/go-github/v66/github" "github.com/trufflesecurity/trufflehog/v3/pkg/giturl" "github.com/trufflesecurity/trufflehog/v3/pkg/pb/source_metadatapb" From 05015b38f6cbe71d18ec4c8d5eed12752e432775 Mon Sep 17 00:00:00 2001 From: Richard Gomez <32133502+rgmz@users.noreply.github.com> Date: Thu, 10 Oct 2024 09:47:40 -0400 Subject: [PATCH 12/76] Separate detector tests into unit/integration (#3274) * test: split unit and integration tests * test: split railway unit/integration * test(alchemy): add new case --- .../alchemy/alchemy_integration_test.go | 161 ++++++++++++++ pkg/detectors/alchemy/alchemy_test.go | 166 +------------- .../v1/atlassian_integration_test.go | 161 ++++++++++++++ pkg/detectors/atlassian/v1/atlassian_test.go | 155 +------------ .../v2/atlassian_integration_test.go | 161 ++++++++++++++ pkg/detectors/atlassian/v2/atlassian_test.go | 155 +------------ .../coinbase_waas_integration_test.go | 174 +++++++++++++++ .../coinbase_waas/coinbase_waas_test.go | 168 -------------- .../deno/denodeploy_integration_test.go | 162 ++++++++++++++ pkg/detectors/deno/denodeploy_test.go | 156 ------------- .../v1/elevenlabs_integration_test.go | 27 +++ .../elevenlabs/v1/elevenlabs_test.go | 19 -- .../v2/elevenlabs_integration_test.go | 175 +++++++++++++++ .../elevenlabs/v2/elevenlabs_test.go | 169 +------------- .../endorlabs/endorlabs_integration_test.go | 182 +++++++++++++++ pkg/detectors/endorlabs/endorlabs_test.go | 176 +-------------- .../eraser/eraser_integration_test.go | 161 ++++++++++++++ pkg/detectors/eraser/eraser_test.go | 155 +------------ ...tiondefaultcredentials_integration_test.go | 161 ++++++++++++++ .../gcpapplicationdefaultcredentials_test.go | 159 +------------- pkg/detectors/groq/groq_integration_test.go | 161 ++++++++++++++ pkg/detectors/groq/groq_test.go | 155 +------------ .../intra42/intra42_integration_test.go | 159 ++++++++++++++ pkg/detectors/intra42/intra42_test.go | 153 +------------ .../larksuite/larksuite_integration_test.go | 139 ++++++++++++ pkg/detectors/larksuite/larksuite_test.go | 134 +----------- .../larksuiteapikey_integration_test.go | 126 +++++++++++ .../larksuiteapikey/larksuiteapikey_test.go | 121 +--------- ....go => maxmindlicense_integration_test.go} | 0 .../v2/maxmindlicense_v2_integration_test.go | 128 +++++++++++ .../v2/maxmindlicense_v2_test.go | 124 +---------- .../onfleet/onfleet_integration_test.go | 161 ++++++++++++++ pkg/detectors/onfleet/onfleet_test.go | 155 +------------ .../openai/openai_integration_test.go | 126 +++++++++++ pkg/detectors/openai/openai_test.go | 121 +--------- .../pagarme/pagarme_integration_test.go | 161 ++++++++++++++ pkg/detectors/pagarme/pagarme_test.go | 155 +------------ .../parseur/parseur_integration_test.go | 121 ++++++++++ pkg/detectors/parseur/parseur_test.go | 112 ---------- .../railwayapp/railwayapp_integration_test.go | 173 +++++++++++++++ pkg/detectors/railwayapp/railwayapp_test.go | 167 +------------- .../robinhoodcrypto_integration_test.go | 207 ++++++++++++++++++ .../robinhoodcrypto/robinhoodcrypto_test.go | 201 +---------------- .../signable/signable_integration_test.go | 121 ++++++++++ pkg/detectors/signable/signable_test.go | 115 ---------- .../snykkey/snykkey_integration_test.go | 125 +++++++++++ pkg/detectors/snykkey/snykkey_test.go | 121 +--------- .../voiceflow/voiceflow_integration_test.go | 162 ++++++++++++++ pkg/detectors/voiceflow/voiceflow_test.go | 156 ------------- pkg/detectors/wiz/wiz_integration_test.go | 161 ++++++++++++++ pkg/detectors/wiz/wiz_test.go | 155 +------------ 51 files changed, 3786 insertions(+), 3593 deletions(-) create mode 100644 pkg/detectors/alchemy/alchemy_integration_test.go create mode 100644 pkg/detectors/atlassian/v1/atlassian_integration_test.go create mode 100644 pkg/detectors/atlassian/v2/atlassian_integration_test.go create mode 100644 pkg/detectors/coinbase_waas/coinbase_waas_integration_test.go create mode 100644 pkg/detectors/deno/denodeploy_integration_test.go create mode 100644 pkg/detectors/elevenlabs/v1/elevenlabs_integration_test.go create mode 100644 pkg/detectors/elevenlabs/v2/elevenlabs_integration_test.go create mode 100644 pkg/detectors/endorlabs/endorlabs_integration_test.go create mode 100644 pkg/detectors/eraser/eraser_integration_test.go create mode 100644 pkg/detectors/gcpapplicationdefaultcredentials/gcpapplicationdefaultcredentials_integration_test.go create mode 100644 pkg/detectors/groq/groq_integration_test.go create mode 100644 pkg/detectors/intra42/intra42_integration_test.go create mode 100644 pkg/detectors/larksuite/larksuite_integration_test.go create mode 100644 pkg/detectors/larksuiteapikey/larksuiteapikey_integration_test.go rename pkg/detectors/maxmindlicense/v1/{maxmindlicense_test.go => maxmindlicense_integration_test.go} (100%) create mode 100644 pkg/detectors/maxmindlicense/v2/maxmindlicense_v2_integration_test.go create mode 100644 pkg/detectors/onfleet/onfleet_integration_test.go create mode 100644 pkg/detectors/openai/openai_integration_test.go create mode 100644 pkg/detectors/pagarme/pagarme_integration_test.go create mode 100644 pkg/detectors/parseur/parseur_integration_test.go create mode 100644 pkg/detectors/railwayapp/railwayapp_integration_test.go create mode 100644 pkg/detectors/robinhoodcrypto/robinhoodcrypto_integration_test.go create mode 100644 pkg/detectors/signable/signable_integration_test.go create mode 100644 pkg/detectors/snykkey/snykkey_integration_test.go create mode 100644 pkg/detectors/voiceflow/voiceflow_integration_test.go create mode 100644 pkg/detectors/wiz/wiz_integration_test.go diff --git a/pkg/detectors/alchemy/alchemy_integration_test.go b/pkg/detectors/alchemy/alchemy_integration_test.go new file mode 100644 index 000000000000..036e0a39d579 --- /dev/null +++ b/pkg/detectors/alchemy/alchemy_integration_test.go @@ -0,0 +1,161 @@ +//go:build detectors +// +build detectors + +package alchemy + +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 TestAlchemy_FromChunk(t *testing.T) { + ctx, cancel := context.WithTimeout(context.Background(), time.Second*5) + defer cancel() + testSecrets, err := common.GetSecret(ctx, "trufflehog-testing", "detectors5") + if err != nil { + t.Fatalf("could not get test secrets from GCP: %s", err) + } + secret := testSecrets.MustGetField("ALCHEMY") + inactiveSecret := testSecrets.MustGetField("ALCHEMY_INACTIVE") + + 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", + s: Scanner{}, + args: args{ + ctx: context.Background(), + data: []byte(fmt.Sprintf("You can find a alchemy secret %s within", secret)), + verify: true, + }, + want: []detectors.Result{ + { + DetectorType: detectorspb.DetectorType_Alchemy, + Verified: true, + }, + }, + wantErr: false, + wantVerificationErr: false, + }, + { + name: "found, unverified", + s: Scanner{}, + args: args{ + ctx: context.Background(), + data: []byte(fmt.Sprintf("You can find a alchemy secret %s within but not valid", inactiveSecret)), // the secret would satisfy the regex but not pass validation + verify: true, + }, + want: []detectors.Result{ + { + DetectorType: detectorspb.DetectorType_Alchemy, + Verified: false, + }, + }, + wantErr: false, + wantVerificationErr: false, + }, + { + name: "not found", + s: Scanner{}, + args: args{ + ctx: context.Background(), + data: []byte("You cannot find the secret within"), + verify: true, + }, + want: nil, + wantErr: false, + wantVerificationErr: false, + }, + { + name: "found, would be verified if not for timeout", + s: Scanner{client: common.SaneHttpClientTimeOut(1 * time.Microsecond)}, + args: args{ + ctx: context.Background(), + data: []byte(fmt.Sprintf("You can find a alchemy secret %s within", secret)), + verify: true, + }, + want: []detectors.Result{ + { + DetectorType: detectorspb.DetectorType_Alchemy, + Verified: false, + }, + }, + wantErr: false, + wantVerificationErr: true, + }, + { + name: "found, verified but unexpected api surface", + s: Scanner{client: common.ConstantResponseHttpClient(404, "")}, + args: args{ + ctx: context.Background(), + data: []byte(fmt.Sprintf("You can find a alchemy secret %s within", secret)), + verify: true, + }, + want: []detectors.Result{ + { + DetectorType: detectorspb.DetectorType_Alchemy, + Verified: false, + }, + }, + wantErr: false, + wantVerificationErr: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := tt.s.FromData(tt.args.ctx, tt.args.verify, tt.args.data) + if (err != nil) != tt.wantErr { + t.Errorf("Alchemy.FromData() error = %v, wantErr %v", err, tt.wantErr) + return + } + 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.Fatalf("wantVerificationError = %v, verification error = %v", tt.wantVerificationErr, got[i].VerificationError()) + } + } + ignoreOpts := cmpopts.IgnoreFields(detectors.Result{}, "Raw", "verificationError") + if diff := cmp.Diff(got, tt.want, ignoreOpts); diff != "" { + t.Errorf("Alchemy.FromData() %s diff: (-got +want)\n%s", tt.name, diff) + } + }) + } +} + +func BenchmarkFromData(benchmark *testing.B) { + ctx := context.Background() + s := Scanner{} + for name, data := range detectors.MustGetBenchmarkData() { + benchmark.Run(name, func(b *testing.B) { + b.ResetTimer() + for n := 0; n < b.N; n++ { + _, err := s.FromData(ctx, false, data) + if err != nil { + b.Fatal(err) + } + } + }) + } +} diff --git a/pkg/detectors/alchemy/alchemy_test.go b/pkg/detectors/alchemy/alchemy_test.go index cd655da7d8d5..83af610b3f4e 100644 --- a/pkg/detectors/alchemy/alchemy_test.go +++ b/pkg/detectors/alchemy/alchemy_test.go @@ -1,21 +1,11 @@ -//go:build detectors -// +build detectors - package alchemy 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/engine/ahocorasick" - "github.com/trufflesecurity/trufflehog/v3/pkg/pb/detectorspb" + "testing" ) func TestAlchemy_Pattern(t *testing.T) { @@ -31,6 +21,17 @@ func TestAlchemy_Pattern(t *testing.T) { input: "alchemy_token = '3aBcDFE5678901234567890_1a2b3c4d'", want: []string{"3aBcDFE5678901234567890_1a2b3c4d"}, }, + { + name: "finds all matches", + input: `alchemy_token1 = '3aBcDFE5678901234567890_1a2b3c4d' +alchemy_token2 = '3aDcDFE56789012245678a0_1a2b3c2d'`, + want: []string{"3aBcDFE5678901234567890_1a2b3c4d", "3aDcDFE56789012245678a0_1a2b3c2d"}, + }, + { + name: "invald pattern", + input: "alchemy_token = '1a2b3c4d'", + want: []string{}, + }, } for _, test := range tests { @@ -75,146 +76,3 @@ func TestAlchemy_Pattern(t *testing.T) { }) } } - -func TestAlchemy_FromChunk(t *testing.T) { - ctx, cancel := context.WithTimeout(context.Background(), time.Second*5) - defer cancel() - testSecrets, err := common.GetSecret(ctx, "trufflehog-testing", "detectors5") - if err != nil { - t.Fatalf("could not get test secrets from GCP: %s", err) - } - secret := testSecrets.MustGetField("ALCHEMY") - inactiveSecret := testSecrets.MustGetField("ALCHEMY_INACTIVE") - - 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", - s: Scanner{}, - args: args{ - ctx: context.Background(), - data: []byte(fmt.Sprintf("You can find a alchemy secret %s within", secret)), - verify: true, - }, - want: []detectors.Result{ - { - DetectorType: detectorspb.DetectorType_Alchemy, - Verified: true, - }, - }, - wantErr: false, - wantVerificationErr: false, - }, - { - name: "found, unverified", - s: Scanner{}, - args: args{ - ctx: context.Background(), - data: []byte(fmt.Sprintf("You can find a alchemy secret %s within but not valid", inactiveSecret)), // the secret would satisfy the regex but not pass validation - verify: true, - }, - want: []detectors.Result{ - { - DetectorType: detectorspb.DetectorType_Alchemy, - Verified: false, - }, - }, - wantErr: false, - wantVerificationErr: false, - }, - { - name: "not found", - s: Scanner{}, - args: args{ - ctx: context.Background(), - data: []byte("You cannot find the secret within"), - verify: true, - }, - want: nil, - wantErr: false, - wantVerificationErr: false, - }, - { - name: "found, would be verified if not for timeout", - s: Scanner{client: common.SaneHttpClientTimeOut(1 * time.Microsecond)}, - args: args{ - ctx: context.Background(), - data: []byte(fmt.Sprintf("You can find a alchemy secret %s within", secret)), - verify: true, - }, - want: []detectors.Result{ - { - DetectorType: detectorspb.DetectorType_Alchemy, - Verified: false, - }, - }, - wantErr: false, - wantVerificationErr: true, - }, - { - name: "found, verified but unexpected api surface", - s: Scanner{client: common.ConstantResponseHttpClient(404, "")}, - args: args{ - ctx: context.Background(), - data: []byte(fmt.Sprintf("You can find a alchemy secret %s within", secret)), - verify: true, - }, - want: []detectors.Result{ - { - DetectorType: detectorspb.DetectorType_Alchemy, - Verified: false, - }, - }, - wantErr: false, - wantVerificationErr: true, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - got, err := tt.s.FromData(tt.args.ctx, tt.args.verify, tt.args.data) - if (err != nil) != tt.wantErr { - t.Errorf("Alchemy.FromData() error = %v, wantErr %v", err, tt.wantErr) - return - } - 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.Fatalf("wantVerificationError = %v, verification error = %v", tt.wantVerificationErr, got[i].VerificationError()) - } - } - ignoreOpts := cmpopts.IgnoreFields(detectors.Result{}, "Raw", "verificationError") - if diff := cmp.Diff(got, tt.want, ignoreOpts); diff != "" { - t.Errorf("Alchemy.FromData() %s diff: (-got +want)\n%s", tt.name, diff) - } - }) - } -} - -func BenchmarkFromData(benchmark *testing.B) { - ctx := context.Background() - s := Scanner{} - for name, data := range detectors.MustGetBenchmarkData() { - benchmark.Run(name, func(b *testing.B) { - b.ResetTimer() - for n := 0; n < b.N; n++ { - _, err := s.FromData(ctx, false, data) - if err != nil { - b.Fatal(err) - } - } - }) - } -} diff --git a/pkg/detectors/atlassian/v1/atlassian_integration_test.go b/pkg/detectors/atlassian/v1/atlassian_integration_test.go new file mode 100644 index 000000000000..4d5633928b7d --- /dev/null +++ b/pkg/detectors/atlassian/v1/atlassian_integration_test.go @@ -0,0 +1,161 @@ +//go:build detectors +// +build detectors + +package atlassian + +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 TestAtlassian_FromChunk(t *testing.T) { + ctx, cancel := context.WithTimeout(context.Background(), time.Second*5) + defer cancel() + testSecrets, err := common.GetSecret(ctx, "trufflehog-testing", "detectors5") + if err != nil { + t.Fatalf("could not get test secrets from GCP: %s", err) + } + secret := testSecrets.MustGetField("ATLASSIAN") + inactiveSecret := testSecrets.MustGetField("ATLASSIAN_INACTIVE") + + 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", + s: Scanner{}, + args: args{ + ctx: context.Background(), + data: []byte(fmt.Sprintf("You can find a atlassian secret %s within", secret)), + verify: true, + }, + want: []detectors.Result{ + { + DetectorType: detectorspb.DetectorType_Atlassian, + Verified: true, + }, + }, + wantErr: false, + wantVerificationErr: false, + }, + { + name: "found, unverified", + s: Scanner{}, + args: args{ + ctx: context.Background(), + data: []byte(fmt.Sprintf("You can find a atlassian secret %s within but not valid", inactiveSecret)), // the secret would satisfy the regex but not pass validation + verify: true, + }, + want: []detectors.Result{ + { + DetectorType: detectorspb.DetectorType_Atlassian, + Verified: false, + }, + }, + wantErr: false, + wantVerificationErr: false, + }, + { + name: "not found", + s: Scanner{}, + args: args{ + ctx: context.Background(), + data: []byte("You cannot find the secret within"), + verify: true, + }, + want: nil, + wantErr: false, + wantVerificationErr: false, + }, + { + name: "found, would be verified if not for timeout", + s: Scanner{client: common.SaneHttpClientTimeOut(1 * time.Microsecond)}, + args: args{ + ctx: context.Background(), + data: []byte(fmt.Sprintf("You can find a atlassian secret %s within", secret)), + verify: true, + }, + want: []detectors.Result{ + { + DetectorType: detectorspb.DetectorType_Atlassian, + Verified: false, + }, + }, + wantErr: false, + wantVerificationErr: true, + }, + { + name: "found, verified but unexpected api surface", + s: Scanner{client: common.ConstantResponseHttpClient(404, "")}, + args: args{ + ctx: context.Background(), + data: []byte(fmt.Sprintf("You can find a atlassian secret %s within", secret)), + verify: true, + }, + want: []detectors.Result{ + { + DetectorType: detectorspb.DetectorType_Atlassian, + Verified: false, + }, + }, + wantErr: false, + wantVerificationErr: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := tt.s.FromData(tt.args.ctx, tt.args.verify, tt.args.data) + if (err != nil) != tt.wantErr { + t.Errorf("Atlassian.FromData() error = %v, wantErr %v", err, tt.wantErr) + return + } + 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.Fatalf("wantVerificationError = %v, verification error = %v", tt.wantVerificationErr, got[i].VerificationError()) + } + } + ignoreOpts := cmpopts.IgnoreFields(detectors.Result{}, "Raw", "verificationError", "ExtraData") + if diff := cmp.Diff(got, tt.want, ignoreOpts); diff != "" { + t.Errorf("Atlassian.FromData() %s diff: (-got +want)\n%s", tt.name, diff) + } + }) + } +} + +func BenchmarkFromData(benchmark *testing.B) { + ctx := context.Background() + s := Scanner{} + for name, data := range detectors.MustGetBenchmarkData() { + benchmark.Run(name, func(b *testing.B) { + b.ResetTimer() + for n := 0; n < b.N; n++ { + _, err := s.FromData(ctx, false, data) + if err != nil { + b.Fatal(err) + } + } + }) + } +} diff --git a/pkg/detectors/atlassian/v1/atlassian_test.go b/pkg/detectors/atlassian/v1/atlassian_test.go index e39ba6569415..29984495d20a 100644 --- a/pkg/detectors/atlassian/v1/atlassian_test.go +++ b/pkg/detectors/atlassian/v1/atlassian_test.go @@ -1,21 +1,11 @@ -//go:build detectors -// +build detectors - package atlassian 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/engine/ahocorasick" - "github.com/trufflesecurity/trufflehog/v3/pkg/pb/detectorspb" + "testing" ) func TestAtlassian_Pattern(t *testing.T) { @@ -75,146 +65,3 @@ func TestAtlassian_Pattern(t *testing.T) { }) } } - -func TestAtlassian_FromChunk(t *testing.T) { - ctx, cancel := context.WithTimeout(context.Background(), time.Second*5) - defer cancel() - testSecrets, err := common.GetSecret(ctx, "trufflehog-testing", "detectors5") - if err != nil { - t.Fatalf("could not get test secrets from GCP: %s", err) - } - secret := testSecrets.MustGetField("ATLASSIAN") - inactiveSecret := testSecrets.MustGetField("ATLASSIAN_INACTIVE") - - 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", - s: Scanner{}, - args: args{ - ctx: context.Background(), - data: []byte(fmt.Sprintf("You can find a atlassian secret %s within", secret)), - verify: true, - }, - want: []detectors.Result{ - { - DetectorType: detectorspb.DetectorType_Atlassian, - Verified: true, - }, - }, - wantErr: false, - wantVerificationErr: false, - }, - { - name: "found, unverified", - s: Scanner{}, - args: args{ - ctx: context.Background(), - data: []byte(fmt.Sprintf("You can find a atlassian secret %s within but not valid", inactiveSecret)), // the secret would satisfy the regex but not pass validation - verify: true, - }, - want: []detectors.Result{ - { - DetectorType: detectorspb.DetectorType_Atlassian, - Verified: false, - }, - }, - wantErr: false, - wantVerificationErr: false, - }, - { - name: "not found", - s: Scanner{}, - args: args{ - ctx: context.Background(), - data: []byte("You cannot find the secret within"), - verify: true, - }, - want: nil, - wantErr: false, - wantVerificationErr: false, - }, - { - name: "found, would be verified if not for timeout", - s: Scanner{client: common.SaneHttpClientTimeOut(1 * time.Microsecond)}, - args: args{ - ctx: context.Background(), - data: []byte(fmt.Sprintf("You can find a atlassian secret %s within", secret)), - verify: true, - }, - want: []detectors.Result{ - { - DetectorType: detectorspb.DetectorType_Atlassian, - Verified: false, - }, - }, - wantErr: false, - wantVerificationErr: true, - }, - { - name: "found, verified but unexpected api surface", - s: Scanner{client: common.ConstantResponseHttpClient(404, "")}, - args: args{ - ctx: context.Background(), - data: []byte(fmt.Sprintf("You can find a atlassian secret %s within", secret)), - verify: true, - }, - want: []detectors.Result{ - { - DetectorType: detectorspb.DetectorType_Atlassian, - Verified: false, - }, - }, - wantErr: false, - wantVerificationErr: true, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - got, err := tt.s.FromData(tt.args.ctx, tt.args.verify, tt.args.data) - if (err != nil) != tt.wantErr { - t.Errorf("Atlassian.FromData() error = %v, wantErr %v", err, tt.wantErr) - return - } - 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.Fatalf("wantVerificationError = %v, verification error = %v", tt.wantVerificationErr, got[i].VerificationError()) - } - } - ignoreOpts := cmpopts.IgnoreFields(detectors.Result{}, "Raw", "verificationError", "ExtraData") - if diff := cmp.Diff(got, tt.want, ignoreOpts); diff != "" { - t.Errorf("Atlassian.FromData() %s diff: (-got +want)\n%s", tt.name, diff) - } - }) - } -} - -func BenchmarkFromData(benchmark *testing.B) { - ctx := context.Background() - s := Scanner{} - for name, data := range detectors.MustGetBenchmarkData() { - benchmark.Run(name, func(b *testing.B) { - b.ResetTimer() - for n := 0; n < b.N; n++ { - _, err := s.FromData(ctx, false, data) - if err != nil { - b.Fatal(err) - } - } - }) - } -} diff --git a/pkg/detectors/atlassian/v2/atlassian_integration_test.go b/pkg/detectors/atlassian/v2/atlassian_integration_test.go new file mode 100644 index 000000000000..4d5633928b7d --- /dev/null +++ b/pkg/detectors/atlassian/v2/atlassian_integration_test.go @@ -0,0 +1,161 @@ +//go:build detectors +// +build detectors + +package atlassian + +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 TestAtlassian_FromChunk(t *testing.T) { + ctx, cancel := context.WithTimeout(context.Background(), time.Second*5) + defer cancel() + testSecrets, err := common.GetSecret(ctx, "trufflehog-testing", "detectors5") + if err != nil { + t.Fatalf("could not get test secrets from GCP: %s", err) + } + secret := testSecrets.MustGetField("ATLASSIAN") + inactiveSecret := testSecrets.MustGetField("ATLASSIAN_INACTIVE") + + 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", + s: Scanner{}, + args: args{ + ctx: context.Background(), + data: []byte(fmt.Sprintf("You can find a atlassian secret %s within", secret)), + verify: true, + }, + want: []detectors.Result{ + { + DetectorType: detectorspb.DetectorType_Atlassian, + Verified: true, + }, + }, + wantErr: false, + wantVerificationErr: false, + }, + { + name: "found, unverified", + s: Scanner{}, + args: args{ + ctx: context.Background(), + data: []byte(fmt.Sprintf("You can find a atlassian secret %s within but not valid", inactiveSecret)), // the secret would satisfy the regex but not pass validation + verify: true, + }, + want: []detectors.Result{ + { + DetectorType: detectorspb.DetectorType_Atlassian, + Verified: false, + }, + }, + wantErr: false, + wantVerificationErr: false, + }, + { + name: "not found", + s: Scanner{}, + args: args{ + ctx: context.Background(), + data: []byte("You cannot find the secret within"), + verify: true, + }, + want: nil, + wantErr: false, + wantVerificationErr: false, + }, + { + name: "found, would be verified if not for timeout", + s: Scanner{client: common.SaneHttpClientTimeOut(1 * time.Microsecond)}, + args: args{ + ctx: context.Background(), + data: []byte(fmt.Sprintf("You can find a atlassian secret %s within", secret)), + verify: true, + }, + want: []detectors.Result{ + { + DetectorType: detectorspb.DetectorType_Atlassian, + Verified: false, + }, + }, + wantErr: false, + wantVerificationErr: true, + }, + { + name: "found, verified but unexpected api surface", + s: Scanner{client: common.ConstantResponseHttpClient(404, "")}, + args: args{ + ctx: context.Background(), + data: []byte(fmt.Sprintf("You can find a atlassian secret %s within", secret)), + verify: true, + }, + want: []detectors.Result{ + { + DetectorType: detectorspb.DetectorType_Atlassian, + Verified: false, + }, + }, + wantErr: false, + wantVerificationErr: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := tt.s.FromData(tt.args.ctx, tt.args.verify, tt.args.data) + if (err != nil) != tt.wantErr { + t.Errorf("Atlassian.FromData() error = %v, wantErr %v", err, tt.wantErr) + return + } + 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.Fatalf("wantVerificationError = %v, verification error = %v", tt.wantVerificationErr, got[i].VerificationError()) + } + } + ignoreOpts := cmpopts.IgnoreFields(detectors.Result{}, "Raw", "verificationError", "ExtraData") + if diff := cmp.Diff(got, tt.want, ignoreOpts); diff != "" { + t.Errorf("Atlassian.FromData() %s diff: (-got +want)\n%s", tt.name, diff) + } + }) + } +} + +func BenchmarkFromData(benchmark *testing.B) { + ctx := context.Background() + s := Scanner{} + for name, data := range detectors.MustGetBenchmarkData() { + benchmark.Run(name, func(b *testing.B) { + b.ResetTimer() + for n := 0; n < b.N; n++ { + _, err := s.FromData(ctx, false, data) + if err != nil { + b.Fatal(err) + } + } + }) + } +} diff --git a/pkg/detectors/atlassian/v2/atlassian_test.go b/pkg/detectors/atlassian/v2/atlassian_test.go index 755463f1f5e3..de1093f9fb56 100644 --- a/pkg/detectors/atlassian/v2/atlassian_test.go +++ b/pkg/detectors/atlassian/v2/atlassian_test.go @@ -1,21 +1,11 @@ -//go:build detectors -// +build detectors - package atlassian 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/engine/ahocorasick" - "github.com/trufflesecurity/trufflehog/v3/pkg/pb/detectorspb" + "testing" ) func TestAtlassian_Pattern(t *testing.T) { @@ -75,146 +65,3 @@ func TestAtlassian_Pattern(t *testing.T) { }) } } - -func TestAtlassian_FromChunk(t *testing.T) { - ctx, cancel := context.WithTimeout(context.Background(), time.Second*5) - defer cancel() - testSecrets, err := common.GetSecret(ctx, "trufflehog-testing", "detectors5") - if err != nil { - t.Fatalf("could not get test secrets from GCP: %s", err) - } - secret := testSecrets.MustGetField("ATLASSIAN") - inactiveSecret := testSecrets.MustGetField("ATLASSIAN_INACTIVE") - - 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", - s: Scanner{}, - args: args{ - ctx: context.Background(), - data: []byte(fmt.Sprintf("You can find a atlassian secret %s within", secret)), - verify: true, - }, - want: []detectors.Result{ - { - DetectorType: detectorspb.DetectorType_Atlassian, - Verified: true, - }, - }, - wantErr: false, - wantVerificationErr: false, - }, - { - name: "found, unverified", - s: Scanner{}, - args: args{ - ctx: context.Background(), - data: []byte(fmt.Sprintf("You can find a atlassian secret %s within but not valid", inactiveSecret)), // the secret would satisfy the regex but not pass validation - verify: true, - }, - want: []detectors.Result{ - { - DetectorType: detectorspb.DetectorType_Atlassian, - Verified: false, - }, - }, - wantErr: false, - wantVerificationErr: false, - }, - { - name: "not found", - s: Scanner{}, - args: args{ - ctx: context.Background(), - data: []byte("You cannot find the secret within"), - verify: true, - }, - want: nil, - wantErr: false, - wantVerificationErr: false, - }, - { - name: "found, would be verified if not for timeout", - s: Scanner{client: common.SaneHttpClientTimeOut(1 * time.Microsecond)}, - args: args{ - ctx: context.Background(), - data: []byte(fmt.Sprintf("You can find a atlassian secret %s within", secret)), - verify: true, - }, - want: []detectors.Result{ - { - DetectorType: detectorspb.DetectorType_Atlassian, - Verified: false, - }, - }, - wantErr: false, - wantVerificationErr: true, - }, - { - name: "found, verified but unexpected api surface", - s: Scanner{client: common.ConstantResponseHttpClient(404, "")}, - args: args{ - ctx: context.Background(), - data: []byte(fmt.Sprintf("You can find a atlassian secret %s within", secret)), - verify: true, - }, - want: []detectors.Result{ - { - DetectorType: detectorspb.DetectorType_Atlassian, - Verified: false, - }, - }, - wantErr: false, - wantVerificationErr: true, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - got, err := tt.s.FromData(tt.args.ctx, tt.args.verify, tt.args.data) - if (err != nil) != tt.wantErr { - t.Errorf("Atlassian.FromData() error = %v, wantErr %v", err, tt.wantErr) - return - } - 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.Fatalf("wantVerificationError = %v, verification error = %v", tt.wantVerificationErr, got[i].VerificationError()) - } - } - ignoreOpts := cmpopts.IgnoreFields(detectors.Result{}, "Raw", "verificationError", "ExtraData") - if diff := cmp.Diff(got, tt.want, ignoreOpts); diff != "" { - t.Errorf("Atlassian.FromData() %s diff: (-got +want)\n%s", tt.name, diff) - } - }) - } -} - -func BenchmarkFromData(benchmark *testing.B) { - ctx := context.Background() - s := Scanner{} - for name, data := range detectors.MustGetBenchmarkData() { - benchmark.Run(name, func(b *testing.B) { - b.ResetTimer() - for n := 0; n < b.N; n++ { - _, err := s.FromData(ctx, false, data) - if err != nil { - b.Fatal(err) - } - } - }) - } -} diff --git a/pkg/detectors/coinbase_waas/coinbase_waas_integration_test.go b/pkg/detectors/coinbase_waas/coinbase_waas_integration_test.go new file mode 100644 index 000000000000..9aa6edacba37 --- /dev/null +++ b/pkg/detectors/coinbase_waas/coinbase_waas_integration_test.go @@ -0,0 +1,174 @@ +//go:build detectors +// +build detectors + +package coinbase_waas + +import ( + "context" + "encoding/base64" + "fmt" + "testing" + "time" + + "github.com/google/go-cmp/cmp" + "github.com/google/go-cmp/cmp/cmpopts" + + "github.com/trufflesecurity/trufflehog/v3/pkg/detectors" + + "github.com/trufflesecurity/trufflehog/v3/pkg/common" + "github.com/trufflesecurity/trufflehog/v3/pkg/pb/detectorspb" +) + +func TestCoinbaseWaaS_FromChunk(t *testing.T) { + ctx, cancel := context.WithTimeout(context.Background(), time.Second*5) + defer cancel() + testSecrets, err := common.GetSecret(ctx, "trufflehog-testing", "detectors5") + if err != nil { + t.Fatalf("could not get test secrets from GCP: %s", err) + } + secretb64 := testSecrets.MustGetField("COINBASE_WAAS") + secretB, err := base64.StdEncoding.DecodeString(secretb64) + if err != nil { + t.Fatalf("could not decode secret: %s", err) + } + secret := string(secretB) + + inactiveSecretb64 := testSecrets.MustGetField("COINBASE_WAAS_INACTIVE") + inactiveSecretB, err := base64.StdEncoding.DecodeString(inactiveSecretb64) + if err != nil { + t.Fatalf("could not decode secret: %s", err) + } + inactiveSecret := string(inactiveSecretB) + + 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", + s: Scanner{}, + args: args{ + ctx: context.Background(), + data: []byte(fmt.Sprintf("You can find a coinbase_waas secret %s within", secret)), + verify: true, + }, + want: []detectors.Result{ + { + DetectorType: detectorspb.DetectorType_CoinbaseWaaS, + Verified: true, + }, + }, + wantErr: false, + wantVerificationErr: false, + }, + { + name: "found, unverified", + s: Scanner{}, + args: args{ + ctx: context.Background(), + data: []byte(fmt.Sprintf("You can find a coinbase_waas secret %s within but not valid", inactiveSecret)), // the secret would satisfy the regex but not pass validation + verify: true, + }, + want: []detectors.Result{ + { + DetectorType: detectorspb.DetectorType_CoinbaseWaaS, + Verified: false, + }, + }, + wantErr: false, + wantVerificationErr: false, + }, + { + name: "not found", + s: Scanner{}, + args: args{ + ctx: context.Background(), + data: []byte("You cannot find the secret within"), + verify: true, + }, + want: nil, + wantErr: false, + wantVerificationErr: false, + }, + { + name: "found, would be verified if not for timeout", + s: Scanner{client: common.SaneHttpClientTimeOut(1 * time.Microsecond)}, + args: args{ + ctx: context.Background(), + data: []byte(fmt.Sprintf("You can find a coinbase_waas secret %s within", secret)), + verify: true, + }, + want: []detectors.Result{ + { + DetectorType: detectorspb.DetectorType_CoinbaseWaaS, + Verified: false, + }, + }, + wantErr: false, + wantVerificationErr: true, + }, + { + name: "found, verified but unexpected api surface", + s: Scanner{client: common.ConstantResponseHttpClient(500, "")}, + args: args{ + ctx: context.Background(), + data: []byte(fmt.Sprintf("You can find a coinbase_waas secret %s within", secret)), + verify: true, + }, + want: []detectors.Result{ + { + DetectorType: detectorspb.DetectorType_CoinbaseWaaS, + Verified: false, + }, + }, + wantErr: false, + wantVerificationErr: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := tt.s.FromData(tt.args.ctx, tt.args.verify, tt.args.data) + if (err != nil) != tt.wantErr { + t.Errorf("Coinbasewaas.FromData() error = %v, wantErr %v", err, tt.wantErr) + return + } + 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.Fatalf("wantVerificationError = %v, verification error = %v", tt.wantVerificationErr, got[i].VerificationError()) + } + } + ignoreOpts := cmpopts.IgnoreFields(detectors.Result{}, "Raw", "RawV2", "verificationError") + if diff := cmp.Diff(got, tt.want, ignoreOpts); diff != "" { + t.Errorf("Coinbasewaas.FromData() %s diff: (-got +want)\n%s", tt.name, diff) + } + }) + } +} + +func BenchmarkFromData(benchmark *testing.B) { + ctx := context.Background() + s := Scanner{} + for name, data := range detectors.MustGetBenchmarkData() { + benchmark.Run(name, func(b *testing.B) { + b.ResetTimer() + for n := 0; n < b.N; n++ { + _, err := s.FromData(ctx, false, data) + if err != nil { + b.Fatal(err) + } + } + }) + } +} diff --git a/pkg/detectors/coinbase_waas/coinbase_waas_test.go b/pkg/detectors/coinbase_waas/coinbase_waas_test.go index 27f6cc64c63e..e2948a639179 100644 --- a/pkg/detectors/coinbase_waas/coinbase_waas_test.go +++ b/pkg/detectors/coinbase_waas/coinbase_waas_test.go @@ -1,22 +1,8 @@ -//go:build detectors -// +build detectors - package coinbase_waas import ( "context" - "encoding/base64" - "fmt" "testing" - "time" - - "github.com/google/go-cmp/cmp" - "github.com/google/go-cmp/cmp/cmpopts" - - "github.com/trufflesecurity/trufflehog/v3/pkg/detectors" - - "github.com/trufflesecurity/trufflehog/v3/pkg/common" - "github.com/trufflesecurity/trufflehog/v3/pkg/pb/detectorspb" ) func TestCoinbaseWaaS_Pattern(t *testing.T) { @@ -148,157 +134,3 @@ func TestCoinbaseWaaS_Pattern(t *testing.T) { }) } } - -func TestCoinbaseWaaS_FromChunk(t *testing.T) { - ctx, cancel := context.WithTimeout(context.Background(), time.Second*5) - defer cancel() - testSecrets, err := common.GetSecret(ctx, "trufflehog-testing", "detectors5") - if err != nil { - t.Fatalf("could not get test secrets from GCP: %s", err) - } - secretb64 := testSecrets.MustGetField("COINBASE_WAAS") - secretB, err := base64.StdEncoding.DecodeString(secretb64) - if err != nil { - t.Fatalf("could not decode secret: %s", err) - } - secret := string(secretB) - - inactiveSecretb64 := testSecrets.MustGetField("COINBASE_WAAS_INACTIVE") - inactiveSecretB, err := base64.StdEncoding.DecodeString(inactiveSecretb64) - if err != nil { - t.Fatalf("could not decode secret: %s", err) - } - inactiveSecret := string(inactiveSecretB) - - 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", - s: Scanner{}, - args: args{ - ctx: context.Background(), - data: []byte(fmt.Sprintf("You can find a coinbase_waas secret %s within", secret)), - verify: true, - }, - want: []detectors.Result{ - { - DetectorType: detectorspb.DetectorType_CoinbaseWaaS, - Verified: true, - }, - }, - wantErr: false, - wantVerificationErr: false, - }, - { - name: "found, unverified", - s: Scanner{}, - args: args{ - ctx: context.Background(), - data: []byte(fmt.Sprintf("You can find a coinbase_waas secret %s within but not valid", inactiveSecret)), // the secret would satisfy the regex but not pass validation - verify: true, - }, - want: []detectors.Result{ - { - DetectorType: detectorspb.DetectorType_CoinbaseWaaS, - Verified: false, - }, - }, - wantErr: false, - wantVerificationErr: false, - }, - { - name: "not found", - s: Scanner{}, - args: args{ - ctx: context.Background(), - data: []byte("You cannot find the secret within"), - verify: true, - }, - want: nil, - wantErr: false, - wantVerificationErr: false, - }, - { - name: "found, would be verified if not for timeout", - s: Scanner{client: common.SaneHttpClientTimeOut(1 * time.Microsecond)}, - args: args{ - ctx: context.Background(), - data: []byte(fmt.Sprintf("You can find a coinbase_waas secret %s within", secret)), - verify: true, - }, - want: []detectors.Result{ - { - DetectorType: detectorspb.DetectorType_CoinbaseWaaS, - Verified: false, - }, - }, - wantErr: false, - wantVerificationErr: true, - }, - { - name: "found, verified but unexpected api surface", - s: Scanner{client: common.ConstantResponseHttpClient(500, "")}, - args: args{ - ctx: context.Background(), - data: []byte(fmt.Sprintf("You can find a coinbase_waas secret %s within", secret)), - verify: true, - }, - want: []detectors.Result{ - { - DetectorType: detectorspb.DetectorType_CoinbaseWaaS, - Verified: false, - }, - }, - wantErr: false, - wantVerificationErr: true, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - got, err := tt.s.FromData(tt.args.ctx, tt.args.verify, tt.args.data) - if (err != nil) != tt.wantErr { - t.Errorf("Coinbasewaas.FromData() error = %v, wantErr %v", err, tt.wantErr) - return - } - 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.Fatalf("wantVerificationError = %v, verification error = %v", tt.wantVerificationErr, got[i].VerificationError()) - } - } - ignoreOpts := cmpopts.IgnoreFields(detectors.Result{}, "Raw", "RawV2", "verificationError") - if diff := cmp.Diff(got, tt.want, ignoreOpts); diff != "" { - t.Errorf("Coinbasewaas.FromData() %s diff: (-got +want)\n%s", tt.name, diff) - } - }) - } -} - -func BenchmarkFromData(benchmark *testing.B) { - ctx := context.Background() - s := Scanner{} - for name, data := range detectors.MustGetBenchmarkData() { - benchmark.Run(name, func(b *testing.B) { - b.ResetTimer() - for n := 0; n < b.N; n++ { - _, err := s.FromData(ctx, false, data) - if err != nil { - b.Fatal(err) - } - } - }) - } -} diff --git a/pkg/detectors/deno/denodeploy_integration_test.go b/pkg/detectors/deno/denodeploy_integration_test.go new file mode 100644 index 000000000000..8a2a4a4cab63 --- /dev/null +++ b/pkg/detectors/deno/denodeploy_integration_test.go @@ -0,0 +1,162 @@ +//go:build detectors +// +build detectors + +package denodeploy + +import ( + "context" + "fmt" + "testing" + "time" + + "github.com/google/go-cmp/cmp" + "github.com/google/go-cmp/cmp/cmpopts" + + "github.com/trufflesecurity/trufflehog/v3/pkg/detectors" + + "github.com/trufflesecurity/trufflehog/v3/pkg/common" + "github.com/trufflesecurity/trufflehog/v3/pkg/pb/detectorspb" +) + +func TestDenoDeploy_FromChunk(t *testing.T) { + ctx, cancel := context.WithTimeout(context.Background(), time.Second*5) + defer cancel() + testSecrets, err := common.GetSecret(ctx, "trufflehog-testing", "detectors5") + if err != nil { + t.Fatalf("could not get test secrets from GCP: %s", err) + } + secret := testSecrets.MustGetField("DENODEPLOY") + inactiveSecret := testSecrets.MustGetField("DENODEPLOY_INACTIVE") + + 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", + s: Scanner{}, + args: args{ + ctx: context.Background(), + data: []byte(fmt.Sprintf("You can find a denodeploy secret %s within", secret)), + verify: true, + }, + want: []detectors.Result{ + { + DetectorType: detectorspb.DetectorType_DenoDeploy, + Verified: true, + }, + }, + wantErr: false, + wantVerificationErr: false, + }, + { + name: "found, unverified", + s: Scanner{}, + args: args{ + ctx: context.Background(), + data: []byte(fmt.Sprintf("You can find a denodeploy secret %s within but not valid", inactiveSecret)), // the secret would satisfy the regex but not pass validation + verify: true, + }, + want: []detectors.Result{ + { + DetectorType: detectorspb.DetectorType_DenoDeploy, + Verified: false, + }, + }, + wantErr: false, + wantVerificationErr: false, + }, + { + name: "not found", + s: Scanner{}, + args: args{ + ctx: context.Background(), + data: []byte("You cannot find the secret within"), + verify: true, + }, + want: nil, + wantErr: false, + wantVerificationErr: false, + }, + { + name: "found, would be verified if not for timeout", + s: Scanner{client: common.SaneHttpClientTimeOut(1 * time.Microsecond)}, + args: args{ + ctx: context.Background(), + data: []byte(fmt.Sprintf("You can find a denodeploy secret %s within", secret)), + verify: true, + }, + want: []detectors.Result{ + { + DetectorType: detectorspb.DetectorType_DenoDeploy, + Verified: false, + }, + }, + wantErr: false, + wantVerificationErr: true, + }, + { + name: "found, verified but unexpected api surface", + s: Scanner{client: common.ConstantResponseHttpClient(404, "")}, + args: args{ + ctx: context.Background(), + data: []byte(fmt.Sprintf("You can find a denodeploy secret %s within", secret)), + verify: true, + }, + want: []detectors.Result{ + { + DetectorType: detectorspb.DetectorType_DenoDeploy, + Verified: false, + }, + }, + wantErr: false, + wantVerificationErr: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := tt.s.FromData(tt.args.ctx, tt.args.verify, tt.args.data) + if (err != nil) != tt.wantErr { + t.Errorf("Denodeploy.FromData() error = %v, wantErr %v", err, tt.wantErr) + return + } + 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.Fatalf("wantVerificationError = %v, verification error = %v", tt.wantVerificationErr, got[i].VerificationError()) + } + } + ignoreOpts := cmpopts.IgnoreFields(detectors.Result{}, "Raw", "verificationError", "ExtraData") + if diff := cmp.Diff(got, tt.want, ignoreOpts); diff != "" { + t.Errorf("Denodeploy.FromData() %s diff: (-got +want)\n%s", tt.name, diff) + } + }) + } +} + +func BenchmarkFromData(benchmark *testing.B) { + ctx := context.Background() + s := Scanner{} + for name, data := range detectors.MustGetBenchmarkData() { + benchmark.Run(name, func(b *testing.B) { + b.ResetTimer() + for n := 0; n < b.N; n++ { + _, err := s.FromData(ctx, false, data) + if err != nil { + b.Fatal(err) + } + } + }) + } +} diff --git a/pkg/detectors/deno/denodeploy_test.go b/pkg/detectors/deno/denodeploy_test.go index 4b6189ba18c9..89e39f6cb517 100644 --- a/pkg/detectors/deno/denodeploy_test.go +++ b/pkg/detectors/deno/denodeploy_test.go @@ -1,21 +1,8 @@ -//go:build detectors -// +build detectors - package denodeploy import ( "context" - "fmt" "testing" - "time" - - "github.com/google/go-cmp/cmp" - "github.com/google/go-cmp/cmp/cmpopts" - - "github.com/trufflesecurity/trufflehog/v3/pkg/detectors" - - "github.com/trufflesecurity/trufflehog/v3/pkg/common" - "github.com/trufflesecurity/trufflehog/v3/pkg/pb/detectorspb" ) func TestDenoDeploy_Pattern(t *testing.T) { @@ -110,146 +97,3 @@ export DENO_DEPLOY_TOKEN="ddp_QLbDfRlMKpXSf3oCz20Hp8wVVxThDwlwhFbV""`, }) } } - -func TestDenoDeploy_FromChunk(t *testing.T) { - ctx, cancel := context.WithTimeout(context.Background(), time.Second*5) - defer cancel() - testSecrets, err := common.GetSecret(ctx, "trufflehog-testing", "detectors5") - if err != nil { - t.Fatalf("could not get test secrets from GCP: %s", err) - } - secret := testSecrets.MustGetField("DENODEPLOY") - inactiveSecret := testSecrets.MustGetField("DENODEPLOY_INACTIVE") - - 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", - s: Scanner{}, - args: args{ - ctx: context.Background(), - data: []byte(fmt.Sprintf("You can find a denodeploy secret %s within", secret)), - verify: true, - }, - want: []detectors.Result{ - { - DetectorType: detectorspb.DetectorType_DenoDeploy, - Verified: true, - }, - }, - wantErr: false, - wantVerificationErr: false, - }, - { - name: "found, unverified", - s: Scanner{}, - args: args{ - ctx: context.Background(), - data: []byte(fmt.Sprintf("You can find a denodeploy secret %s within but not valid", inactiveSecret)), // the secret would satisfy the regex but not pass validation - verify: true, - }, - want: []detectors.Result{ - { - DetectorType: detectorspb.DetectorType_DenoDeploy, - Verified: false, - }, - }, - wantErr: false, - wantVerificationErr: false, - }, - { - name: "not found", - s: Scanner{}, - args: args{ - ctx: context.Background(), - data: []byte("You cannot find the secret within"), - verify: true, - }, - want: nil, - wantErr: false, - wantVerificationErr: false, - }, - { - name: "found, would be verified if not for timeout", - s: Scanner{client: common.SaneHttpClientTimeOut(1 * time.Microsecond)}, - args: args{ - ctx: context.Background(), - data: []byte(fmt.Sprintf("You can find a denodeploy secret %s within", secret)), - verify: true, - }, - want: []detectors.Result{ - { - DetectorType: detectorspb.DetectorType_DenoDeploy, - Verified: false, - }, - }, - wantErr: false, - wantVerificationErr: true, - }, - { - name: "found, verified but unexpected api surface", - s: Scanner{client: common.ConstantResponseHttpClient(404, "")}, - args: args{ - ctx: context.Background(), - data: []byte(fmt.Sprintf("You can find a denodeploy secret %s within", secret)), - verify: true, - }, - want: []detectors.Result{ - { - DetectorType: detectorspb.DetectorType_DenoDeploy, - Verified: false, - }, - }, - wantErr: false, - wantVerificationErr: true, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - got, err := tt.s.FromData(tt.args.ctx, tt.args.verify, tt.args.data) - if (err != nil) != tt.wantErr { - t.Errorf("Denodeploy.FromData() error = %v, wantErr %v", err, tt.wantErr) - return - } - 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.Fatalf("wantVerificationError = %v, verification error = %v", tt.wantVerificationErr, got[i].VerificationError()) - } - } - ignoreOpts := cmpopts.IgnoreFields(detectors.Result{}, "Raw", "verificationError", "ExtraData") - if diff := cmp.Diff(got, tt.want, ignoreOpts); diff != "" { - t.Errorf("Denodeploy.FromData() %s diff: (-got +want)\n%s", tt.name, diff) - } - }) - } -} - -func BenchmarkFromData(benchmark *testing.B) { - ctx := context.Background() - s := Scanner{} - for name, data := range detectors.MustGetBenchmarkData() { - benchmark.Run(name, func(b *testing.B) { - b.ResetTimer() - for n := 0; n < b.N; n++ { - _, err := s.FromData(ctx, false, data) - if err != nil { - b.Fatal(err) - } - } - }) - } -} diff --git a/pkg/detectors/elevenlabs/v1/elevenlabs_integration_test.go b/pkg/detectors/elevenlabs/v1/elevenlabs_integration_test.go new file mode 100644 index 000000000000..408eb0275701 --- /dev/null +++ b/pkg/detectors/elevenlabs/v1/elevenlabs_integration_test.go @@ -0,0 +1,27 @@ +//go:build detectors +// +build detectors + +package elevenlabs + +import ( + "context" + "testing" + + "github.com/trufflesecurity/trufflehog/v3/pkg/detectors" +) + +func BenchmarkFromData(benchmark *testing.B) { + ctx := context.Background() + s := Scanner{} + for name, data := range detectors.MustGetBenchmarkData() { + benchmark.Run(name, func(b *testing.B) { + b.ResetTimer() + for n := 0; n < b.N; n++ { + _, err := s.FromData(ctx, false, data) + if err != nil { + b.Fatal(err) + } + } + }) + } +} diff --git a/pkg/detectors/elevenlabs/v1/elevenlabs_test.go b/pkg/detectors/elevenlabs/v1/elevenlabs_test.go index a9bb279876ae..c24a3af5ee71 100644 --- a/pkg/detectors/elevenlabs/v1/elevenlabs_test.go +++ b/pkg/detectors/elevenlabs/v1/elevenlabs_test.go @@ -1,6 +1,3 @@ -//go:build detectors -// +build detectors - package elevenlabs import ( @@ -70,19 +67,3 @@ func TestElevenlabs_Pattern(t *testing.T) { }) } } - -func BenchmarkFromData(benchmark *testing.B) { - ctx := context.Background() - s := Scanner{} - for name, data := range detectors.MustGetBenchmarkData() { - benchmark.Run(name, func(b *testing.B) { - b.ResetTimer() - for n := 0; n < b.N; n++ { - _, err := s.FromData(ctx, false, data) - if err != nil { - b.Fatal(err) - } - } - }) - } -} diff --git a/pkg/detectors/elevenlabs/v2/elevenlabs_integration_test.go b/pkg/detectors/elevenlabs/v2/elevenlabs_integration_test.go new file mode 100644 index 000000000000..1d439f377cd7 --- /dev/null +++ b/pkg/detectors/elevenlabs/v2/elevenlabs_integration_test.go @@ -0,0 +1,175 @@ +//go:build detectors +// +build detectors + +package elevenlabs + +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 TestElevenlabs_FromChunk(t *testing.T) { + ctx, cancel := context.WithTimeout(context.Background(), time.Second*5) + defer cancel() + testSecrets, err := common.GetSecret(ctx, "trufflehog-testing", "detectors5") + if err != nil { + t.Fatalf("could not get test secrets from GCP: %s", err) + } + secret := testSecrets.MustGetField("ELEVENLABS") + inactiveSecret := testSecrets.MustGetField("ELEVENLABS_INACTIVE") + + 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", + s: Scanner{}, + args: args{ + ctx: context.Background(), + data: []byte(fmt.Sprintf("You can find a elevenlabs secret %s within", secret)), + verify: true, + }, + want: []detectors.Result{ + { + DetectorType: detectorspb.DetectorType_ElevenLabs, + Verified: true, + ExtraData: map[string]string{ + "version": "2", + "Name": "Ahmed", + "Tier": "free", + }, + }, + }, + wantErr: false, + wantVerificationErr: false, + }, + { + name: "found, unverified", + s: Scanner{}, + args: args{ + ctx: context.Background(), + data: []byte(fmt.Sprintf("You can find a elevenlabs secret %s within but not valid", inactiveSecret)), // the secret would satisfy the regex but not pass validation + verify: true, + }, + want: []detectors.Result{ + { + DetectorType: detectorspb.DetectorType_ElevenLabs, + Verified: false, + ExtraData: map[string]string{ + "version": "2", + }, + }, + }, + wantErr: false, + wantVerificationErr: false, + }, + { + name: "not found", + s: Scanner{}, + args: args{ + ctx: context.Background(), + data: []byte("You cannot find the secret within"), + verify: true, + }, + want: nil, + wantErr: false, + wantVerificationErr: false, + }, + { + name: "found, would be verified if not for timeout", + s: Scanner{client: common.SaneHttpClientTimeOut(1 * time.Microsecond)}, + args: args{ + ctx: context.Background(), + data: []byte(fmt.Sprintf("You can find a elevenlabs secret %s within", secret)), + verify: true, + }, + want: []detectors.Result{ + { + DetectorType: detectorspb.DetectorType_ElevenLabs, + Verified: false, + ExtraData: map[string]string{ + "version": "2", + }, + }, + }, + wantErr: false, + wantVerificationErr: true, + }, + { + name: "found, verified but unexpected api surface", + s: Scanner{client: common.ConstantResponseHttpClient(404, "")}, + args: args{ + ctx: context.Background(), + data: []byte(fmt.Sprintf("You can find a elevenlabs secret %s within", secret)), + verify: true, + }, + want: []detectors.Result{ + { + DetectorType: detectorspb.DetectorType_ElevenLabs, + Verified: false, + ExtraData: map[string]string{ + "version": "2", + }, + }, + }, + wantErr: false, + wantVerificationErr: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := tt.s.FromData(tt.args.ctx, tt.args.verify, tt.args.data) + if (err != nil) != tt.wantErr { + t.Errorf("Elevenlabs.FromData() error = %v, wantErr %v", err, tt.wantErr) + return + } + 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.Fatalf("wantVerificationError = %v, verification error = %v", tt.wantVerificationErr, got[i].VerificationError()) + } + } + ignoreOpts := cmpopts.IgnoreFields(detectors.Result{}, "Raw", "verificationError") + if diff := cmp.Diff(got, tt.want, ignoreOpts); diff != "" { + t.Errorf("Elevenlabs.FromData() %s diff: (-got +want)\n%s", tt.name, diff) + } + }) + } +} + +func BenchmarkFromData(benchmark *testing.B) { + ctx := context.Background() + s := Scanner{} + for name, data := range detectors.MustGetBenchmarkData() { + benchmark.Run(name, func(b *testing.B) { + b.ResetTimer() + for n := 0; n < b.N; n++ { + _, err := s.FromData(ctx, false, data) + if err != nil { + b.Fatal(err) + } + } + }) + } +} diff --git a/pkg/detectors/elevenlabs/v2/elevenlabs_test.go b/pkg/detectors/elevenlabs/v2/elevenlabs_test.go index 4aa37f57fdf4..1523459f78e6 100644 --- a/pkg/detectors/elevenlabs/v2/elevenlabs_test.go +++ b/pkg/detectors/elevenlabs/v2/elevenlabs_test.go @@ -1,21 +1,11 @@ -//go:build detectors -// +build detectors - package elevenlabs 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/engine/ahocorasick" - "github.com/trufflesecurity/trufflehog/v3/pkg/pb/detectorspb" + "testing" ) func TestElevenlabs_Pattern(t *testing.T) { @@ -75,160 +65,3 @@ func TestElevenlabs_Pattern(t *testing.T) { }) } } - -func TestElevenlabs_FromChunk(t *testing.T) { - ctx, cancel := context.WithTimeout(context.Background(), time.Second*5) - defer cancel() - testSecrets, err := common.GetSecret(ctx, "trufflehog-testing", "detectors5") - if err != nil { - t.Fatalf("could not get test secrets from GCP: %s", err) - } - secret := testSecrets.MustGetField("ELEVENLABS") - inactiveSecret := testSecrets.MustGetField("ELEVENLABS_INACTIVE") - - 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", - s: Scanner{}, - args: args{ - ctx: context.Background(), - data: []byte(fmt.Sprintf("You can find a elevenlabs secret %s within", secret)), - verify: true, - }, - want: []detectors.Result{ - { - DetectorType: detectorspb.DetectorType_ElevenLabs, - Verified: true, - ExtraData: map[string]string{ - "version": "2", - "Name": "Ahmed", - "Tier": "free", - }, - }, - }, - wantErr: false, - wantVerificationErr: false, - }, - { - name: "found, unverified", - s: Scanner{}, - args: args{ - ctx: context.Background(), - data: []byte(fmt.Sprintf("You can find a elevenlabs secret %s within but not valid", inactiveSecret)), // the secret would satisfy the regex but not pass validation - verify: true, - }, - want: []detectors.Result{ - { - DetectorType: detectorspb.DetectorType_ElevenLabs, - Verified: false, - ExtraData: map[string]string{ - "version": "2", - }, - }, - }, - wantErr: false, - wantVerificationErr: false, - }, - { - name: "not found", - s: Scanner{}, - args: args{ - ctx: context.Background(), - data: []byte("You cannot find the secret within"), - verify: true, - }, - want: nil, - wantErr: false, - wantVerificationErr: false, - }, - { - name: "found, would be verified if not for timeout", - s: Scanner{client: common.SaneHttpClientTimeOut(1 * time.Microsecond)}, - args: args{ - ctx: context.Background(), - data: []byte(fmt.Sprintf("You can find a elevenlabs secret %s within", secret)), - verify: true, - }, - want: []detectors.Result{ - { - DetectorType: detectorspb.DetectorType_ElevenLabs, - Verified: false, - ExtraData: map[string]string{ - "version": "2", - }, - }, - }, - wantErr: false, - wantVerificationErr: true, - }, - { - name: "found, verified but unexpected api surface", - s: Scanner{client: common.ConstantResponseHttpClient(404, "")}, - args: args{ - ctx: context.Background(), - data: []byte(fmt.Sprintf("You can find a elevenlabs secret %s within", secret)), - verify: true, - }, - want: []detectors.Result{ - { - DetectorType: detectorspb.DetectorType_ElevenLabs, - Verified: false, - ExtraData: map[string]string{ - "version": "2", - }, - }, - }, - wantErr: false, - wantVerificationErr: true, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - got, err := tt.s.FromData(tt.args.ctx, tt.args.verify, tt.args.data) - if (err != nil) != tt.wantErr { - t.Errorf("Elevenlabs.FromData() error = %v, wantErr %v", err, tt.wantErr) - return - } - 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.Fatalf("wantVerificationError = %v, verification error = %v", tt.wantVerificationErr, got[i].VerificationError()) - } - } - ignoreOpts := cmpopts.IgnoreFields(detectors.Result{}, "Raw", "verificationError") - if diff := cmp.Diff(got, tt.want, ignoreOpts); diff != "" { - t.Errorf("Elevenlabs.FromData() %s diff: (-got +want)\n%s", tt.name, diff) - } - }) - } -} - -func BenchmarkFromData(benchmark *testing.B) { - ctx := context.Background() - s := Scanner{} - for name, data := range detectors.MustGetBenchmarkData() { - benchmark.Run(name, func(b *testing.B) { - b.ResetTimer() - for n := 0; n < b.N; n++ { - _, err := s.FromData(ctx, false, data) - if err != nil { - b.Fatal(err) - } - } - }) - } -} diff --git a/pkg/detectors/endorlabs/endorlabs_integration_test.go b/pkg/detectors/endorlabs/endorlabs_integration_test.go new file mode 100644 index 000000000000..313c0b291074 --- /dev/null +++ b/pkg/detectors/endorlabs/endorlabs_integration_test.go @@ -0,0 +1,182 @@ +//go:build detectors +// +build detectors + +package endorlabs + +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 TestEndorlabs_FromChunk(t *testing.T) { + ctx, cancel := context.WithTimeout(context.Background(), time.Second*5) + defer cancel() + testSecrets, err := common.GetSecret(ctx, "trufflehog-testing", "detectors5") + if err != nil { + t.Fatalf("could not get test secrets from GCP: %s", err) + } + key := testSecrets.MustGetField("ENDOR_KEY") + secret := testSecrets.MustGetField("ENDOR_SECRET") + inactiveKey := testSecrets.MustGetField("ENDOR_KEY_INACTIVE") + inactiveSecret := testSecrets.MustGetField("ENDOR_SECRET_INACTIVE") + + 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", + s: Scanner{}, + args: args{ + ctx: context.Background(), + data: []byte(fmt.Sprintf("You can find a endorlabs key %s and endorlabs secret %s within", key, secret)), + verify: true, + }, + want: []detectors.Result{ + { + DetectorType: detectorspb.DetectorType_EndorLabs, + Verified: true, + }, + { + DetectorType: detectorspb.DetectorType_EndorLabs, + Verified: false, + }, + }, + wantErr: false, + wantVerificationErr: false, + }, + { + name: "found, unverified", + s: Scanner{}, + args: args{ + ctx: context.Background(), + data: []byte(fmt.Sprintf("You can find a endorlabs key %s and endorlabs secret %s within but not valid", inactiveKey, inactiveSecret)), // the secret would satisfy the regex but not pass validation + verify: true, + }, + want: []detectors.Result{ + { + DetectorType: detectorspb.DetectorType_EndorLabs, + Verified: false, + }, + { + DetectorType: detectorspb.DetectorType_EndorLabs, + Verified: false, + }, + }, + wantErr: false, + wantVerificationErr: false, + }, + { + name: "not found", + s: Scanner{}, + args: args{ + ctx: context.Background(), + data: []byte("You cannot find the secret within"), + verify: true, + }, + want: nil, + wantErr: false, + wantVerificationErr: false, + }, + { + name: "found, would be verified if not for timeout", + s: Scanner{client: common.SaneHttpClientTimeOut(1 * time.Microsecond)}, + args: args{ + ctx: context.Background(), + data: []byte(fmt.Sprintf("You can find a endorlabs key %s and endorlabs secret %s within", key, secret)), + verify: true, + }, + want: []detectors.Result{ + { + DetectorType: detectorspb.DetectorType_EndorLabs, + Verified: false, + }, + { + DetectorType: detectorspb.DetectorType_EndorLabs, + Verified: false, + }, + }, + wantErr: false, + wantVerificationErr: true, + }, + { + name: "found, verified but unexpected api surface", + s: Scanner{client: common.ConstantResponseHttpClient(404, "")}, + args: args{ + ctx: context.Background(), + data: []byte(fmt.Sprintf("You can find a endorlabs key %s and endorlabs secret %s within", key, secret)), + verify: true, + }, + want: []detectors.Result{ + { + DetectorType: detectorspb.DetectorType_EndorLabs, + Verified: false, + }, + { + DetectorType: detectorspb.DetectorType_EndorLabs, + Verified: false, + }, + }, + wantErr: false, + wantVerificationErr: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := tt.s.FromData(tt.args.ctx, tt.args.verify, tt.args.data) + if (err != nil) != tt.wantErr { + t.Errorf("Endorlabs.FromData() error = %v, wantErr %v", err, tt.wantErr) + return + } + 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.Fatalf("wantVerificationError = %v, verification error = %v", tt.wantVerificationErr, got[i].VerificationError()) + } + } + ignoreOpts := cmpopts.IgnoreFields(detectors.Result{}, "Raw", "RawV2", "verificationError") + sortOpts := cmpopts.SortSlices(func(a, b []detectors.Result) bool { + return string(a[0].Raw) < string(b[0].Raw) + }) + if diff := cmp.Diff(got, tt.want, ignoreOpts, sortOpts); diff != "" { + t.Errorf("Endorlabs.FromData() %s diff: (-got +want)\n%s", tt.name, diff) + } + }) + } +} + +func BenchmarkFromData(benchmark *testing.B) { + ctx := context.Background() + s := Scanner{} + for name, data := range detectors.MustGetBenchmarkData() { + benchmark.Run(name, func(b *testing.B) { + b.ResetTimer() + for n := 0; n < b.N; n++ { + _, err := s.FromData(ctx, false, data) + if err != nil { + b.Fatal(err) + } + } + }) + } +} diff --git a/pkg/detectors/endorlabs/endorlabs_test.go b/pkg/detectors/endorlabs/endorlabs_test.go index b4565b566a52..ecb46265a36e 100644 --- a/pkg/detectors/endorlabs/endorlabs_test.go +++ b/pkg/detectors/endorlabs/endorlabs_test.go @@ -1,21 +1,11 @@ -//go:build detectors -// +build detectors - package endorlabs 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/engine/ahocorasick" - "github.com/trufflesecurity/trufflehog/v3/pkg/pb/detectorspb" + "testing" ) func TestEndorlabs_Pattern(t *testing.T) { @@ -81,167 +71,3 @@ func TestEndorlabs_Pattern(t *testing.T) { }) } } - -func TestEndorlabs_FromChunk(t *testing.T) { - ctx, cancel := context.WithTimeout(context.Background(), time.Second*5) - defer cancel() - testSecrets, err := common.GetSecret(ctx, "trufflehog-testing", "detectors5") - if err != nil { - t.Fatalf("could not get test secrets from GCP: %s", err) - } - key := testSecrets.MustGetField("ENDOR_KEY") - secret := testSecrets.MustGetField("ENDOR_SECRET") - inactiveKey := testSecrets.MustGetField("ENDOR_KEY_INACTIVE") - inactiveSecret := testSecrets.MustGetField("ENDOR_SECRET_INACTIVE") - - 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", - s: Scanner{}, - args: args{ - ctx: context.Background(), - data: []byte(fmt.Sprintf("You can find a endorlabs key %s and endorlabs secret %s within", key, secret)), - verify: true, - }, - want: []detectors.Result{ - { - DetectorType: detectorspb.DetectorType_EndorLabs, - Verified: true, - }, - { - DetectorType: detectorspb.DetectorType_EndorLabs, - Verified: false, - }, - }, - wantErr: false, - wantVerificationErr: false, - }, - { - name: "found, unverified", - s: Scanner{}, - args: args{ - ctx: context.Background(), - data: []byte(fmt.Sprintf("You can find a endorlabs key %s and endorlabs secret %s within but not valid", inactiveKey, inactiveSecret)), // the secret would satisfy the regex but not pass validation - verify: true, - }, - want: []detectors.Result{ - { - DetectorType: detectorspb.DetectorType_EndorLabs, - Verified: false, - }, - { - DetectorType: detectorspb.DetectorType_EndorLabs, - Verified: false, - }, - }, - wantErr: false, - wantVerificationErr: false, - }, - { - name: "not found", - s: Scanner{}, - args: args{ - ctx: context.Background(), - data: []byte("You cannot find the secret within"), - verify: true, - }, - want: nil, - wantErr: false, - wantVerificationErr: false, - }, - { - name: "found, would be verified if not for timeout", - s: Scanner{client: common.SaneHttpClientTimeOut(1 * time.Microsecond)}, - args: args{ - ctx: context.Background(), - data: []byte(fmt.Sprintf("You can find a endorlabs key %s and endorlabs secret %s within", key, secret)), - verify: true, - }, - want: []detectors.Result{ - { - DetectorType: detectorspb.DetectorType_EndorLabs, - Verified: false, - }, - { - DetectorType: detectorspb.DetectorType_EndorLabs, - Verified: false, - }, - }, - wantErr: false, - wantVerificationErr: true, - }, - { - name: "found, verified but unexpected api surface", - s: Scanner{client: common.ConstantResponseHttpClient(404, "")}, - args: args{ - ctx: context.Background(), - data: []byte(fmt.Sprintf("You can find a endorlabs key %s and endorlabs secret %s within", key, secret)), - verify: true, - }, - want: []detectors.Result{ - { - DetectorType: detectorspb.DetectorType_EndorLabs, - Verified: false, - }, - { - DetectorType: detectorspb.DetectorType_EndorLabs, - Verified: false, - }, - }, - wantErr: false, - wantVerificationErr: true, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - got, err := tt.s.FromData(tt.args.ctx, tt.args.verify, tt.args.data) - if (err != nil) != tt.wantErr { - t.Errorf("Endorlabs.FromData() error = %v, wantErr %v", err, tt.wantErr) - return - } - 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.Fatalf("wantVerificationError = %v, verification error = %v", tt.wantVerificationErr, got[i].VerificationError()) - } - } - ignoreOpts := cmpopts.IgnoreFields(detectors.Result{}, "Raw", "RawV2", "verificationError") - sortOpts := cmpopts.SortSlices(func(a, b []detectors.Result) bool { - return string(a[0].Raw) < string(b[0].Raw) - }) - if diff := cmp.Diff(got, tt.want, ignoreOpts, sortOpts); diff != "" { - t.Errorf("Endorlabs.FromData() %s diff: (-got +want)\n%s", tt.name, diff) - } - }) - } -} - -func BenchmarkFromData(benchmark *testing.B) { - ctx := context.Background() - s := Scanner{} - for name, data := range detectors.MustGetBenchmarkData() { - benchmark.Run(name, func(b *testing.B) { - b.ResetTimer() - for n := 0; n < b.N; n++ { - _, err := s.FromData(ctx, false, data) - if err != nil { - b.Fatal(err) - } - } - }) - } -} diff --git a/pkg/detectors/eraser/eraser_integration_test.go b/pkg/detectors/eraser/eraser_integration_test.go new file mode 100644 index 000000000000..6827f6e955ed --- /dev/null +++ b/pkg/detectors/eraser/eraser_integration_test.go @@ -0,0 +1,161 @@ +//go:build detectors +// +build detectors + +package eraser + +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 TestEraser_FromChunk(t *testing.T) { + ctx, cancel := context.WithTimeout(context.Background(), time.Second*5) + defer cancel() + testSecrets, err := common.GetSecret(ctx, "trufflehog-testing", "detectors5") + if err != nil { + t.Fatalf("could not get test secrets from GCP: %s", err) + } + secret := testSecrets.MustGetField("ERASER") + inactiveSecret := testSecrets.MustGetField("ERASER_INACTIVE") + + 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", + s: Scanner{}, + args: args{ + ctx: context.Background(), + data: []byte(fmt.Sprintf("You can find a eraser secret %s within", secret)), + verify: true, + }, + want: []detectors.Result{ + { + DetectorType: detectorspb.DetectorType_Eraser, + Verified: true, + }, + }, + wantErr: false, + wantVerificationErr: false, + }, + { + name: "found, unverified", + s: Scanner{}, + args: args{ + ctx: context.Background(), + data: []byte(fmt.Sprintf("You can find a eraser secret %s within but not valid", inactiveSecret)), // the secret would satisfy the regex but not pass validation + verify: true, + }, + want: []detectors.Result{ + { + DetectorType: detectorspb.DetectorType_Eraser, + Verified: false, + }, + }, + wantErr: false, + wantVerificationErr: false, + }, + { + name: "not found", + s: Scanner{}, + args: args{ + ctx: context.Background(), + data: []byte("You cannot find the secret within"), + verify: true, + }, + want: nil, + wantErr: false, + wantVerificationErr: false, + }, + { + name: "found, would be verified if not for timeout", + s: Scanner{client: common.SaneHttpClientTimeOut(1 * time.Microsecond)}, + args: args{ + ctx: context.Background(), + data: []byte(fmt.Sprintf("You can find a eraser secret %s within", secret)), + verify: true, + }, + want: []detectors.Result{ + { + DetectorType: detectorspb.DetectorType_Eraser, + Verified: false, + }, + }, + wantErr: false, + wantVerificationErr: true, + }, + { + name: "found, verified but unexpected api surface", + s: Scanner{client: common.ConstantResponseHttpClient(500, "")}, + args: args{ + ctx: context.Background(), + data: []byte(fmt.Sprintf("You can find a eraser secret %s within", secret)), + verify: true, + }, + want: []detectors.Result{ + { + DetectorType: detectorspb.DetectorType_Eraser, + Verified: false, + }, + }, + wantErr: false, + wantVerificationErr: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := tt.s.FromData(tt.args.ctx, tt.args.verify, tt.args.data) + if (err != nil) != tt.wantErr { + t.Errorf("Eraser.FromData() error = %v, wantErr %v", err, tt.wantErr) + return + } + 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.Fatalf("wantVerificationError = %v, verification error = %v", tt.wantVerificationErr, got[i].VerificationError()) + } + } + ignoreOpts := cmpopts.IgnoreFields(detectors.Result{}, "Raw", "verificationError") + if diff := cmp.Diff(got, tt.want, ignoreOpts); diff != "" { + t.Errorf("Eraser.FromData() %s diff: (-got +want)\n%s", tt.name, diff) + } + }) + } +} + +func BenchmarkFromData(benchmark *testing.B) { + ctx := context.Background() + s := Scanner{} + for name, data := range detectors.MustGetBenchmarkData() { + benchmark.Run(name, func(b *testing.B) { + b.ResetTimer() + for n := 0; n < b.N; n++ { + _, err := s.FromData(ctx, false, data) + if err != nil { + b.Fatal(err) + } + } + }) + } +} diff --git a/pkg/detectors/eraser/eraser_test.go b/pkg/detectors/eraser/eraser_test.go index f1e574fe1c69..af28bd827e10 100644 --- a/pkg/detectors/eraser/eraser_test.go +++ b/pkg/detectors/eraser/eraser_test.go @@ -1,21 +1,11 @@ -//go:build detectors -// +build detectors - package eraser 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/engine/ahocorasick" - "github.com/trufflesecurity/trufflehog/v3/pkg/pb/detectorspb" + "testing" ) func TestEraser_Pattern(t *testing.T) { @@ -75,146 +65,3 @@ func TestEraser_Pattern(t *testing.T) { }) } } - -func TestEraser_FromChunk(t *testing.T) { - ctx, cancel := context.WithTimeout(context.Background(), time.Second*5) - defer cancel() - testSecrets, err := common.GetSecret(ctx, "trufflehog-testing", "detectors5") - if err != nil { - t.Fatalf("could not get test secrets from GCP: %s", err) - } - secret := testSecrets.MustGetField("ERASER") - inactiveSecret := testSecrets.MustGetField("ERASER_INACTIVE") - - 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", - s: Scanner{}, - args: args{ - ctx: context.Background(), - data: []byte(fmt.Sprintf("You can find a eraser secret %s within", secret)), - verify: true, - }, - want: []detectors.Result{ - { - DetectorType: detectorspb.DetectorType_Eraser, - Verified: true, - }, - }, - wantErr: false, - wantVerificationErr: false, - }, - { - name: "found, unverified", - s: Scanner{}, - args: args{ - ctx: context.Background(), - data: []byte(fmt.Sprintf("You can find a eraser secret %s within but not valid", inactiveSecret)), // the secret would satisfy the regex but not pass validation - verify: true, - }, - want: []detectors.Result{ - { - DetectorType: detectorspb.DetectorType_Eraser, - Verified: false, - }, - }, - wantErr: false, - wantVerificationErr: false, - }, - { - name: "not found", - s: Scanner{}, - args: args{ - ctx: context.Background(), - data: []byte("You cannot find the secret within"), - verify: true, - }, - want: nil, - wantErr: false, - wantVerificationErr: false, - }, - { - name: "found, would be verified if not for timeout", - s: Scanner{client: common.SaneHttpClientTimeOut(1 * time.Microsecond)}, - args: args{ - ctx: context.Background(), - data: []byte(fmt.Sprintf("You can find a eraser secret %s within", secret)), - verify: true, - }, - want: []detectors.Result{ - { - DetectorType: detectorspb.DetectorType_Eraser, - Verified: false, - }, - }, - wantErr: false, - wantVerificationErr: true, - }, - { - name: "found, verified but unexpected api surface", - s: Scanner{client: common.ConstantResponseHttpClient(500, "")}, - args: args{ - ctx: context.Background(), - data: []byte(fmt.Sprintf("You can find a eraser secret %s within", secret)), - verify: true, - }, - want: []detectors.Result{ - { - DetectorType: detectorspb.DetectorType_Eraser, - Verified: false, - }, - }, - wantErr: false, - wantVerificationErr: true, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - got, err := tt.s.FromData(tt.args.ctx, tt.args.verify, tt.args.data) - if (err != nil) != tt.wantErr { - t.Errorf("Eraser.FromData() error = %v, wantErr %v", err, tt.wantErr) - return - } - 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.Fatalf("wantVerificationError = %v, verification error = %v", tt.wantVerificationErr, got[i].VerificationError()) - } - } - ignoreOpts := cmpopts.IgnoreFields(detectors.Result{}, "Raw", "verificationError") - if diff := cmp.Diff(got, tt.want, ignoreOpts); diff != "" { - t.Errorf("Eraser.FromData() %s diff: (-got +want)\n%s", tt.name, diff) - } - }) - } -} - -func BenchmarkFromData(benchmark *testing.B) { - ctx := context.Background() - s := Scanner{} - for name, data := range detectors.MustGetBenchmarkData() { - benchmark.Run(name, func(b *testing.B) { - b.ResetTimer() - for n := 0; n < b.N; n++ { - _, err := s.FromData(ctx, false, data) - if err != nil { - b.Fatal(err) - } - } - }) - } -} diff --git a/pkg/detectors/gcpapplicationdefaultcredentials/gcpapplicationdefaultcredentials_integration_test.go b/pkg/detectors/gcpapplicationdefaultcredentials/gcpapplicationdefaultcredentials_integration_test.go new file mode 100644 index 000000000000..501ec66b44d3 --- /dev/null +++ b/pkg/detectors/gcpapplicationdefaultcredentials/gcpapplicationdefaultcredentials_integration_test.go @@ -0,0 +1,161 @@ +//go:build detectors +// +build detectors + +package gcpapplicationdefaultcredentials + +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 TestGcpapplicationdefaultcredentials_FromChunk(t *testing.T) { + ctx, cancel := context.WithTimeout(context.Background(), time.Second*5) + defer cancel() + testSecrets, err := common.GetSecret(ctx, "trufflehog-testing", "detectors5") + if err != nil { + t.Fatalf("could not get test secrets from GCP: %s", err) + } + secret := testSecrets.MustGetField("GCPAPPLICATIONDEFAULTCREDENTIALS") + inactiveSecret := testSecrets.MustGetField("GCPAPPLICATIONDEFAULTCREDENTIALS_INACTIVE") + + 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", + s: Scanner{}, + args: args{ + ctx: context.Background(), + data: []byte(fmt.Sprintf("You can find a gcpapplicationdefaultcredentials secret %s within", secret)), + verify: true, + }, + want: []detectors.Result{ + { + DetectorType: detectorspb.DetectorType_GCPApplicationDefaultCredentials, + Verified: true, + }, + }, + wantErr: false, + wantVerificationErr: false, + }, + { + name: "found, unverified", + s: Scanner{}, + args: args{ + ctx: context.Background(), + data: []byte(fmt.Sprintf("You can find a gcpapplicationdefaultcredentials secret %s within but not valid", inactiveSecret)), // the secret would satisfy the regex but not pass validation + verify: true, + }, + want: []detectors.Result{ + { + DetectorType: detectorspb.DetectorType_GCPApplicationDefaultCredentials, + Verified: false, + }, + }, + wantErr: false, + wantVerificationErr: false, + }, + { + name: "not found", + s: Scanner{}, + args: args{ + ctx: context.Background(), + data: []byte("You cannot find the secret within"), + verify: true, + }, + want: nil, + wantErr: false, + wantVerificationErr: false, + }, + { + name: "found, would be verified if not for timeout", + s: Scanner{client: common.SaneHttpClientTimeOut(1 * time.Microsecond)}, + args: args{ + ctx: context.Background(), + data: []byte(fmt.Sprintf("You can find a gcpapplicationdefaultcredentials secret %s within", secret)), + verify: true, + }, + want: []detectors.Result{ + { + DetectorType: detectorspb.DetectorType_GCPApplicationDefaultCredentials, + Verified: false, + }, + }, + wantErr: false, + wantVerificationErr: true, + }, + { + name: "found, verified but unexpected api surface", + s: Scanner{client: common.ConstantResponseHttpClient(404, "")}, + args: args{ + ctx: context.Background(), + data: []byte(fmt.Sprintf("You can find a gcpapplicationdefaultcredentials secret %s within", secret)), + verify: true, + }, + want: []detectors.Result{ + { + DetectorType: detectorspb.DetectorType_GCPApplicationDefaultCredentials, + Verified: false, + }, + }, + wantErr: false, + wantVerificationErr: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := tt.s.FromData(tt.args.ctx, tt.args.verify, tt.args.data) + if (err != nil) != tt.wantErr { + t.Errorf("Gcpapplicationdefaultcredentials.FromData() error = %v, wantErr %v", err, tt.wantErr) + return + } + 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.Fatalf("wantVerificationError = %v, verification error = %v", tt.wantVerificationErr, got[i].VerificationError()) + } + } + ignoreOpts := cmpopts.IgnoreFields(detectors.Result{}, "Raw", "verificationError") + if diff := cmp.Diff(got, tt.want, ignoreOpts); diff != "" { + t.Errorf("Gcpapplicationdefaultcredentials.FromData() %s diff: (-got +want)\n%s", tt.name, diff) + } + }) + } +} + +func BenchmarkFromData(benchmark *testing.B) { + ctx := context.Background() + s := Scanner{} + for name, data := range detectors.MustGetBenchmarkData() { + benchmark.Run(name, func(b *testing.B) { + b.ResetTimer() + for n := 0; n < b.N; n++ { + _, err := s.FromData(ctx, false, data) + if err != nil { + b.Fatal(err) + } + } + }) + } +} diff --git a/pkg/detectors/gcpapplicationdefaultcredentials/gcpapplicationdefaultcredentials_test.go b/pkg/detectors/gcpapplicationdefaultcredentials/gcpapplicationdefaultcredentials_test.go index c161e420a999..4d77c47ebcc8 100644 --- a/pkg/detectors/gcpapplicationdefaultcredentials/gcpapplicationdefaultcredentials_test.go +++ b/pkg/detectors/gcpapplicationdefaultcredentials/gcpapplicationdefaultcredentials_test.go @@ -1,25 +1,11 @@ -//go:build detectors -// +build detectors - package gcpapplicationdefaultcredentials 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/engine/ahocorasick" - "github.com/trufflesecurity/trufflehog/v3/pkg/pb/detectorspb" -) - -var ( - validTestString = `{'client_id': '191375729402-oiuj2498ry3497gjveoierj8294jfj41.apps.googleusercontent.com', 'client_secret': 'z-OIFJWEOIJGWER91834325R', 'refresh_token': '1//0_joijgor3i4ut98579862709342j3kjJOIE02834jijfewoifjowiejfhghyzznfoiwejfwnvuhewiufnwinciwu_-o2i3jjfcc', 'type': 'authorized_user'}` + "testing" ) func TestGcpapplicationdefaultcredentials_Pattern(t *testing.T) { @@ -84,146 +70,3 @@ func TestGcpapplicationdefaultcredentials_Pattern(t *testing.T) { }) } } - -func TestGcpapplicationdefaultcredentials_FromChunk(t *testing.T) { - ctx, cancel := context.WithTimeout(context.Background(), time.Second*5) - defer cancel() - testSecrets, err := common.GetSecret(ctx, "trufflehog-testing", "detectors5") - if err != nil { - t.Fatalf("could not get test secrets from GCP: %s", err) - } - secret := testSecrets.MustGetField("GCPAPPLICATIONDEFAULTCREDENTIALS") - inactiveSecret := testSecrets.MustGetField("GCPAPPLICATIONDEFAULTCREDENTIALS_INACTIVE") - - 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", - s: Scanner{}, - args: args{ - ctx: context.Background(), - data: []byte(fmt.Sprintf("You can find a gcpapplicationdefaultcredentials secret %s within", secret)), - verify: true, - }, - want: []detectors.Result{ - { - DetectorType: detectorspb.DetectorType_GCPApplicationDefaultCredentials, - Verified: true, - }, - }, - wantErr: false, - wantVerificationErr: false, - }, - { - name: "found, unverified", - s: Scanner{}, - args: args{ - ctx: context.Background(), - data: []byte(fmt.Sprintf("You can find a gcpapplicationdefaultcredentials secret %s within but not valid", inactiveSecret)), // the secret would satisfy the regex but not pass validation - verify: true, - }, - want: []detectors.Result{ - { - DetectorType: detectorspb.DetectorType_GCPApplicationDefaultCredentials, - Verified: false, - }, - }, - wantErr: false, - wantVerificationErr: false, - }, - { - name: "not found", - s: Scanner{}, - args: args{ - ctx: context.Background(), - data: []byte("You cannot find the secret within"), - verify: true, - }, - want: nil, - wantErr: false, - wantVerificationErr: false, - }, - { - name: "found, would be verified if not for timeout", - s: Scanner{client: common.SaneHttpClientTimeOut(1 * time.Microsecond)}, - args: args{ - ctx: context.Background(), - data: []byte(fmt.Sprintf("You can find a gcpapplicationdefaultcredentials secret %s within", secret)), - verify: true, - }, - want: []detectors.Result{ - { - DetectorType: detectorspb.DetectorType_GCPApplicationDefaultCredentials, - Verified: false, - }, - }, - wantErr: false, - wantVerificationErr: true, - }, - { - name: "found, verified but unexpected api surface", - s: Scanner{client: common.ConstantResponseHttpClient(404, "")}, - args: args{ - ctx: context.Background(), - data: []byte(fmt.Sprintf("You can find a gcpapplicationdefaultcredentials secret %s within", secret)), - verify: true, - }, - want: []detectors.Result{ - { - DetectorType: detectorspb.DetectorType_GCPApplicationDefaultCredentials, - Verified: false, - }, - }, - wantErr: false, - wantVerificationErr: true, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - got, err := tt.s.FromData(tt.args.ctx, tt.args.verify, tt.args.data) - if (err != nil) != tt.wantErr { - t.Errorf("Gcpapplicationdefaultcredentials.FromData() error = %v, wantErr %v", err, tt.wantErr) - return - } - 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.Fatalf("wantVerificationError = %v, verification error = %v", tt.wantVerificationErr, got[i].VerificationError()) - } - } - ignoreOpts := cmpopts.IgnoreFields(detectors.Result{}, "Raw", "verificationError") - if diff := cmp.Diff(got, tt.want, ignoreOpts); diff != "" { - t.Errorf("Gcpapplicationdefaultcredentials.FromData() %s diff: (-got +want)\n%s", tt.name, diff) - } - }) - } -} - -func BenchmarkFromData(benchmark *testing.B) { - ctx := context.Background() - s := Scanner{} - for name, data := range detectors.MustGetBenchmarkData() { - benchmark.Run(name, func(b *testing.B) { - b.ResetTimer() - for n := 0; n < b.N; n++ { - _, err := s.FromData(ctx, false, data) - if err != nil { - b.Fatal(err) - } - } - }) - } -} diff --git a/pkg/detectors/groq/groq_integration_test.go b/pkg/detectors/groq/groq_integration_test.go new file mode 100644 index 000000000000..fb287cf2c0df --- /dev/null +++ b/pkg/detectors/groq/groq_integration_test.go @@ -0,0 +1,161 @@ +//go:build detectors +// +build detectors + +package groq + +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 TestGroq_FromChunk(t *testing.T) { + ctx, cancel := context.WithTimeout(context.Background(), time.Second*5) + defer cancel() + testSecrets, err := common.GetSecret(ctx, "trufflehog-testing", "detectors5") + if err != nil { + t.Fatalf("could not get test secrets from GCP: %s", err) + } + secret := testSecrets.MustGetField("GROQ") + inactiveSecret := testSecrets.MustGetField("GROQ_INACTIVE") + + 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", + s: Scanner{}, + args: args{ + ctx: context.Background(), + data: []byte(fmt.Sprintf("You can find a groq secret %s within", secret)), + verify: true, + }, + want: []detectors.Result{ + { + DetectorType: detectorspb.DetectorType_Groq, + Verified: true, + }, + }, + wantErr: false, + wantVerificationErr: false, + }, + { + name: "found, unverified", + s: Scanner{}, + args: args{ + ctx: context.Background(), + data: []byte(fmt.Sprintf("You can find a groq secret %s within but not valid", inactiveSecret)), // the secret would satisfy the regex but not pass validation + verify: true, + }, + want: []detectors.Result{ + { + DetectorType: detectorspb.DetectorType_Groq, + Verified: false, + }, + }, + wantErr: false, + wantVerificationErr: false, + }, + { + name: "not found", + s: Scanner{}, + args: args{ + ctx: context.Background(), + data: []byte("You cannot find the secret within"), + verify: true, + }, + want: nil, + wantErr: false, + wantVerificationErr: false, + }, + { + name: "found, would be verified if not for timeout", + s: Scanner{client: common.SaneHttpClientTimeOut(1 * time.Microsecond)}, + args: args{ + ctx: context.Background(), + data: []byte(fmt.Sprintf("You can find a groq secret %s within", secret)), + verify: true, + }, + want: []detectors.Result{ + { + DetectorType: detectorspb.DetectorType_Groq, + Verified: false, + }, + }, + wantErr: false, + wantVerificationErr: true, + }, + { + name: "found, verified but unexpected api surface", + s: Scanner{client: common.ConstantResponseHttpClient(404, "")}, + args: args{ + ctx: context.Background(), + data: []byte(fmt.Sprintf("You can find a groq secret %s within", secret)), + verify: true, + }, + want: []detectors.Result{ + { + DetectorType: detectorspb.DetectorType_Groq, + Verified: false, + }, + }, + wantErr: false, + wantVerificationErr: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := tt.s.FromData(tt.args.ctx, tt.args.verify, tt.args.data) + if (err != nil) != tt.wantErr { + t.Errorf("Groq.FromData() error = %v, wantErr %v", err, tt.wantErr) + return + } + 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.Fatalf("wantVerificationError = %v, verification error = %v", tt.wantVerificationErr, got[i].VerificationError()) + } + } + ignoreOpts := cmpopts.IgnoreFields(detectors.Result{}, "Raw", "verificationError") + if diff := cmp.Diff(got, tt.want, ignoreOpts); diff != "" { + t.Errorf("Groq.FromData() %s diff: (-got +want)\n%s", tt.name, diff) + } + }) + } +} + +func BenchmarkFromData(benchmark *testing.B) { + ctx := context.Background() + s := Scanner{} + for name, data := range detectors.MustGetBenchmarkData() { + benchmark.Run(name, func(b *testing.B) { + b.ResetTimer() + for n := 0; n < b.N; n++ { + _, err := s.FromData(ctx, false, data) + if err != nil { + b.Fatal(err) + } + } + }) + } +} diff --git a/pkg/detectors/groq/groq_test.go b/pkg/detectors/groq/groq_test.go index 08d78e1885ec..8c2fbc6aa77b 100644 --- a/pkg/detectors/groq/groq_test.go +++ b/pkg/detectors/groq/groq_test.go @@ -1,21 +1,11 @@ -//go:build detectors -// +build detectors - package groq 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/engine/ahocorasick" - "github.com/trufflesecurity/trufflehog/v3/pkg/pb/detectorspb" + "testing" ) func TestGroq_Pattern(t *testing.T) { @@ -75,146 +65,3 @@ func TestGroq_Pattern(t *testing.T) { }) } } - -func TestGroq_FromChunk(t *testing.T) { - ctx, cancel := context.WithTimeout(context.Background(), time.Second*5) - defer cancel() - testSecrets, err := common.GetSecret(ctx, "trufflehog-testing", "detectors5") - if err != nil { - t.Fatalf("could not get test secrets from GCP: %s", err) - } - secret := testSecrets.MustGetField("GROQ") - inactiveSecret := testSecrets.MustGetField("GROQ_INACTIVE") - - 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", - s: Scanner{}, - args: args{ - ctx: context.Background(), - data: []byte(fmt.Sprintf("You can find a groq secret %s within", secret)), - verify: true, - }, - want: []detectors.Result{ - { - DetectorType: detectorspb.DetectorType_Groq, - Verified: true, - }, - }, - wantErr: false, - wantVerificationErr: false, - }, - { - name: "found, unverified", - s: Scanner{}, - args: args{ - ctx: context.Background(), - data: []byte(fmt.Sprintf("You can find a groq secret %s within but not valid", inactiveSecret)), // the secret would satisfy the regex but not pass validation - verify: true, - }, - want: []detectors.Result{ - { - DetectorType: detectorspb.DetectorType_Groq, - Verified: false, - }, - }, - wantErr: false, - wantVerificationErr: false, - }, - { - name: "not found", - s: Scanner{}, - args: args{ - ctx: context.Background(), - data: []byte("You cannot find the secret within"), - verify: true, - }, - want: nil, - wantErr: false, - wantVerificationErr: false, - }, - { - name: "found, would be verified if not for timeout", - s: Scanner{client: common.SaneHttpClientTimeOut(1 * time.Microsecond)}, - args: args{ - ctx: context.Background(), - data: []byte(fmt.Sprintf("You can find a groq secret %s within", secret)), - verify: true, - }, - want: []detectors.Result{ - { - DetectorType: detectorspb.DetectorType_Groq, - Verified: false, - }, - }, - wantErr: false, - wantVerificationErr: true, - }, - { - name: "found, verified but unexpected api surface", - s: Scanner{client: common.ConstantResponseHttpClient(404, "")}, - args: args{ - ctx: context.Background(), - data: []byte(fmt.Sprintf("You can find a groq secret %s within", secret)), - verify: true, - }, - want: []detectors.Result{ - { - DetectorType: detectorspb.DetectorType_Groq, - Verified: false, - }, - }, - wantErr: false, - wantVerificationErr: true, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - got, err := tt.s.FromData(tt.args.ctx, tt.args.verify, tt.args.data) - if (err != nil) != tt.wantErr { - t.Errorf("Groq.FromData() error = %v, wantErr %v", err, tt.wantErr) - return - } - 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.Fatalf("wantVerificationError = %v, verification error = %v", tt.wantVerificationErr, got[i].VerificationError()) - } - } - ignoreOpts := cmpopts.IgnoreFields(detectors.Result{}, "Raw", "verificationError") - if diff := cmp.Diff(got, tt.want, ignoreOpts); diff != "" { - t.Errorf("Groq.FromData() %s diff: (-got +want)\n%s", tt.name, diff) - } - }) - } -} - -func BenchmarkFromData(benchmark *testing.B) { - ctx := context.Background() - s := Scanner{} - for name, data := range detectors.MustGetBenchmarkData() { - benchmark.Run(name, func(b *testing.B) { - b.ResetTimer() - for n := 0; n < b.N; n++ { - _, err := s.FromData(ctx, false, data) - if err != nil { - b.Fatal(err) - } - } - }) - } -} diff --git a/pkg/detectors/intra42/intra42_integration_test.go b/pkg/detectors/intra42/intra42_integration_test.go new file mode 100644 index 000000000000..3bc7f28fb550 --- /dev/null +++ b/pkg/detectors/intra42/intra42_integration_test.go @@ -0,0 +1,159 @@ +//go:build detectors +// +build detectors + +package intra42 + +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 TestIntra42_FromChunk(t *testing.T) { + ctx, cancel := context.WithTimeout(context.Background(), time.Second*10) + defer cancel() + testSecrets, err := common.GetSecret(ctx, "trufflehog-testing", "detectors5") + if err != nil { + t.Fatalf("could not get test secrets from GCP: %s", err) + } + secret := testSecrets.MustGetField("INTRA42_SECRET") + id := testSecrets.MustGetField("INTRA42_ID") + inactiveSecret := testSecrets.MustGetField("INTRA42_INACTIVE") + + 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", + s: Scanner{}, + args: args{ + ctx: context.Background(), + data: []byte(fmt.Sprintf("You can find an intra42 secret %s within intra42 %s", secret, id)), + verify: true, + }, + want: []detectors.Result{ + { + DetectorType: detectorspb.DetectorType_Intra42, + Verified: true, + }, + }, + wantErr: false, + }, + { + name: "found, would be verified if not for timeout", + s: Scanner{client: common.SaneHttpClientTimeOut(1 * time.Microsecond)}, + args: args{ + ctx: context.Background(), + data: []byte(fmt.Sprintf("You can find an intra42 secret %s within intra42 %s", secret, id)), + verify: true, + }, + want: []detectors.Result{ + { + DetectorType: detectorspb.DetectorType_Intra42, + Verified: false, + }, + }, + wantErr: false, + wantVerificationErr: true, + }, + { + name: "found, verified but unexpected api surface", + s: Scanner{client: common.ConstantResponseHttpClient(404, "")}, + args: args{ + ctx: context.Background(), + data: []byte(fmt.Sprintf("You can find an intra42 secret %s within intra42 %s", secret, id)), + verify: true, + }, + want: []detectors.Result{ + { + DetectorType: detectorspb.DetectorType_Intra42, + Verified: false, + }, + }, + wantErr: false, + wantVerificationErr: true, + }, + { + name: "found, unverified", + s: Scanner{}, + args: args{ + ctx: context.Background(), + data: []byte(fmt.Sprintf("You can find an intra42 secret %s within intra42 %s but not valid", inactiveSecret, id)), // the secret would satisfy the regex but not pass validation + verify: true, + }, + want: []detectors.Result{ + { + DetectorType: detectorspb.DetectorType_Intra42, + Verified: false, + }, + }, + wantErr: false, + }, + { + name: "not found", + s: Scanner{}, + args: args{ + ctx: context.Background(), + data: []byte("You cannot find the secret within"), + verify: true, + }, + want: nil, + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := tt.s.FromData(tt.args.ctx, tt.args.verify, tt.args.data) + if (err != nil) != tt.wantErr { + t.Errorf("Intra42.FromData() error = %v, wantErr %v", err, tt.wantErr) + return + } + 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("Intra42.FromData() verificationError = %v, wantVerificationErr %v", got[i].VerificationError(), tt.wantVerificationErr) + } + } + ignoreOpts := cmpopts.IgnoreFields(detectors.Result{}, "Raw", "verificationError") + if diff := cmp.Diff(got, tt.want, ignoreOpts); diff != "" { + t.Errorf("Intra42.FromData() %s diff: (-got +want)\n%s", tt.name, diff) + } + }) + } +} + +func BenchmarkFromData(benchmark *testing.B) { + ctx := context.Background() + s := Scanner{} + for name, data := range detectors.MustGetBenchmarkData() { + benchmark.Run(name, func(b *testing.B) { + b.ResetTimer() + for n := 0; n < b.N; n++ { + _, err := s.FromData(ctx, false, data) + if err != nil { + b.Fatal(err) + } + } + }) + } +} diff --git a/pkg/detectors/intra42/intra42_test.go b/pkg/detectors/intra42/intra42_test.go index bbbe6ae44192..3d00d1cbbb90 100644 --- a/pkg/detectors/intra42/intra42_test.go +++ b/pkg/detectors/intra42/intra42_test.go @@ -1,21 +1,11 @@ -//go:build detectors -// +build detectors - package intra42 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/engine/ahocorasick" - "github.com/trufflesecurity/trufflehog/v3/pkg/pb/detectorspb" + "testing" ) func TestIntra42_Pattern(t *testing.T) { @@ -80,144 +70,3 @@ intra_client_secret = 's-s4t2ud-d91c558a2ba6b47f60f690efc20a33d28c252d5bed840034 }) } } - -func TestIntra42_FromChunk(t *testing.T) { - ctx, cancel := context.WithTimeout(context.Background(), time.Second*10) - defer cancel() - testSecrets, err := common.GetSecret(ctx, "trufflehog-testing", "detectors5") - if err != nil { - t.Fatalf("could not get test secrets from GCP: %s", err) - } - secret := testSecrets.MustGetField("INTRA42_SECRET") - id := testSecrets.MustGetField("INTRA42_ID") - inactiveSecret := testSecrets.MustGetField("INTRA42_INACTIVE") - - 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", - s: Scanner{}, - args: args{ - ctx: context.Background(), - data: []byte(fmt.Sprintf("You can find an intra42 secret %s within intra42 %s", secret, id)), - verify: true, - }, - want: []detectors.Result{ - { - DetectorType: detectorspb.DetectorType_Intra42, - Verified: true, - }, - }, - wantErr: false, - }, - { - name: "found, would be verified if not for timeout", - s: Scanner{client: common.SaneHttpClientTimeOut(1 * time.Microsecond)}, - args: args{ - ctx: context.Background(), - data: []byte(fmt.Sprintf("You can find an intra42 secret %s within intra42 %s", secret, id)), - verify: true, - }, - want: []detectors.Result{ - { - DetectorType: detectorspb.DetectorType_Intra42, - Verified: false, - }, - }, - wantErr: false, - wantVerificationErr: true, - }, - { - name: "found, verified but unexpected api surface", - s: Scanner{client: common.ConstantResponseHttpClient(404, "")}, - args: args{ - ctx: context.Background(), - data: []byte(fmt.Sprintf("You can find an intra42 secret %s within intra42 %s", secret, id)), - verify: true, - }, - want: []detectors.Result{ - { - DetectorType: detectorspb.DetectorType_Intra42, - Verified: false, - }, - }, - wantErr: false, - wantVerificationErr: true, - }, - { - name: "found, unverified", - s: Scanner{}, - args: args{ - ctx: context.Background(), - data: []byte(fmt.Sprintf("You can find an intra42 secret %s within intra42 %s but not valid", inactiveSecret, id)), // the secret would satisfy the regex but not pass validation - verify: true, - }, - want: []detectors.Result{ - { - DetectorType: detectorspb.DetectorType_Intra42, - Verified: false, - }, - }, - wantErr: false, - }, - { - name: "not found", - s: Scanner{}, - args: args{ - ctx: context.Background(), - data: []byte("You cannot find the secret within"), - verify: true, - }, - want: nil, - wantErr: false, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - got, err := tt.s.FromData(tt.args.ctx, tt.args.verify, tt.args.data) - if (err != nil) != tt.wantErr { - t.Errorf("Intra42.FromData() error = %v, wantErr %v", err, tt.wantErr) - return - } - 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("Intra42.FromData() verificationError = %v, wantVerificationErr %v", got[i].VerificationError(), tt.wantVerificationErr) - } - } - ignoreOpts := cmpopts.IgnoreFields(detectors.Result{}, "Raw", "verificationError") - if diff := cmp.Diff(got, tt.want, ignoreOpts); diff != "" { - t.Errorf("Intra42.FromData() %s diff: (-got +want)\n%s", tt.name, diff) - } - }) - } -} - -func BenchmarkFromData(benchmark *testing.B) { - ctx := context.Background() - s := Scanner{} - for name, data := range detectors.MustGetBenchmarkData() { - benchmark.Run(name, func(b *testing.B) { - b.ResetTimer() - for n := 0; n < b.N; n++ { - _, err := s.FromData(ctx, false, data) - if err != nil { - b.Fatal(err) - } - } - }) - } -} diff --git a/pkg/detectors/larksuite/larksuite_integration_test.go b/pkg/detectors/larksuite/larksuite_integration_test.go new file mode 100644 index 000000000000..f0845c336425 --- /dev/null +++ b/pkg/detectors/larksuite/larksuite_integration_test.go @@ -0,0 +1,139 @@ +//go:build detectors +// +build detectors + +package larksuite + +import ( + "context" + "fmt" + "testing" + "time" + + "github.com/kylelemons/godebug/pretty" + "github.com/trufflesecurity/trufflehog/v3/pkg/common" + "github.com/trufflesecurity/trufflehog/v3/pkg/detectors" + "github.com/trufflesecurity/trufflehog/v3/pkg/pb/detectorspb" +) + +func TestLarksuite_FromChunk(t *testing.T) { + ctx, cancel := context.WithTimeout(context.Background(), time.Second*5) + defer cancel() + testSecrets, err := common.GetSecret(ctx, "trufflehog-testing", "detectors5") + if err != nil { + t.Fatalf("could not get test secrets from GCP: %s", err) + } + tenantToken := testSecrets.MustGetField("LARKSUITE_TENANT") + userToken := testSecrets.MustGetField("LARKSUITE_USER") + appToken := testSecrets.MustGetField("LARKSUITE_APP") + + type args struct { + ctx context.Context + data []byte + verify bool + } + tests := []struct { + name string + s Scanner + args args + want []detectors.Result + wantErr bool + }{ + { + name: "found tenant token, verified", + s: Scanner{}, + args: args{ + ctx: context.Background(), + data: []byte(fmt.Sprintf("You can find a larksuite token %s within", tenantToken)), + verify: true, + }, + want: []detectors.Result{ + { + DetectorType: detectorspb.DetectorType_LarkSuite, + Verified: true, + }, + }, + wantErr: false, + }, + { + name: "found user token, verified", + s: Scanner{}, + args: args{ + ctx: context.Background(), + data: []byte(fmt.Sprintf("You can find a larksuite token %s within", userToken)), + verify: true, + }, + want: []detectors.Result{ + { + DetectorType: detectorspb.DetectorType_LarkSuite, + Verified: true, + }, + }, + wantErr: false, + }, + { + name: "found app token, unverified", + s: Scanner{}, + args: args{ + ctx: context.Background(), + data: []byte(fmt.Sprintf("You can find a larksuite app %s within", appToken)), + verify: true, + }, + want: func() []detectors.Result { + r := detectors.Result{ + DetectorType: detectorspb.DetectorType_LarkSuite, + Verified: false, + } + r.SetVerificationError(fmt.Errorf("unexpected verification response code 99991668, message Invalid access token for authorization. Please make a request with token attached.")) + return []detectors.Result{r} + }(), + wantErr: false, + }, + { + name: "not found", + s: Scanner{}, + args: args{ + ctx: context.Background(), + data: []byte("You cannot find the secret within"), + verify: true, + }, + want: nil, + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + s := Scanner{} + got, err := s.FromData(tt.args.ctx, tt.args.verify, tt.args.data) + if (err != nil) != tt.wantErr { + t.Errorf("Larksuite.FromData() error = %v, wantErr %v", err, tt.wantErr) + return + } + for i := range got { + if len(got[i].Raw) == 0 { + t.Fatalf("no raw secret present: \n %+v", got[i]) + } + got[i].Raw = nil + got[i].ExtraData = nil + } + if diff := pretty.Compare(got, tt.want); diff != "" { + t.Errorf("Larksuite.FromData() %s diff: (-got +want)\n%s", tt.name, diff) + } + }) + } +} + +func BenchmarkFromData(benchmark *testing.B) { + ctx := context.Background() + s := Scanner{} + for name, data := range detectors.MustGetBenchmarkData() { + benchmark.Run(name, func(b *testing.B) { + b.ResetTimer() + for n := 0; n < b.N; n++ { + _, err := s.FromData(ctx, false, data) + if err != nil { + b.Fatal(err) + } + } + }) + } +} diff --git a/pkg/detectors/larksuite/larksuite_test.go b/pkg/detectors/larksuite/larksuite_test.go index 7210b097832c..0ee8dd0f64a5 100644 --- a/pkg/detectors/larksuite/larksuite_test.go +++ b/pkg/detectors/larksuite/larksuite_test.go @@ -1,20 +1,11 @@ -//go:build detectors -// +build detectors - package larksuite import ( "context" - "fmt" - "testing" - "time" - "github.com/google/go-cmp/cmp" - "github.com/kylelemons/godebug/pretty" - "github.com/trufflesecurity/trufflehog/v3/pkg/common" "github.com/trufflesecurity/trufflehog/v3/pkg/detectors" "github.com/trufflesecurity/trufflehog/v3/pkg/engine/ahocorasick" - "github.com/trufflesecurity/trufflehog/v3/pkg/pb/detectorspb" + "testing" ) func TestLarksuite_Pattern(t *testing.T) { @@ -84,126 +75,3 @@ func TestLarksuite_Pattern(t *testing.T) { }) } } - -func TestLarksuite_FromChunk(t *testing.T) { - ctx, cancel := context.WithTimeout(context.Background(), time.Second*5) - defer cancel() - testSecrets, err := common.GetSecret(ctx, "trufflehog-testing", "detectors5") - if err != nil { - t.Fatalf("could not get test secrets from GCP: %s", err) - } - tenantToken := testSecrets.MustGetField("LARKSUITE_TENANT") - userToken := testSecrets.MustGetField("LARKSUITE_USER") - appToken := testSecrets.MustGetField("LARKSUITE_APP") - - type args struct { - ctx context.Context - data []byte - verify bool - } - tests := []struct { - name string - s Scanner - args args - want []detectors.Result - wantErr bool - }{ - { - name: "found tenant token, verified", - s: Scanner{}, - args: args{ - ctx: context.Background(), - data: []byte(fmt.Sprintf("You can find a larksuite token %s within", tenantToken)), - verify: true, - }, - want: []detectors.Result{ - { - DetectorType: detectorspb.DetectorType_LarkSuite, - Verified: true, - }, - }, - wantErr: false, - }, - { - name: "found user token, verified", - s: Scanner{}, - args: args{ - ctx: context.Background(), - data: []byte(fmt.Sprintf("You can find a larksuite token %s within", userToken)), - verify: true, - }, - want: []detectors.Result{ - { - DetectorType: detectorspb.DetectorType_LarkSuite, - Verified: true, - }, - }, - wantErr: false, - }, - { - name: "found app token, unverified", - s: Scanner{}, - args: args{ - ctx: context.Background(), - data: []byte(fmt.Sprintf("You can find a larksuite app %s within", appToken)), - verify: true, - }, - want: func() []detectors.Result { - r := detectors.Result{ - DetectorType: detectorspb.DetectorType_LarkSuite, - Verified: false, - } - r.SetVerificationError(fmt.Errorf("unexpected verification response code 99991668, message Invalid access token for authorization. Please make a request with token attached.")) - return []detectors.Result{r} - }(), - wantErr: false, - }, - { - name: "not found", - s: Scanner{}, - args: args{ - ctx: context.Background(), - data: []byte("You cannot find the secret within"), - verify: true, - }, - want: nil, - wantErr: false, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - s := Scanner{} - got, err := s.FromData(tt.args.ctx, tt.args.verify, tt.args.data) - if (err != nil) != tt.wantErr { - t.Errorf("Larksuite.FromData() error = %v, wantErr %v", err, tt.wantErr) - return - } - for i := range got { - if len(got[i].Raw) == 0 { - t.Fatalf("no raw secret present: \n %+v", got[i]) - } - got[i].Raw = nil - got[i].ExtraData = nil - } - if diff := pretty.Compare(got, tt.want); diff != "" { - t.Errorf("Larksuite.FromData() %s diff: (-got +want)\n%s", tt.name, diff) - } - }) - } -} - -func BenchmarkFromData(benchmark *testing.B) { - ctx := context.Background() - s := Scanner{} - for name, data := range detectors.MustGetBenchmarkData() { - benchmark.Run(name, func(b *testing.B) { - b.ResetTimer() - for n := 0; n < b.N; n++ { - _, err := s.FromData(ctx, false, data) - if err != nil { - b.Fatal(err) - } - } - }) - } -} diff --git a/pkg/detectors/larksuiteapikey/larksuiteapikey_integration_test.go b/pkg/detectors/larksuiteapikey/larksuiteapikey_integration_test.go new file mode 100644 index 000000000000..c4ca9049ee2f --- /dev/null +++ b/pkg/detectors/larksuiteapikey/larksuiteapikey_integration_test.go @@ -0,0 +1,126 @@ +//go:build detectors +// +build detectors + +package larksuiteapikey + +import ( + "context" + "fmt" + "testing" + "time" + + "github.com/kylelemons/godebug/pretty" + "github.com/trufflesecurity/trufflehog/v3/pkg/common" + "github.com/trufflesecurity/trufflehog/v3/pkg/detectors" + "github.com/trufflesecurity/trufflehog/v3/pkg/pb/detectorspb" +) + +func TestLarksuiteApiKey_FromChunk(t *testing.T) { + ctx, cancel := context.WithTimeout(context.Background(), time.Second*5) + defer cancel() + testSecrets, err := common.GetSecret(ctx, "trufflehog-testing", "detectors5") + if err != nil { + t.Fatalf("could not get test secrets from GCP: %s", err) + } + id := testSecrets.MustGetField("LARKSUITE_APP_ID") + secret := testSecrets.MustGetField("LARKSUITE_APP_SECRET") + inactiveSecret := testSecrets.MustGetField("LARKSUITE_APP_SECRET_INACTIVE") + + type args struct { + ctx context.Context + data []byte + verify bool + } + tests := []struct { + name string + s Scanner + args args + want []detectors.Result + wantErr bool + }{ + { + name: "found verified", + s: Scanner{}, + args: args{ + ctx: context.Background(), + data: []byte(fmt.Sprintf("You can find a larksuite appid %s and secret %s within", id, secret)), + verify: true, + }, + want: []detectors.Result{ + { + DetectorType: detectorspb.DetectorType_LarkSuiteApiKey, + Verified: true, + Raw: []byte(id), + RawV2: []byte(id + secret), + }, + }, + wantErr: false, + }, + { + name: "found unverified", + s: Scanner{}, + args: args{ + ctx: context.Background(), + data: []byte(fmt.Sprintf("You can find a larksuite appid %s and larksuite secret %s within", id, inactiveSecret)), + verify: true, + }, + want: func() []detectors.Result { + r := detectors.Result{ + DetectorType: detectorspb.DetectorType_LarkSuiteApiKey, + Verified: false, + Raw: []byte(id), + RawV2: []byte(id + inactiveSecret), + } + r.SetVerificationError(fmt.Errorf("Verification failed code 10014, message app secret invalid")) + return []detectors.Result{r} + }(), + wantErr: false, + }, + { + name: "not found", + s: Scanner{}, + args: args{ + ctx: context.Background(), + data: []byte("You cannot find the secret within"), + verify: true, + }, + want: nil, + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + s := Scanner{} + got, err := s.FromData(tt.args.ctx, tt.args.verify, tt.args.data) + if (err != nil) != tt.wantErr { + t.Errorf("Larksuite.FromData() error = %v, wantErr %v", err, tt.wantErr) + return + } + for i := range got { + if len(got[i].Raw) == 0 { + t.Fatalf("no raw secret present: \n %+v", got[i]) + } + got[i].ExtraData = nil + } + if diff := pretty.Compare(got, tt.want); diff != "" { + t.Errorf("Larksuite.FromData() %s diff: (-got +want)\n%s", tt.name, diff) + } + }) + } +} + +func BenchmarkFromData(benchmark *testing.B) { + ctx := context.Background() + s := Scanner{} + for name, data := range detectors.MustGetBenchmarkData() { + benchmark.Run(name, func(b *testing.B) { + b.ResetTimer() + for n := 0; n < b.N; n++ { + _, err := s.FromData(ctx, false, data) + if err != nil { + b.Fatal(err) + } + } + }) + } +} diff --git a/pkg/detectors/larksuiteapikey/larksuiteapikey_test.go b/pkg/detectors/larksuiteapikey/larksuiteapikey_test.go index b2bfa35b20bd..234b586e17c8 100644 --- a/pkg/detectors/larksuiteapikey/larksuiteapikey_test.go +++ b/pkg/detectors/larksuiteapikey/larksuiteapikey_test.go @@ -1,20 +1,11 @@ -//go:build detectors -// +build detectors - package larksuiteapikey import ( "context" - "fmt" - "testing" - "time" - "github.com/google/go-cmp/cmp" - "github.com/kylelemons/godebug/pretty" - "github.com/trufflesecurity/trufflehog/v3/pkg/common" "github.com/trufflesecurity/trufflehog/v3/pkg/detectors" "github.com/trufflesecurity/trufflehog/v3/pkg/engine/ahocorasick" - "github.com/trufflesecurity/trufflehog/v3/pkg/pb/detectorspb" + "testing" ) func TestLarksuiteApiKey_Pattern(t *testing.T) { @@ -77,113 +68,3 @@ func TestLarksuiteApiKey_Pattern(t *testing.T) { }) } } - -func TestLarksuiteApiKey_FromChunk(t *testing.T) { - ctx, cancel := context.WithTimeout(context.Background(), time.Second*5) - defer cancel() - testSecrets, err := common.GetSecret(ctx, "trufflehog-testing", "detectors5") - if err != nil { - t.Fatalf("could not get test secrets from GCP: %s", err) - } - id := testSecrets.MustGetField("LARKSUITE_APP_ID") - secret := testSecrets.MustGetField("LARKSUITE_APP_SECRET") - inactiveSecret := testSecrets.MustGetField("LARKSUITE_APP_SECRET_INACTIVE") - - type args struct { - ctx context.Context - data []byte - verify bool - } - tests := []struct { - name string - s Scanner - args args - want []detectors.Result - wantErr bool - }{ - { - name: "found verified", - s: Scanner{}, - args: args{ - ctx: context.Background(), - data: []byte(fmt.Sprintf("You can find a larksuite appid %s and secret %s within", id, secret)), - verify: true, - }, - want: []detectors.Result{ - { - DetectorType: detectorspb.DetectorType_LarkSuiteApiKey, - Verified: true, - Raw: []byte(id), - RawV2: []byte(id + secret), - }, - }, - wantErr: false, - }, - { - name: "found unverified", - s: Scanner{}, - args: args{ - ctx: context.Background(), - data: []byte(fmt.Sprintf("You can find a larksuite appid %s and larksuite secret %s within", id, inactiveSecret)), - verify: true, - }, - want: func() []detectors.Result { - r := detectors.Result{ - DetectorType: detectorspb.DetectorType_LarkSuiteApiKey, - Verified: false, - Raw: []byte(id), - RawV2: []byte(id + inactiveSecret), - } - r.SetVerificationError(fmt.Errorf("Verification failed code 10014, message app secret invalid")) - return []detectors.Result{r} - }(), - wantErr: false, - }, - { - name: "not found", - s: Scanner{}, - args: args{ - ctx: context.Background(), - data: []byte("You cannot find the secret within"), - verify: true, - }, - want: nil, - wantErr: false, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - s := Scanner{} - got, err := s.FromData(tt.args.ctx, tt.args.verify, tt.args.data) - if (err != nil) != tt.wantErr { - t.Errorf("Larksuite.FromData() error = %v, wantErr %v", err, tt.wantErr) - return - } - for i := range got { - if len(got[i].Raw) == 0 { - t.Fatalf("no raw secret present: \n %+v", got[i]) - } - got[i].ExtraData = nil - } - if diff := pretty.Compare(got, tt.want); diff != "" { - t.Errorf("Larksuite.FromData() %s diff: (-got +want)\n%s", tt.name, diff) - } - }) - } -} - -func BenchmarkFromData(benchmark *testing.B) { - ctx := context.Background() - s := Scanner{} - for name, data := range detectors.MustGetBenchmarkData() { - benchmark.Run(name, func(b *testing.B) { - b.ResetTimer() - for n := 0; n < b.N; n++ { - _, err := s.FromData(ctx, false, data) - if err != nil { - b.Fatal(err) - } - } - }) - } -} diff --git a/pkg/detectors/maxmindlicense/v1/maxmindlicense_test.go b/pkg/detectors/maxmindlicense/v1/maxmindlicense_integration_test.go similarity index 100% rename from pkg/detectors/maxmindlicense/v1/maxmindlicense_test.go rename to pkg/detectors/maxmindlicense/v1/maxmindlicense_integration_test.go diff --git a/pkg/detectors/maxmindlicense/v2/maxmindlicense_v2_integration_test.go b/pkg/detectors/maxmindlicense/v2/maxmindlicense_v2_integration_test.go new file mode 100644 index 000000000000..9c919dc513eb --- /dev/null +++ b/pkg/detectors/maxmindlicense/v2/maxmindlicense_v2_integration_test.go @@ -0,0 +1,128 @@ +//go:build detectors +// +build detectors + +package maxmindlicense + +import ( + "context" + "fmt" + "testing" + "time" + + "github.com/kylelemons/godebug/pretty" + + "github.com/trufflesecurity/trufflehog/v3/pkg/common" + "github.com/trufflesecurity/trufflehog/v3/pkg/detectors" + "github.com/trufflesecurity/trufflehog/v3/pkg/pb/detectorspb" +) + +func TestMaxMindLicense(t *testing.T) { + ctx, cancel := context.WithTimeout(context.Background(), time.Second*5) + defer cancel() + testSecrets, err := common.GetSecret(ctx, "trufflehog-testing", "detectors3") + if err != nil { + t.Fatalf("could not get test secrets from GCP: %s", err) + } + secret := testSecrets.MustGetField("MAXMIND_LICENSE_V2") + inactiveSecret := testSecrets.MustGetField("MAXMIND_LICENSE_INACTIVE_V2") + + type args struct { + ctx context.Context + data []byte + verify bool + } + tests := []struct { + name string + s Scanner + args args + want []detectors.Result + wantErr bool + }{ + { + name: "found, verified", + s: Scanner{}, + args: args{ + ctx: context.Background(), + data: []byte(fmt.Sprintf("You can find a geoip secret %s", secret)), + verify: true, + }, + want: []detectors.Result{ + { + DetectorType: detectorspb.DetectorType_MaxMindLicense, + Verified: true, + ExtraData: map[string]string{ + "rotation_guide": "https://howtorotate.com/docs/tutorials/maxmind/", + "version": "2", + }, + }, + }, + wantErr: false, + }, + { + name: "found, unverified", + s: Scanner{}, + args: args{ + ctx: context.Background(), + data: []byte(fmt.Sprintf("You can find a maxmind secret %s", inactiveSecret)), + verify: true, + }, + want: []detectors.Result{ + { + DetectorType: detectorspb.DetectorType_MaxMindLicense, + Verified: false, + ExtraData: map[string]string{ + "rotation_guide": "https://howtorotate.com/docs/tutorials/maxmind/", + "version": "2", + }, + }, + }, + wantErr: false, + }, + { + name: "not found", + s: Scanner{}, + args: args{ + ctx: context.Background(), + data: []byte("You cannot find the secret within"), + verify: true, + }, + want: nil, + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + s := Scanner{} + got, err := s.FromData(tt.args.ctx, tt.args.verify, tt.args.data) + if (err != nil) != tt.wantErr { + t.Errorf("MaxMindLicense.FromData() error = %v, wantErr %v", err, tt.wantErr) + return + } + for i := range got { + if len(got[i].Raw) == 0 { + t.Fatalf("no raw secret present: \n %+v", got[i]) + } + got[i].Raw = nil + } + if diff := pretty.Compare(got, tt.want); diff != "" { + t.Errorf("MaxMindLicense.FromData() %s diff: (-got +want)\n%s", tt.name, diff) + } + }) + } +} + +func BenchmarkFromData(benchmark *testing.B) { + ctx := context.Background() + s := Scanner{} + for name, data := range detectors.MustGetBenchmarkData() { + benchmark.Run(name, func(b *testing.B) { + b.ResetTimer() + for n := 0; n < b.N; n++ { + _, err := s.FromData(ctx, false, data) + if err != nil { + b.Fatal(err) + } + } + }) + } +} diff --git a/pkg/detectors/maxmindlicense/v2/maxmindlicense_v2_test.go b/pkg/detectors/maxmindlicense/v2/maxmindlicense_v2_test.go index 02e98b21354f..0636c9a0e5f8 100644 --- a/pkg/detectors/maxmindlicense/v2/maxmindlicense_v2_test.go +++ b/pkg/detectors/maxmindlicense/v2/maxmindlicense_v2_test.go @@ -1,22 +1,11 @@ -//go:build detectors -// +build detectors - package maxmindlicense import ( "context" - "fmt" - "testing" - "time" - "github.com/google/go-cmp/cmp" - "github.com/kylelemons/godebug/pretty" - "github.com/trufflesecurity/trufflehog/v3/pkg/detectors" "github.com/trufflesecurity/trufflehog/v3/pkg/engine/ahocorasick" - - "github.com/trufflesecurity/trufflehog/v3/pkg/common" - "github.com/trufflesecurity/trufflehog/v3/pkg/pb/detectorspb" + "testing" ) func TestMaxMind_Pattern(t *testing.T) { @@ -94,114 +83,3 @@ LicenseKey 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`, }) } } - -func TestMaxMindLicense(t *testing.T) { - ctx, cancel := context.WithTimeout(context.Background(), time.Second*5) - defer cancel() - testSecrets, err := common.GetSecret(ctx, "trufflehog-testing", "detectors3") - if err != nil { - t.Fatalf("could not get test secrets from GCP: %s", err) - } - secret := testSecrets.MustGetField("MAXMIND_LICENSE_V2") - inactiveSecret := testSecrets.MustGetField("MAXMIND_LICENSE_INACTIVE_V2") - - type args struct { - ctx context.Context - data []byte - verify bool - } - tests := []struct { - name string - s Scanner - args args - want []detectors.Result - wantErr bool - }{ - { - name: "found, verified", - s: Scanner{}, - args: args{ - ctx: context.Background(), - data: []byte(fmt.Sprintf("You can find a geoip secret %s", secret)), - verify: true, - }, - want: []detectors.Result{ - { - DetectorType: detectorspb.DetectorType_MaxMindLicense, - Verified: true, - ExtraData: map[string]string{ - "rotation_guide": "https://howtorotate.com/docs/tutorials/maxmind/", - "version": "2", - }, - }, - }, - wantErr: false, - }, - { - name: "found, unverified", - s: Scanner{}, - args: args{ - ctx: context.Background(), - data: []byte(fmt.Sprintf("You can find a maxmind secret %s", inactiveSecret)), - verify: true, - }, - want: []detectors.Result{ - { - DetectorType: detectorspb.DetectorType_MaxMindLicense, - Verified: false, - ExtraData: map[string]string{ - "rotation_guide": "https://howtorotate.com/docs/tutorials/maxmind/", - "version": "2", - }, - }, - }, - wantErr: false, - }, - { - name: "not found", - s: Scanner{}, - args: args{ - ctx: context.Background(), - data: []byte("You cannot find the secret within"), - verify: true, - }, - want: nil, - wantErr: false, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - s := Scanner{} - got, err := s.FromData(tt.args.ctx, tt.args.verify, tt.args.data) - if (err != nil) != tt.wantErr { - t.Errorf("MaxMindLicense.FromData() error = %v, wantErr %v", err, tt.wantErr) - return - } - for i := range got { - if len(got[i].Raw) == 0 { - t.Fatalf("no raw secret present: \n %+v", got[i]) - } - got[i].Raw = nil - } - if diff := pretty.Compare(got, tt.want); diff != "" { - t.Errorf("MaxMindLicense.FromData() %s diff: (-got +want)\n%s", tt.name, diff) - } - }) - } -} - -func BenchmarkFromData(benchmark *testing.B) { - ctx := context.Background() - s := Scanner{} - for name, data := range detectors.MustGetBenchmarkData() { - benchmark.Run(name, func(b *testing.B) { - b.ResetTimer() - for n := 0; n < b.N; n++ { - _, err := s.FromData(ctx, false, data) - if err != nil { - b.Fatal(err) - } - } - }) - } -} diff --git a/pkg/detectors/onfleet/onfleet_integration_test.go b/pkg/detectors/onfleet/onfleet_integration_test.go new file mode 100644 index 000000000000..d5b527a4f9d0 --- /dev/null +++ b/pkg/detectors/onfleet/onfleet_integration_test.go @@ -0,0 +1,161 @@ +//go:build detectors +// +build detectors + +package onfleet + +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 TestOnfleet_FromChunk(t *testing.T) { + ctx, cancel := context.WithTimeout(context.Background(), time.Second*5) + defer cancel() + testSecrets, err := common.GetSecret(ctx, "trufflehog-testing", "detectors5") + if err != nil { + t.Fatalf("could not get test secrets from GCP: %s", err) + } + secret := testSecrets.MustGetField("ONFLEET") + inactiveSecret := testSecrets.MustGetField("ONFLEET_INACTIVE") + + 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", + s: Scanner{}, + args: args{ + ctx: context.Background(), + data: []byte(fmt.Sprintf("You can find a onfleet secret %s within", secret)), + verify: true, + }, + want: []detectors.Result{ + { + DetectorType: detectorspb.DetectorType_Onfleet, + Verified: true, + }, + }, + wantErr: false, + wantVerificationErr: false, + }, + { + name: "found, unverified", + s: Scanner{}, + args: args{ + ctx: context.Background(), + data: []byte(fmt.Sprintf("You can find a onfleet secret %s within but not valid", inactiveSecret)), // the secret would satisfy the regex but not pass validation + verify: true, + }, + want: []detectors.Result{ + { + DetectorType: detectorspb.DetectorType_Onfleet, + Verified: false, + }, + }, + wantErr: false, + wantVerificationErr: false, + }, + { + name: "not found", + s: Scanner{}, + args: args{ + ctx: context.Background(), + data: []byte("You cannot find the secret within"), + verify: true, + }, + want: nil, + wantErr: false, + wantVerificationErr: false, + }, + { + name: "found, would be verified if not for timeout", + s: Scanner{client: common.SaneHttpClientTimeOut(1 * time.Microsecond)}, + args: args{ + ctx: context.Background(), + data: []byte(fmt.Sprintf("You can find a onfleet secret %s within", secret)), + verify: true, + }, + want: []detectors.Result{ + { + DetectorType: detectorspb.DetectorType_Onfleet, + Verified: false, + }, + }, + wantErr: false, + wantVerificationErr: true, + }, + { + name: "found, verified but unexpected api surface", + s: Scanner{client: common.ConstantResponseHttpClient(404, "")}, + args: args{ + ctx: context.Background(), + data: []byte(fmt.Sprintf("You can find a onfleet secret %s within", secret)), + verify: true, + }, + want: []detectors.Result{ + { + DetectorType: detectorspb.DetectorType_Onfleet, + Verified: false, + }, + }, + wantErr: false, + wantVerificationErr: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := tt.s.FromData(tt.args.ctx, tt.args.verify, tt.args.data) + if (err != nil) != tt.wantErr { + t.Errorf("Onfleet.FromData() error = %v, wantErr %v", err, tt.wantErr) + return + } + 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.Fatalf("wantVerificationError = %v, verification error = %v", tt.wantVerificationErr, got[i].VerificationError()) + } + } + ignoreOpts := cmpopts.IgnoreFields(detectors.Result{}, "Raw", "verificationError") + if diff := cmp.Diff(got, tt.want, ignoreOpts); diff != "" { + t.Errorf("Onfleet.FromData() %s diff: (-got +want)\n%s", tt.name, diff) + } + }) + } +} + +func BenchmarkFromData(benchmark *testing.B) { + ctx := context.Background() + s := Scanner{} + for name, data := range detectors.MustGetBenchmarkData() { + benchmark.Run(name, func(b *testing.B) { + b.ResetTimer() + for n := 0; n < b.N; n++ { + _, err := s.FromData(ctx, false, data) + if err != nil { + b.Fatal(err) + } + } + }) + } +} diff --git a/pkg/detectors/onfleet/onfleet_test.go b/pkg/detectors/onfleet/onfleet_test.go index 725fbd89a1b8..33c965e403a2 100644 --- a/pkg/detectors/onfleet/onfleet_test.go +++ b/pkg/detectors/onfleet/onfleet_test.go @@ -1,21 +1,11 @@ -//go:build detectors -// +build detectors - package onfleet 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/engine/ahocorasick" - "github.com/trufflesecurity/trufflehog/v3/pkg/pb/detectorspb" + "testing" ) func TestOnfleet_Pattern(t *testing.T) { @@ -75,146 +65,3 @@ func TestOnfleet_Pattern(t *testing.T) { }) } } - -func TestOnfleet_FromChunk(t *testing.T) { - ctx, cancel := context.WithTimeout(context.Background(), time.Second*5) - defer cancel() - testSecrets, err := common.GetSecret(ctx, "trufflehog-testing", "detectors5") - if err != nil { - t.Fatalf("could not get test secrets from GCP: %s", err) - } - secret := testSecrets.MustGetField("ONFLEET") - inactiveSecret := testSecrets.MustGetField("ONFLEET_INACTIVE") - - 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", - s: Scanner{}, - args: args{ - ctx: context.Background(), - data: []byte(fmt.Sprintf("You can find a onfleet secret %s within", secret)), - verify: true, - }, - want: []detectors.Result{ - { - DetectorType: detectorspb.DetectorType_Onfleet, - Verified: true, - }, - }, - wantErr: false, - wantVerificationErr: false, - }, - { - name: "found, unverified", - s: Scanner{}, - args: args{ - ctx: context.Background(), - data: []byte(fmt.Sprintf("You can find a onfleet secret %s within but not valid", inactiveSecret)), // the secret would satisfy the regex but not pass validation - verify: true, - }, - want: []detectors.Result{ - { - DetectorType: detectorspb.DetectorType_Onfleet, - Verified: false, - }, - }, - wantErr: false, - wantVerificationErr: false, - }, - { - name: "not found", - s: Scanner{}, - args: args{ - ctx: context.Background(), - data: []byte("You cannot find the secret within"), - verify: true, - }, - want: nil, - wantErr: false, - wantVerificationErr: false, - }, - { - name: "found, would be verified if not for timeout", - s: Scanner{client: common.SaneHttpClientTimeOut(1 * time.Microsecond)}, - args: args{ - ctx: context.Background(), - data: []byte(fmt.Sprintf("You can find a onfleet secret %s within", secret)), - verify: true, - }, - want: []detectors.Result{ - { - DetectorType: detectorspb.DetectorType_Onfleet, - Verified: false, - }, - }, - wantErr: false, - wantVerificationErr: true, - }, - { - name: "found, verified but unexpected api surface", - s: Scanner{client: common.ConstantResponseHttpClient(404, "")}, - args: args{ - ctx: context.Background(), - data: []byte(fmt.Sprintf("You can find a onfleet secret %s within", secret)), - verify: true, - }, - want: []detectors.Result{ - { - DetectorType: detectorspb.DetectorType_Onfleet, - Verified: false, - }, - }, - wantErr: false, - wantVerificationErr: true, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - got, err := tt.s.FromData(tt.args.ctx, tt.args.verify, tt.args.data) - if (err != nil) != tt.wantErr { - t.Errorf("Onfleet.FromData() error = %v, wantErr %v", err, tt.wantErr) - return - } - 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.Fatalf("wantVerificationError = %v, verification error = %v", tt.wantVerificationErr, got[i].VerificationError()) - } - } - ignoreOpts := cmpopts.IgnoreFields(detectors.Result{}, "Raw", "verificationError") - if diff := cmp.Diff(got, tt.want, ignoreOpts); diff != "" { - t.Errorf("Onfleet.FromData() %s diff: (-got +want)\n%s", tt.name, diff) - } - }) - } -} - -func BenchmarkFromData(benchmark *testing.B) { - ctx := context.Background() - s := Scanner{} - for name, data := range detectors.MustGetBenchmarkData() { - benchmark.Run(name, func(b *testing.B) { - b.ResetTimer() - for n := 0; n < b.N; n++ { - _, err := s.FromData(ctx, false, data) - if err != nil { - b.Fatal(err) - } - } - }) - } -} diff --git a/pkg/detectors/openai/openai_integration_test.go b/pkg/detectors/openai/openai_integration_test.go new file mode 100644 index 000000000000..400191bee2a3 --- /dev/null +++ b/pkg/detectors/openai/openai_integration_test.go @@ -0,0 +1,126 @@ +//go:build detectors +// +build detectors + +package openai + +import ( + "context" + "fmt" + "testing" + "time" + + "github.com/kylelemons/godebug/pretty" + + "github.com/trufflesecurity/trufflehog/v3/pkg/common" + "github.com/trufflesecurity/trufflehog/v3/pkg/detectors" + "github.com/trufflesecurity/trufflehog/v3/pkg/pb/detectorspb" +) + +func TestOpenAI_FromChunk(t *testing.T) { + ctx, cancel := context.WithTimeout(context.Background(), time.Second*5) + defer cancel() + testSecrets, err := common.GetSecret(ctx, "trufflehog-testing", "detectors4") + if err != nil { + t.Fatalf("could not get test secrets from GCP: %s", err) + } + + oaiUnverified := testSecrets.MustGetField("OPENAI_UNVERIFIED") + oaiVerified := testSecrets.MustGetField("OPENAI_VERIFIED") + + type args struct { + ctx context.Context + data []byte + verify bool + } + + tests := []struct { + name string + s Scanner + args args + want []detectors.Result + wantErr bool + }{ + { + name: "Found, unverified OpenAI token sk-", + s: Scanner{}, + args: args{ + ctx: context.Background(), + data: []byte(fmt.Sprintf("You can find an OpenAI secret %s within", oaiUnverified)), + verify: true, + }, + want: []detectors.Result{ + { + DetectorType: detectorspb.DetectorType_OpenAI, + Redacted: "sk-...gOPc", + Verified: false, + }, + }, + wantErr: false, + }, + { + name: "Found, verified OpenAI token sk-", + s: Scanner{}, + args: args{ + ctx: context.Background(), + data: []byte(fmt.Sprintf("You can find an OpenAI secret %s within", oaiVerified)), + verify: true, + }, + want: []detectors.Result{ + { + DetectorType: detectorspb.DetectorType_OpenAI, + Verified: true, + Redacted: "sk-...gOPb", + }, + }, + wantErr: false, + }, + { + name: "not found", + s: Scanner{}, + args: args{ + ctx: context.Background(), + data: []byte("You cannot find the secret within"), + verify: true, + }, + want: nil, + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + s := Scanner{} + got, err := s.FromData(tt.args.ctx, tt.args.verify, tt.args.data) + if (err != nil) != tt.wantErr { + t.Errorf("OpenAI.FromData() error = %v, wantErr %v", err, tt.wantErr) + return + } + for i := range got { + if len(got[i].Raw) == 0 { + t.Fatal("no raw secret present") + } + got[i].Raw = nil + got[i].ExtraData = nil + got[i].AnalysisInfo = nil + } + if diff := pretty.Compare(got, tt.want); diff != "" { + t.Errorf("OpenAI.FromData() %s diff: (-got +want)\n%s", tt.name, diff) + } + }) + } +} + +func BenchmarkFromData(benchmark *testing.B) { + ctx := context.Background() + s := Scanner{} + for name, data := range detectors.MustGetBenchmarkData() { + benchmark.Run(name, func(b *testing.B) { + b.ResetTimer() + for n := 0; n < b.N; n++ { + _, err := s.FromData(ctx, false, data) + if err != nil { + b.Fatal(err) + } + } + }) + } +} diff --git a/pkg/detectors/openai/openai_test.go b/pkg/detectors/openai/openai_test.go index 33b5a64d1246..e23c4a6e4f86 100644 --- a/pkg/detectors/openai/openai_test.go +++ b/pkg/detectors/openai/openai_test.go @@ -1,21 +1,11 @@ -//go:build detectors -// +build detectors - package openai import ( "context" - "fmt" - "testing" - "time" - "github.com/google/go-cmp/cmp" - "github.com/kylelemons/godebug/pretty" - - "github.com/trufflesecurity/trufflehog/v3/pkg/common" "github.com/trufflesecurity/trufflehog/v3/pkg/detectors" "github.com/trufflesecurity/trufflehog/v3/pkg/engine/ahocorasick" - "github.com/trufflesecurity/trufflehog/v3/pkg/pb/detectorspb" + "testing" ) func TestOpenAI_Pattern(t *testing.T) { @@ -95,112 +85,3 @@ func TestOpenAI_Pattern(t *testing.T) { }) } } - -func TestOpenAI_FromChunk(t *testing.T) { - ctx, cancel := context.WithTimeout(context.Background(), time.Second*5) - defer cancel() - testSecrets, err := common.GetSecret(ctx, "trufflehog-testing", "detectors4") - if err != nil { - t.Fatalf("could not get test secrets from GCP: %s", err) - } - - oaiUnverified := testSecrets.MustGetField("OPENAI_UNVERIFIED") - oaiVerified := testSecrets.MustGetField("OPENAI_VERIFIED") - - type args struct { - ctx context.Context - data []byte - verify bool - } - - tests := []struct { - name string - s Scanner - args args - want []detectors.Result - wantErr bool - }{ - { - name: "Found, unverified OpenAI token sk-", - s: Scanner{}, - args: args{ - ctx: context.Background(), - data: []byte(fmt.Sprintf("You can find an OpenAI secret %s within", oaiUnverified)), - verify: true, - }, - want: []detectors.Result{ - { - DetectorType: detectorspb.DetectorType_OpenAI, - Redacted: "sk-...gOPc", - Verified: false, - }, - }, - wantErr: false, - }, - { - name: "Found, verified OpenAI token sk-", - s: Scanner{}, - args: args{ - ctx: context.Background(), - data: []byte(fmt.Sprintf("You can find an OpenAI secret %s within", oaiVerified)), - verify: true, - }, - want: []detectors.Result{ - { - DetectorType: detectorspb.DetectorType_OpenAI, - Verified: true, - Redacted: "sk-...gOPb", - }, - }, - wantErr: false, - }, - { - name: "not found", - s: Scanner{}, - args: args{ - ctx: context.Background(), - data: []byte("You cannot find the secret within"), - verify: true, - }, - want: nil, - wantErr: false, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - s := Scanner{} - got, err := s.FromData(tt.args.ctx, tt.args.verify, tt.args.data) - if (err != nil) != tt.wantErr { - t.Errorf("OpenAI.FromData() error = %v, wantErr %v", err, tt.wantErr) - return - } - for i := range got { - if len(got[i].Raw) == 0 { - t.Fatal("no raw secret present") - } - got[i].Raw = nil - got[i].ExtraData = nil - got[i].AnalysisInfo = nil - } - if diff := pretty.Compare(got, tt.want); diff != "" { - t.Errorf("OpenAI.FromData() %s diff: (-got +want)\n%s", tt.name, diff) - } - }) - } -} - -func BenchmarkFromData(benchmark *testing.B) { - ctx := context.Background() - s := Scanner{} - for name, data := range detectors.MustGetBenchmarkData() { - benchmark.Run(name, func(b *testing.B) { - b.ResetTimer() - for n := 0; n < b.N; n++ { - _, err := s.FromData(ctx, false, data) - if err != nil { - b.Fatal(err) - } - } - }) - } -} diff --git a/pkg/detectors/pagarme/pagarme_integration_test.go b/pkg/detectors/pagarme/pagarme_integration_test.go new file mode 100644 index 000000000000..8cf1361f15f1 --- /dev/null +++ b/pkg/detectors/pagarme/pagarme_integration_test.go @@ -0,0 +1,161 @@ +//go:build detectors +// +build detectors + +package pagarme + +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 TestPagarme_FromChunk(t *testing.T) { + ctx, cancel := context.WithTimeout(context.Background(), time.Second*5) + defer cancel() + testSecrets, err := common.GetSecret(ctx, "trufflehog-testing", "detectors5") + if err != nil { + t.Fatalf("could not get test secrets from GCP: %s", err) + } + secret := testSecrets.MustGetField("PAGARME") + inactiveSecret := testSecrets.MustGetField("PAGARME_INACTIVE") + + 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", + s: Scanner{}, + args: args{ + ctx: context.Background(), + data: []byte(fmt.Sprintf("You can find a pagarme secret %s within", secret)), + verify: true, + }, + want: []detectors.Result{ + { + DetectorType: detectorspb.DetectorType_Pagarme, + Verified: true, + }, + }, + wantErr: false, + wantVerificationErr: false, + }, + { + name: "found, unverified", + s: Scanner{}, + args: args{ + ctx: context.Background(), + data: []byte(fmt.Sprintf("You can find a pagarme secret %s within but not valid", inactiveSecret)), // the secret would satisfy the regex but not pass validation + verify: true, + }, + want: []detectors.Result{ + { + DetectorType: detectorspb.DetectorType_Pagarme, + Verified: false, + }, + }, + wantErr: false, + wantVerificationErr: false, + }, + { + name: "not found", + s: Scanner{}, + args: args{ + ctx: context.Background(), + data: []byte("You cannot find the secret within"), + verify: true, + }, + want: nil, + wantErr: false, + wantVerificationErr: false, + }, + { + name: "found, would be verified if not for timeout", + s: Scanner{client: common.SaneHttpClientTimeOut(1 * time.Microsecond)}, + args: args{ + ctx: context.Background(), + data: []byte(fmt.Sprintf("You can find a pagarme secret %s within", secret)), + verify: true, + }, + want: []detectors.Result{ + { + DetectorType: detectorspb.DetectorType_Pagarme, + Verified: false, + }, + }, + wantErr: false, + wantVerificationErr: true, + }, + { + name: "found, verified but unexpected api surface", + s: Scanner{client: common.ConstantResponseHttpClient(404, "")}, + args: args{ + ctx: context.Background(), + data: []byte(fmt.Sprintf("You can find a pagarme secret %s within", secret)), + verify: true, + }, + want: []detectors.Result{ + { + DetectorType: detectorspb.DetectorType_Pagarme, + Verified: false, + }, + }, + wantErr: false, + wantVerificationErr: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := tt.s.FromData(tt.args.ctx, tt.args.verify, tt.args.data) + if (err != nil) != tt.wantErr { + t.Errorf("Pagarme.FromData() error = %v, wantErr %v", err, tt.wantErr) + return + } + 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.Fatalf("wantVerificationError = %v, verification error = %v", tt.wantVerificationErr, got[i].VerificationError()) + } + } + ignoreOpts := cmpopts.IgnoreFields(detectors.Result{}, "Raw", "verificationError") + if diff := cmp.Diff(got, tt.want, ignoreOpts); diff != "" { + t.Errorf("Pagarme.FromData() %s diff: (-got +want)\n%s", tt.name, diff) + } + }) + } +} + +func BenchmarkFromData(benchmark *testing.B) { + ctx := context.Background() + s := Scanner{} + for name, data := range detectors.MustGetBenchmarkData() { + benchmark.Run(name, func(b *testing.B) { + b.ResetTimer() + for n := 0; n < b.N; n++ { + _, err := s.FromData(ctx, false, data) + if err != nil { + b.Fatal(err) + } + } + }) + } +} diff --git a/pkg/detectors/pagarme/pagarme_test.go b/pkg/detectors/pagarme/pagarme_test.go index 595cbd7cde84..bddfe33c0402 100644 --- a/pkg/detectors/pagarme/pagarme_test.go +++ b/pkg/detectors/pagarme/pagarme_test.go @@ -1,21 +1,11 @@ -//go:build detectors -// +build detectors - package pagarme 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/engine/ahocorasick" - "github.com/trufflesecurity/trufflehog/v3/pkg/pb/detectorspb" + "testing" ) func TestPagarme_Pattern(t *testing.T) { @@ -75,146 +65,3 @@ func TestPagarme_Pattern(t *testing.T) { }) } } - -func TestPagarme_FromChunk(t *testing.T) { - ctx, cancel := context.WithTimeout(context.Background(), time.Second*5) - defer cancel() - testSecrets, err := common.GetSecret(ctx, "trufflehog-testing", "detectors5") - if err != nil { - t.Fatalf("could not get test secrets from GCP: %s", err) - } - secret := testSecrets.MustGetField("PAGARME") - inactiveSecret := testSecrets.MustGetField("PAGARME_INACTIVE") - - 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", - s: Scanner{}, - args: args{ - ctx: context.Background(), - data: []byte(fmt.Sprintf("You can find a pagarme secret %s within", secret)), - verify: true, - }, - want: []detectors.Result{ - { - DetectorType: detectorspb.DetectorType_Pagarme, - Verified: true, - }, - }, - wantErr: false, - wantVerificationErr: false, - }, - { - name: "found, unverified", - s: Scanner{}, - args: args{ - ctx: context.Background(), - data: []byte(fmt.Sprintf("You can find a pagarme secret %s within but not valid", inactiveSecret)), // the secret would satisfy the regex but not pass validation - verify: true, - }, - want: []detectors.Result{ - { - DetectorType: detectorspb.DetectorType_Pagarme, - Verified: false, - }, - }, - wantErr: false, - wantVerificationErr: false, - }, - { - name: "not found", - s: Scanner{}, - args: args{ - ctx: context.Background(), - data: []byte("You cannot find the secret within"), - verify: true, - }, - want: nil, - wantErr: false, - wantVerificationErr: false, - }, - { - name: "found, would be verified if not for timeout", - s: Scanner{client: common.SaneHttpClientTimeOut(1 * time.Microsecond)}, - args: args{ - ctx: context.Background(), - data: []byte(fmt.Sprintf("You can find a pagarme secret %s within", secret)), - verify: true, - }, - want: []detectors.Result{ - { - DetectorType: detectorspb.DetectorType_Pagarme, - Verified: false, - }, - }, - wantErr: false, - wantVerificationErr: true, - }, - { - name: "found, verified but unexpected api surface", - s: Scanner{client: common.ConstantResponseHttpClient(404, "")}, - args: args{ - ctx: context.Background(), - data: []byte(fmt.Sprintf("You can find a pagarme secret %s within", secret)), - verify: true, - }, - want: []detectors.Result{ - { - DetectorType: detectorspb.DetectorType_Pagarme, - Verified: false, - }, - }, - wantErr: false, - wantVerificationErr: true, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - got, err := tt.s.FromData(tt.args.ctx, tt.args.verify, tt.args.data) - if (err != nil) != tt.wantErr { - t.Errorf("Pagarme.FromData() error = %v, wantErr %v", err, tt.wantErr) - return - } - 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.Fatalf("wantVerificationError = %v, verification error = %v", tt.wantVerificationErr, got[i].VerificationError()) - } - } - ignoreOpts := cmpopts.IgnoreFields(detectors.Result{}, "Raw", "verificationError") - if diff := cmp.Diff(got, tt.want, ignoreOpts); diff != "" { - t.Errorf("Pagarme.FromData() %s diff: (-got +want)\n%s", tt.name, diff) - } - }) - } -} - -func BenchmarkFromData(benchmark *testing.B) { - ctx := context.Background() - s := Scanner{} - for name, data := range detectors.MustGetBenchmarkData() { - benchmark.Run(name, func(b *testing.B) { - b.ResetTimer() - for n := 0; n < b.N; n++ { - _, err := s.FromData(ctx, false, data) - if err != nil { - b.Fatal(err) - } - } - }) - } -} diff --git a/pkg/detectors/parseur/parseur_integration_test.go b/pkg/detectors/parseur/parseur_integration_test.go new file mode 100644 index 000000000000..b5466b428a4a --- /dev/null +++ b/pkg/detectors/parseur/parseur_integration_test.go @@ -0,0 +1,121 @@ +//go:build detectors +// +build detectors + +package parseur + +import ( + "context" + "fmt" + "testing" + "time" + + "github.com/kylelemons/godebug/pretty" + + "github.com/trufflesecurity/trufflehog/v3/pkg/detectors" + + "github.com/trufflesecurity/trufflehog/v3/pkg/common" + "github.com/trufflesecurity/trufflehog/v3/pkg/pb/detectorspb" +) + +func TestParseur_FromChunk(t *testing.T) { + ctx, cancel := context.WithTimeout(context.Background(), time.Second*5) + defer cancel() + testSecrets, err := common.GetSecret(ctx, "trufflehog-testing", "detectors3") + if err != nil { + t.Fatalf("could not get test secrets from GCP: %s", err) + } + secret := testSecrets.MustGetField("PARSEUR") + inactiveSecret := testSecrets.MustGetField("PARSEUR_INACTIVE") + + type args struct { + ctx context.Context + data []byte + verify bool + } + tests := []struct { + name string + s Scanner + args args + want []detectors.Result + wantErr bool + }{ + { + name: "found, verified", + s: Scanner{}, + args: args{ + ctx: context.Background(), + data: []byte(fmt.Sprintf("You can find a parseur secret %s within", secret)), + verify: true, + }, + want: []detectors.Result{ + { + DetectorType: detectorspb.DetectorType_Parseur, + Verified: true, + }, + }, + wantErr: false, + }, + { + name: "found, unverified", + s: Scanner{}, + args: args{ + ctx: context.Background(), + data: []byte(fmt.Sprintf("You can find a parseur secret %s within but not valid", inactiveSecret)), // the secret would satisfy the regex but not pass validation + verify: true, + }, + want: []detectors.Result{ + { + DetectorType: detectorspb.DetectorType_Parseur, + Verified: false, + }, + }, + wantErr: false, + }, + { + name: "not found", + s: Scanner{}, + args: args{ + ctx: context.Background(), + data: []byte("You cannot find the secret within"), + verify: true, + }, + want: nil, + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + s := Scanner{} + got, err := s.FromData(tt.args.ctx, tt.args.verify, tt.args.data) + if (err != nil) != tt.wantErr { + t.Errorf("Parseur.FromData() error = %v, wantErr %v", err, tt.wantErr) + return + } + for i := range got { + if len(got[i].Raw) == 0 { + t.Fatalf("no raw secret present: \n %+v", got[i]) + } + got[i].Raw = nil + } + if diff := pretty.Compare(got, tt.want); diff != "" { + t.Errorf("Parseur.FromData() %s diff: (-got +want)\n%s", tt.name, diff) + } + }) + } +} + +func BenchmarkFromData(benchmark *testing.B) { + ctx := context.Background() + s := Scanner{} + for name, data := range detectors.MustGetBenchmarkData() { + benchmark.Run(name, func(b *testing.B) { + b.ResetTimer() + for n := 0; n < b.N; n++ { + _, err := s.FromData(ctx, false, data) + if err != nil { + b.Fatal(err) + } + } + }) + } +} diff --git a/pkg/detectors/parseur/parseur_test.go b/pkg/detectors/parseur/parseur_test.go index 9c30cf98d363..fd6a5daa53ed 100644 --- a/pkg/detectors/parseur/parseur_test.go +++ b/pkg/detectors/parseur/parseur_test.go @@ -2,16 +2,7 @@ package parseur import ( "context" - "fmt" "testing" - "time" - - "github.com/kylelemons/godebug/pretty" - - "github.com/trufflesecurity/trufflehog/v3/pkg/detectors" - - "github.com/trufflesecurity/trufflehog/v3/pkg/common" - "github.com/trufflesecurity/trufflehog/v3/pkg/pb/detectorspb" ) func TestParseur_Pattern(t *testing.T) { @@ -117,106 +108,3 @@ commit 2c65bd981d308d264aa0c07083b2bc914905deb3`, }) } } - -func TestParseur_FromChunk(t *testing.T) { - ctx, cancel := context.WithTimeout(context.Background(), time.Second*5) - defer cancel() - testSecrets, err := common.GetSecret(ctx, "trufflehog-testing", "detectors3") - if err != nil { - t.Fatalf("could not get test secrets from GCP: %s", err) - } - secret := testSecrets.MustGetField("PARSEUR") - inactiveSecret := testSecrets.MustGetField("PARSEUR_INACTIVE") - - type args struct { - ctx context.Context - data []byte - verify bool - } - tests := []struct { - name string - s Scanner - args args - want []detectors.Result - wantErr bool - }{ - { - name: "found, verified", - s: Scanner{}, - args: args{ - ctx: context.Background(), - data: []byte(fmt.Sprintf("You can find a parseur secret %s within", secret)), - verify: true, - }, - want: []detectors.Result{ - { - DetectorType: detectorspb.DetectorType_Parseur, - Verified: true, - }, - }, - wantErr: false, - }, - { - name: "found, unverified", - s: Scanner{}, - args: args{ - ctx: context.Background(), - data: []byte(fmt.Sprintf("You can find a parseur secret %s within but not valid", inactiveSecret)), // the secret would satisfy the regex but not pass validation - verify: true, - }, - want: []detectors.Result{ - { - DetectorType: detectorspb.DetectorType_Parseur, - Verified: false, - }, - }, - wantErr: false, - }, - { - name: "not found", - s: Scanner{}, - args: args{ - ctx: context.Background(), - data: []byte("You cannot find the secret within"), - verify: true, - }, - want: nil, - wantErr: false, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - s := Scanner{} - got, err := s.FromData(tt.args.ctx, tt.args.verify, tt.args.data) - if (err != nil) != tt.wantErr { - t.Errorf("Parseur.FromData() error = %v, wantErr %v", err, tt.wantErr) - return - } - for i := range got { - if len(got[i].Raw) == 0 { - t.Fatalf("no raw secret present: \n %+v", got[i]) - } - got[i].Raw = nil - } - if diff := pretty.Compare(got, tt.want); diff != "" { - t.Errorf("Parseur.FromData() %s diff: (-got +want)\n%s", tt.name, diff) - } - }) - } -} - -func BenchmarkFromData(benchmark *testing.B) { - ctx := context.Background() - s := Scanner{} - for name, data := range detectors.MustGetBenchmarkData() { - benchmark.Run(name, func(b *testing.B) { - b.ResetTimer() - for n := 0; n < b.N; n++ { - _, err := s.FromData(ctx, false, data) - if err != nil { - b.Fatal(err) - } - } - }) - } -} diff --git a/pkg/detectors/railwayapp/railwayapp_integration_test.go b/pkg/detectors/railwayapp/railwayapp_integration_test.go new file mode 100644 index 000000000000..0843267b9946 --- /dev/null +++ b/pkg/detectors/railwayapp/railwayapp_integration_test.go @@ -0,0 +1,173 @@ +//go:build detectors +// +build detectors + +package railwayapp + +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 TestRailwayApp_FromChunk(t *testing.T) { + ctx, cancel := context.WithTimeout(context.Background(), time.Second*5) + defer cancel() + testSecrets, err := common.GetSecret(ctx, "trufflehog-testing", "detectors5") + if err != nil { + t.Fatalf("could not get test secrets from GCP: %s", err) + } + secret := testSecrets.MustGetField("RAILWAYAPP") + inactiveSecret := testSecrets.MustGetField("RAILWAYAPP_INACTIVE") + + 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", + s: Scanner{}, + args: args{ + ctx: ctx, + data: []byte(fmt.Sprintf("You can find a railwayapp secret %s within", secret)), + verify: true, + }, + want: []detectors.Result{ + { + DetectorType: detectorspb.DetectorType_RailwayApp, + Verified: true, + ExtraData: map[string]string{ + "rotation_guide": "https://howtorotate.com/docs/tutorials/railwayapp/", + }, + }, + }, + wantErr: false, + wantVerificationErr: false, + }, + { + name: "found, unverified", + s: Scanner{}, + args: args{ + ctx: ctx, + data: []byte(fmt.Sprintf("You can find a railwayapp secret %s within but not valid", inactiveSecret)), // the secret would satisfy the regex but not pass validation + verify: true, + }, + want: []detectors.Result{ + { + DetectorType: detectorspb.DetectorType_RailwayApp, + Verified: false, + ExtraData: map[string]string{ + "rotation_guide": "https://howtorotate.com/docs/tutorials/railwayapp/", + }, + }, + }, + wantErr: false, + wantVerificationErr: false, + }, + { + name: "not found", + s: Scanner{}, + args: args{ + ctx: context.Background(), + data: []byte("You cannot find the secret within"), + verify: true, + }, + want: nil, + wantErr: false, + wantVerificationErr: false, + }, + { + name: "found, would be verified if not for timeout", + s: Scanner{client: common.SaneHttpClientTimeOut(1 * time.Microsecond)}, + args: args{ + ctx: context.Background(), + data: []byte(fmt.Sprintf("You can find a railwayapp secret %s within", secret)), + verify: true, + }, + want: []detectors.Result{ + { + DetectorType: detectorspb.DetectorType_RailwayApp, + Verified: false, + ExtraData: map[string]string{ + "rotation_guide": "https://howtorotate.com/docs/tutorials/railwayapp/", + }, + }, + }, + wantErr: false, + wantVerificationErr: true, + }, + { + name: "found, verified but unexpected api surface", + s: Scanner{client: common.ConstantResponseHttpClient(500, "")}, + args: args{ + ctx: context.Background(), + data: []byte(fmt.Sprintf("You can find a railwayapp secret %s within", secret)), + verify: true, + }, + want: []detectors.Result{ + { + DetectorType: detectorspb.DetectorType_RailwayApp, + Verified: false, + ExtraData: map[string]string{ + "rotation_guide": "https://howtorotate.com/docs/tutorials/railwayapp/", + }, + }, + }, + wantErr: false, + wantVerificationErr: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := tt.s.FromData(tt.args.ctx, tt.args.verify, tt.args.data) + if (err != nil) != tt.wantErr { + t.Errorf("RailwayApp.FromData() error = %v, wantErr %v", err, tt.wantErr) + return + } + 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.Fatalf("wantVerificationError = %v, verification error = %v", tt.wantVerificationErr, got[i].VerificationError()) + } + } + ignoreOpts := cmpopts.IgnoreFields(detectors.Result{}, "Raw", "verificationError") + if diff := cmp.Diff(got, tt.want, ignoreOpts); diff != "" { + t.Errorf("RailwayApp.FromData() %s diff: (-got +want)\n%s", tt.name, diff) + } + }) + } +} + +func BenchmarkFromData(benchmark *testing.B) { + ctx := context.Background() + s := Scanner{} + for name, data := range detectors.MustGetBenchmarkData() { + benchmark.Run(name, func(b *testing.B) { + b.ResetTimer() + for n := 0; n < b.N; n++ { + _, err := s.FromData(ctx, false, data) + if err != nil { + b.Fatal(err) + } + } + }) + } +} diff --git a/pkg/detectors/railwayapp/railwayapp_test.go b/pkg/detectors/railwayapp/railwayapp_test.go index 1bdc9a756257..d27c35eeec3f 100644 --- a/pkg/detectors/railwayapp/railwayapp_test.go +++ b/pkg/detectors/railwayapp/railwayapp_test.go @@ -1,21 +1,11 @@ -//go:build detectors -// +build detectors - package railwayapp 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/engine/ahocorasick" - "github.com/trufflesecurity/trufflehog/v3/pkg/pb/detectorspb" + "testing" ) func TestRailwayApp_Pattern(t *testing.T) { @@ -90,158 +80,3 @@ func TestRailwayApp_Pattern(t *testing.T) { }) } } - -func TestRailwayApp_FromChunk(t *testing.T) { - ctx, cancel := context.WithTimeout(context.Background(), time.Second*5) - defer cancel() - testSecrets, err := common.GetSecret(ctx, "trufflehog-testing", "detectors5") - if err != nil { - t.Fatalf("could not get test secrets from GCP: %s", err) - } - secret := testSecrets.MustGetField("RAILWAYAPP") - inactiveSecret := testSecrets.MustGetField("RAILWAYAPP_INACTIVE") - - 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", - s: Scanner{}, - args: args{ - ctx: ctx, - data: []byte(fmt.Sprintf("You can find a railwayapp secret %s within", secret)), - verify: true, - }, - want: []detectors.Result{ - { - DetectorType: detectorspb.DetectorType_RailwayApp, - Verified: true, - ExtraData: map[string]string{ - "rotation_guide": "https://howtorotate.com/docs/tutorials/railwayapp/", - }, - }, - }, - wantErr: false, - wantVerificationErr: false, - }, - { - name: "found, unverified", - s: Scanner{}, - args: args{ - ctx: ctx, - data: []byte(fmt.Sprintf("You can find a railwayapp secret %s within but not valid", inactiveSecret)), // the secret would satisfy the regex but not pass validation - verify: true, - }, - want: []detectors.Result{ - { - DetectorType: detectorspb.DetectorType_RailwayApp, - Verified: false, - ExtraData: map[string]string{ - "rotation_guide": "https://howtorotate.com/docs/tutorials/railwayapp/", - }, - }, - }, - wantErr: false, - wantVerificationErr: false, - }, - { - name: "not found", - s: Scanner{}, - args: args{ - ctx: context.Background(), - data: []byte("You cannot find the secret within"), - verify: true, - }, - want: nil, - wantErr: false, - wantVerificationErr: false, - }, - { - name: "found, would be verified if not for timeout", - s: Scanner{client: common.SaneHttpClientTimeOut(1 * time.Microsecond)}, - args: args{ - ctx: context.Background(), - data: []byte(fmt.Sprintf("You can find a railwayapp secret %s within", secret)), - verify: true, - }, - want: []detectors.Result{ - { - DetectorType: detectorspb.DetectorType_RailwayApp, - Verified: false, - ExtraData: map[string]string{ - "rotation_guide": "https://howtorotate.com/docs/tutorials/railwayapp/", - }, - }, - }, - wantErr: false, - wantVerificationErr: true, - }, - { - name: "found, verified but unexpected api surface", - s: Scanner{client: common.ConstantResponseHttpClient(500, "")}, - args: args{ - ctx: context.Background(), - data: []byte(fmt.Sprintf("You can find a railwayapp secret %s within", secret)), - verify: true, - }, - want: []detectors.Result{ - { - DetectorType: detectorspb.DetectorType_RailwayApp, - Verified: false, - ExtraData: map[string]string{ - "rotation_guide": "https://howtorotate.com/docs/tutorials/railwayapp/", - }, - }, - }, - wantErr: false, - wantVerificationErr: true, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - got, err := tt.s.FromData(tt.args.ctx, tt.args.verify, tt.args.data) - if (err != nil) != tt.wantErr { - t.Errorf("RailwayApp.FromData() error = %v, wantErr %v", err, tt.wantErr) - return - } - 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.Fatalf("wantVerificationError = %v, verification error = %v", tt.wantVerificationErr, got[i].VerificationError()) - } - } - ignoreOpts := cmpopts.IgnoreFields(detectors.Result{}, "Raw", "verificationError") - if diff := cmp.Diff(got, tt.want, ignoreOpts); diff != "" { - t.Errorf("RailwayApp.FromData() %s diff: (-got +want)\n%s", tt.name, diff) - } - }) - } -} - -func BenchmarkFromData(benchmark *testing.B) { - ctx := context.Background() - s := Scanner{} - for name, data := range detectors.MustGetBenchmarkData() { - benchmark.Run(name, func(b *testing.B) { - b.ResetTimer() - for n := 0; n < b.N; n++ { - _, err := s.FromData(ctx, false, data) - if err != nil { - b.Fatal(err) - } - } - }) - } -} diff --git a/pkg/detectors/robinhoodcrypto/robinhoodcrypto_integration_test.go b/pkg/detectors/robinhoodcrypto/robinhoodcrypto_integration_test.go new file mode 100644 index 000000000000..cc9c9b5750d1 --- /dev/null +++ b/pkg/detectors/robinhoodcrypto/robinhoodcrypto_integration_test.go @@ -0,0 +1,207 @@ +//go:build detectors +// +build detectors + +package robinhoodcrypto + +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 TestRobinhoodcrypto_FromChunk(t *testing.T) { + ctx, cancel := context.WithTimeout(context.Background(), time.Second*5) + defer cancel() + testSecrets, err := common.GetSecret(ctx, "trufflehog-testing", "detectors5") + if err != nil { + t.Fatalf("could not get test secrets from GCP: %s", err) + } + + // Valid and active credentials. + apiKey := testSecrets.MustGetField("ROBINHOODCRYPTO_APIKEY") + privateKey := testSecrets.MustGetField("ROBINHOODCRYPTO_PRIVATEKEY") + + // Valid but inactive credentials. + inactiveApiKey := testSecrets.MustGetField("ROBINHOODCRYPTO_APIKEY_INACTIVE") + inactivePrivateKey := testSecrets.MustGetField("ROBINHOODCRYPTO_PRIVATEKEY_INACTIVE") + + // Invalid credentials. + deletedApiKey := testSecrets.MustGetField("ROBINHOODCRYPTO_APIKEY_DELETED") + deletedPrivateKey := testSecrets.MustGetField("ROBINHOODCRYPTO_PRIVATEKEY_DELETED") + + 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", + s: Scanner{}, + args: args{ + ctx: context.Background(), + data: []byte(fmt.Sprintf( + "You can find a robinhoodcrypto api key %s and a private key %s within", apiKey, privateKey, + )), + verify: true, + }, + want: []detectors.Result{ + { + DetectorType: detectorspb.DetectorType_RobinhoodCrypto, + Verified: true, + }, + }, + wantErr: false, + wantVerificationErr: false, + }, + { + name: "found, verified, but inactive", + s: Scanner{}, + args: args{ + ctx: context.Background(), + data: []byte(fmt.Sprintf( + "You can find a robinhoodcrypto api key %s and a private key %s within", inactiveApiKey, + inactivePrivateKey, + )), + verify: true, + }, + want: []detectors.Result{ + { + DetectorType: detectorspb.DetectorType_RobinhoodCrypto, + Verified: true, + }, + }, + wantErr: false, + wantVerificationErr: false, + }, + { + name: "found, unverified", + s: Scanner{}, + args: args{ + ctx: context.Background(), + data: []byte(fmt.Sprintf( + "You can find a robinhoodcrypto api key %s and a private key %s within", deletedApiKey, + deletedPrivateKey, + )), // the secret would satisfy the regex but not pass validation + verify: true, + }, + want: []detectors.Result{ + { + DetectorType: detectorspb.DetectorType_RobinhoodCrypto, + Verified: false, + }, + }, + wantErr: false, + wantVerificationErr: false, + }, + { + name: "not found", + s: Scanner{}, + args: args{ + ctx: context.Background(), + data: []byte("You cannot find the secret within"), + verify: true, + }, + want: nil, + wantErr: false, + wantVerificationErr: false, + }, + { + name: "found, would be verified if not for timeout", + s: Scanner{client: common.SaneHttpClientTimeOut(1 * time.Microsecond)}, + args: args{ + ctx: context.Background(), + data: []byte(fmt.Sprintf( + "You can find a robinhoodcrypto api key %s and a private key %s within", apiKey, privateKey, + )), + verify: true, + }, + want: []detectors.Result{ + { + DetectorType: detectorspb.DetectorType_RobinhoodCrypto, + Verified: false, + }, + }, + wantErr: false, + wantVerificationErr: true, + }, + { + name: "found, verified but unexpected api surface", + s: Scanner{client: common.ConstantResponseHttpClient(404, "")}, + args: args{ + ctx: context.Background(), + data: []byte(fmt.Sprintf( + "You can find a robinhoodcrypto api key %s and a private key %s within", apiKey, privateKey, + )), + verify: true, + }, + want: []detectors.Result{ + { + DetectorType: detectorspb.DetectorType_RobinhoodCrypto, + Verified: false, + }, + }, + wantErr: false, + wantVerificationErr: true, + }, + } + for _, tt := range tests { + t.Run( + tt.name, func(t *testing.T) { + got, err := tt.s.FromData(tt.args.ctx, tt.args.verify, tt.args.data) + if (err != nil) != tt.wantErr { + t.Errorf("Robinhoodcrypto.FromData() error = %v, wantErr %v", err, tt.wantErr) + return + } + 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.Fatalf( + "wantVerificationError = %v, verification error = %v", tt.wantVerificationErr, + got[i].VerificationError(), + ) + } + } + ignoreOpts := cmpopts.IgnoreFields(detectors.Result{}, "ExtraData", "Raw", "RawV2", "verificationError") + if diff := cmp.Diff(got, tt.want, ignoreOpts); diff != "" { + t.Errorf("Robinhoodcrypto.FromData() %s diff: (-got +want)\n%s", tt.name, diff) + } + }, + ) + } +} + +func BenchmarkFromData(benchmark *testing.B) { + ctx := context.Background() + s := Scanner{} + for name, data := range detectors.MustGetBenchmarkData() { + benchmark.Run( + name, func(b *testing.B) { + b.ResetTimer() + for n := 0; n < b.N; n++ { + _, err := s.FromData(ctx, false, data) + if err != nil { + b.Fatal(err) + } + } + }, + ) + } +} diff --git a/pkg/detectors/robinhoodcrypto/robinhoodcrypto_test.go b/pkg/detectors/robinhoodcrypto/robinhoodcrypto_test.go index 3072b0faec38..d75b1c5973f9 100644 --- a/pkg/detectors/robinhoodcrypto/robinhoodcrypto_test.go +++ b/pkg/detectors/robinhoodcrypto/robinhoodcrypto_test.go @@ -1,21 +1,11 @@ -//go:build detectors -// +build detectors - package robinhoodcrypto 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/engine/ahocorasick" - "github.com/trufflesecurity/trufflehog/v3/pkg/pb/detectorspb" + "testing" ) func TestRobinhoodCrypto_Pattern(t *testing.T) { @@ -83,192 +73,3 @@ func TestRobinhoodCrypto_Pattern(t *testing.T) { ) } } - -func TestRobinhoodcrypto_FromChunk(t *testing.T) { - ctx, cancel := context.WithTimeout(context.Background(), time.Second*5) - defer cancel() - testSecrets, err := common.GetSecret(ctx, "trufflehog-testing", "detectors5") - if err != nil { - t.Fatalf("could not get test secrets from GCP: %s", err) - } - - // Valid and active credentials. - apiKey := testSecrets.MustGetField("ROBINHOODCRYPTO_APIKEY") - privateKey := testSecrets.MustGetField("ROBINHOODCRYPTO_PRIVATEKEY") - - // Valid but inactive credentials. - inactiveApiKey := testSecrets.MustGetField("ROBINHOODCRYPTO_APIKEY_INACTIVE") - inactivePrivateKey := testSecrets.MustGetField("ROBINHOODCRYPTO_PRIVATEKEY_INACTIVE") - - // Invalid credentials. - deletedApiKey := testSecrets.MustGetField("ROBINHOODCRYPTO_APIKEY_DELETED") - deletedPrivateKey := testSecrets.MustGetField("ROBINHOODCRYPTO_PRIVATEKEY_DELETED") - - 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", - s: Scanner{}, - args: args{ - ctx: context.Background(), - data: []byte(fmt.Sprintf( - "You can find a robinhoodcrypto api key %s and a private key %s within", apiKey, privateKey, - )), - verify: true, - }, - want: []detectors.Result{ - { - DetectorType: detectorspb.DetectorType_RobinhoodCrypto, - Verified: true, - }, - }, - wantErr: false, - wantVerificationErr: false, - }, - { - name: "found, verified, but inactive", - s: Scanner{}, - args: args{ - ctx: context.Background(), - data: []byte(fmt.Sprintf( - "You can find a robinhoodcrypto api key %s and a private key %s within", inactiveApiKey, - inactivePrivateKey, - )), - verify: true, - }, - want: []detectors.Result{ - { - DetectorType: detectorspb.DetectorType_RobinhoodCrypto, - Verified: true, - }, - }, - wantErr: false, - wantVerificationErr: false, - }, - { - name: "found, unverified", - s: Scanner{}, - args: args{ - ctx: context.Background(), - data: []byte(fmt.Sprintf( - "You can find a robinhoodcrypto api key %s and a private key %s within", deletedApiKey, - deletedPrivateKey, - )), // the secret would satisfy the regex but not pass validation - verify: true, - }, - want: []detectors.Result{ - { - DetectorType: detectorspb.DetectorType_RobinhoodCrypto, - Verified: false, - }, - }, - wantErr: false, - wantVerificationErr: false, - }, - { - name: "not found", - s: Scanner{}, - args: args{ - ctx: context.Background(), - data: []byte("You cannot find the secret within"), - verify: true, - }, - want: nil, - wantErr: false, - wantVerificationErr: false, - }, - { - name: "found, would be verified if not for timeout", - s: Scanner{client: common.SaneHttpClientTimeOut(1 * time.Microsecond)}, - args: args{ - ctx: context.Background(), - data: []byte(fmt.Sprintf( - "You can find a robinhoodcrypto api key %s and a private key %s within", apiKey, privateKey, - )), - verify: true, - }, - want: []detectors.Result{ - { - DetectorType: detectorspb.DetectorType_RobinhoodCrypto, - Verified: false, - }, - }, - wantErr: false, - wantVerificationErr: true, - }, - { - name: "found, verified but unexpected api surface", - s: Scanner{client: common.ConstantResponseHttpClient(404, "")}, - args: args{ - ctx: context.Background(), - data: []byte(fmt.Sprintf( - "You can find a robinhoodcrypto api key %s and a private key %s within", apiKey, privateKey, - )), - verify: true, - }, - want: []detectors.Result{ - { - DetectorType: detectorspb.DetectorType_RobinhoodCrypto, - Verified: false, - }, - }, - wantErr: false, - wantVerificationErr: true, - }, - } - for _, tt := range tests { - t.Run( - tt.name, func(t *testing.T) { - got, err := tt.s.FromData(tt.args.ctx, tt.args.verify, tt.args.data) - if (err != nil) != tt.wantErr { - t.Errorf("Robinhoodcrypto.FromData() error = %v, wantErr %v", err, tt.wantErr) - return - } - 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.Fatalf( - "wantVerificationError = %v, verification error = %v", tt.wantVerificationErr, - got[i].VerificationError(), - ) - } - } - ignoreOpts := cmpopts.IgnoreFields(detectors.Result{}, "ExtraData", "Raw", "RawV2", "verificationError") - if diff := cmp.Diff(got, tt.want, ignoreOpts); diff != "" { - t.Errorf("Robinhoodcrypto.FromData() %s diff: (-got +want)\n%s", tt.name, diff) - } - }, - ) - } -} - -func BenchmarkFromData(benchmark *testing.B) { - ctx := context.Background() - s := Scanner{} - for name, data := range detectors.MustGetBenchmarkData() { - benchmark.Run( - name, func(b *testing.B) { - b.ResetTimer() - for n := 0; n < b.N; n++ { - _, err := s.FromData(ctx, false, data) - if err != nil { - b.Fatal(err) - } - } - }, - ) - } -} diff --git a/pkg/detectors/signable/signable_integration_test.go b/pkg/detectors/signable/signable_integration_test.go new file mode 100644 index 000000000000..42b8d9839208 --- /dev/null +++ b/pkg/detectors/signable/signable_integration_test.go @@ -0,0 +1,121 @@ +//go:build detectors +// +build detectors + +package signable + +import ( + "context" + "fmt" + "testing" + "time" + + "github.com/kylelemons/godebug/pretty" + + "github.com/trufflesecurity/trufflehog/v3/pkg/detectors" + + "github.com/trufflesecurity/trufflehog/v3/pkg/common" + "github.com/trufflesecurity/trufflehog/v3/pkg/pb/detectorspb" +) + +func TestSignable_FromChunk(t *testing.T) { + ctx, cancel := context.WithTimeout(context.Background(), time.Second*5) + defer cancel() + testSecrets, err := common.GetSecret(ctx, "trufflehog-testing", "detectors3") + if err != nil { + t.Fatalf("could not get test secrets from GCP: %s", err) + } + secret := testSecrets.MustGetField("SIGNABLE") + inactiveSecret := testSecrets.MustGetField("SIGNABLE_INACTIVE") + + type args struct { + ctx context.Context + data []byte + verify bool + } + tests := []struct { + name string + s Scanner + args args + want []detectors.Result + wantErr bool + }{ + { + name: "found, verified", + s: Scanner{}, + args: args{ + ctx: context.Background(), + data: []byte(fmt.Sprintf("You can find a signable secret %s within", secret)), + verify: true, + }, + want: []detectors.Result{ + { + DetectorType: detectorspb.DetectorType_Signable, + Verified: true, + }, + }, + wantErr: false, + }, + { + name: "found, unverified", + s: Scanner{}, + args: args{ + ctx: context.Background(), + data: []byte(fmt.Sprintf("You can find a signable secret %s within but not valid", inactiveSecret)), // the secret would satisfy the regex but not pass validation + verify: true, + }, + want: []detectors.Result{ + { + DetectorType: detectorspb.DetectorType_Signable, + Verified: false, + }, + }, + wantErr: false, + }, + { + name: "not found", + s: Scanner{}, + args: args{ + ctx: context.Background(), + data: []byte("You cannot find the secret within"), + verify: true, + }, + want: nil, + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + s := Scanner{} + got, err := s.FromData(tt.args.ctx, tt.args.verify, tt.args.data) + if (err != nil) != tt.wantErr { + t.Errorf("Signable.FromData() error = %v, wantErr %v", err, tt.wantErr) + return + } + for i := range got { + if len(got[i].Raw) == 0 { + t.Fatalf("no raw secret present: \n %+v", got[i]) + } + got[i].Raw = nil + } + if diff := pretty.Compare(got, tt.want); diff != "" { + t.Errorf("Signable.FromData() %s diff: (-got +want)\n%s", tt.name, diff) + } + }) + } +} + +func BenchmarkFromData(benchmark *testing.B) { + ctx := context.Background() + s := Scanner{} + for name, data := range detectors.MustGetBenchmarkData() { + benchmark.Run(name, func(b *testing.B) { + b.ResetTimer() + for n := 0; n < b.N; n++ { + _, err := s.FromData(ctx, false, data) + if err != nil { + b.Fatal(err) + } + } + }) + } +} diff --git a/pkg/detectors/signable/signable_test.go b/pkg/detectors/signable/signable_test.go index 74328a79c532..9c99f739c07b 100644 --- a/pkg/detectors/signable/signable_test.go +++ b/pkg/detectors/signable/signable_test.go @@ -1,20 +1,8 @@ -//go:build detectors -// +build detectors - package signable import ( "context" - "fmt" "testing" - "time" - - "github.com/kylelemons/godebug/pretty" - - "github.com/trufflesecurity/trufflehog/v3/pkg/detectors" - - "github.com/trufflesecurity/trufflehog/v3/pkg/common" - "github.com/trufflesecurity/trufflehog/v3/pkg/pb/detectorspb" ) func TestSignable_Pattern(t *testing.T) { @@ -165,106 +153,3 @@ void constraints () 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) + } + }) + } +} + +func TestSaladCloudApiKey_FromChunk(t *testing.T) { + ctx, cancel := context.WithTimeout(context.Background(), time.Second*5) + defer cancel() + testSecrets, err := common.GetSecret(ctx, "trufflehog-testing", "detectors5") + if err != nil { + t.Fatalf("could not get test secrets from GCP: %s", err) + } + secret := testSecrets.MustGetField("SALADCLOUDAPIKEY") + inactiveSecret := testSecrets.MustGetField("SALADCLOUDAPIKEY_INACTIVE") + + 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", + s: Scanner{}, + args: args{ + ctx: context.Background(), + data: []byte(fmt.Sprintf("You can find a SaladCloud API Key secret %s within", secret)), + verify: true, + }, + want: []detectors.Result{ + { + DetectorType: detectorspb.DetectorType_SaladCloudApiKey, + Verified: true, + }, + }, + wantErr: false, + wantVerificationErr: false, + }, + { + name: "found, unverified", + s: Scanner{}, + args: args{ + ctx: context.Background(), + data: []byte(fmt.Sprintf("You can find a SaladCloud API Key secret %s within but not valid", inactiveSecret)), // the secret would satisfy the regex but not pass validation + verify: true, + }, + want: []detectors.Result{ + { + DetectorType: detectorspb.DetectorType_SaladCloudApiKey, + Verified: false, + }, + }, + wantErr: false, + wantVerificationErr: false, + }, + { + name: "not found", + s: Scanner{}, + args: args{ + ctx: context.Background(), + data: []byte("You cannot find the secret within"), + verify: true, + }, + want: nil, + wantErr: false, + wantVerificationErr: false, + }, + { + name: "found, would be verified if not for timeout", + s: Scanner{client: common.SaneHttpClientTimeOut(1 * time.Microsecond)}, + args: args{ + ctx: context.Background(), + data: []byte(fmt.Sprintf("You can find a SaladCloud API Key secret %s within", secret)), + verify: true, + }, + want: []detectors.Result{ + { + DetectorType: detectorspb.DetectorType_SaladCloudApiKey, + Verified: false, + }, + }, + wantErr: false, + wantVerificationErr: true, + }, + { + name: "found, verified but unexpected api surface", + s: Scanner{client: common.ConstantResponseHttpClient(404, "")}, + args: args{ + ctx: context.Background(), + data: []byte(fmt.Sprintf("You can find a SaladCloud API Key secret %s within", secret)), + verify: true, + }, + want: []detectors.Result{ + { + DetectorType: detectorspb.DetectorType_SaladCloudApiKey, + Verified: false, + }, + }, + wantErr: false, + wantVerificationErr: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := tt.s.FromData(tt.args.ctx, tt.args.verify, tt.args.data) + if (err != nil) != tt.wantErr { + t.Errorf("SaladCloudApiKey.FromData() error = %v, wantErr %v", err, tt.wantErr) + return + } + 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.Fatalf("wantVerificationError = %v, verification error = %v", tt.wantVerificationErr, got[i].VerificationError()) + } + } + ignoreOpts := cmpopts.IgnoreFields(detectors.Result{}, "Raw", "verificationError") + if diff := cmp.Diff(got, tt.want, ignoreOpts); diff != "" { + t.Errorf("SaladCloudApiKey.FromData() %s diff: (-got +want)\n%s", tt.name, diff) + } + }) + } +} + +func BenchmarkFromData(benchmark *testing.B) { + ctx := context.Background() + s := Scanner{} + for name, data := range detectors.MustGetBenchmarkData() { + benchmark.Run(name, func(b *testing.B) { + b.ResetTimer() + for n := 0; n < b.N; n++ { + _, err := s.FromData(ctx, false, data) + if err != nil { + b.Fatal(err) + } + } + }) + } +} diff --git a/pkg/engine/defaults.go b/pkg/engine/defaults.go index 16529d3a3102..2283505655b9 100644 --- a/pkg/engine/defaults.go +++ b/pkg/engine/defaults.go @@ -589,6 +589,7 @@ import ( "github.com/trufflesecurity/trufflehog/v3/pkg/detectors/rownd" "github.com/trufflesecurity/trufflehog/v3/pkg/detectors/rubygems" "github.com/trufflesecurity/trufflehog/v3/pkg/detectors/runrunit" + "github.com/trufflesecurity/trufflehog/v3/pkg/detectors/saladcloudapikey" "github.com/trufflesecurity/trufflehog/v3/pkg/detectors/salesblink" "github.com/trufflesecurity/trufflehog/v3/pkg/detectors/salescookie" "github.com/trufflesecurity/trufflehog/v3/pkg/detectors/salesflare" @@ -1636,6 +1637,7 @@ func DefaultDetectors() []detectors.Detector { nvapi.Scanner{}, railwayapp.Scanner{}, meraki.Scanner{}, + saladcloudapikey.Scanner{}, } // Automatically initialize all detectors that implement diff --git a/pkg/pb/detectorspb/detectors.pb.go b/pkg/pb/detectorspb/detectors.pb.go index bf7cd9fc0350..d8febf22cae1 100644 --- a/pkg/pb/detectorspb/detectors.pb.go +++ b/pkg/pb/detectorspb/detectors.pb.go @@ -1102,6 +1102,7 @@ const ( DetectorType_PyPI DetectorType = 998 DetectorType_RailwayApp DetectorType = 999 DetectorType_Meraki DetectorType = 1000 + DetectorType_SaladCloudApiKey DetectorType = 1001 ) // Enum value maps for DetectorType. @@ -2104,6 +2105,7 @@ var ( 998: "PyPI", 999: "RailwayApp", 1000: "Meraki", + 1001: "SaladCloudApiKey", } DetectorType_value = map[string]int32{ "Alibaba": 0, @@ -3103,6 +3105,7 @@ var ( "PyPI": 998, "RailwayApp": 999, "Meraki": 1000, + "SaladCloudApiKey": 1001, } ) @@ -3556,7 +3559,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, 0xe3, 0x7f, 0x0a, 0x0c, 0x44, 0x65, 0x74, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x54, + 0x10, 0x04, 0x2a, 0xfa, 0x7f, 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, 0x0a, @@ -4578,11 +4581,13 @@ var file_detectors_proto_rawDesc = []byte{ 0x10, 0xe4, 0x07, 0x12, 0x0a, 0x0a, 0x05, 0x4e, 0x56, 0x41, 0x50, 0x49, 0x10, 0xe5, 0x07, 0x12, 0x09, 0x0a, 0x04, 0x50, 0x79, 0x50, 0x49, 0x10, 0xe6, 0x07, 0x12, 0x0f, 0x0a, 0x0a, 0x52, 0x61, 0x69, 0x6c, 0x77, 0x61, 0x79, 0x41, 0x70, 0x70, 0x10, 0xe7, 0x07, 0x12, 0x0b, 0x0a, 0x06, 0x4d, - 0x65, 0x72, 0x61, 0x6b, 0x69, 0x10, 0xe8, 0x07, 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, + 0x65, 0x72, 0x61, 0x6b, 0x69, 0x10, 0xe8, 0x07, 0x12, 0x15, 0x0a, 0x10, 0x53, 0x61, 0x6c, 0x61, + 0x64, 0x43, 0x6c, 0x6f, 0x75, 0x64, 0x41, 0x70, 0x69, 0x4b, 0x65, 0x79, 0x10, 0xe9, 0x07, 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 371a71d7251d..2e2748df74c6 100644 --- a/proto/detectors.proto +++ b/proto/detectors.proto @@ -1010,6 +1010,7 @@ enum DetectorType { PyPI = 998; RailwayApp = 999; Meraki = 1000; + SaladCloudApiKey = 1001; } message Result { From 3ac63414a2dfb36a51bec935b58e1b629ee59b51 Mon Sep 17 00:00:00 2001 From: Zachary Rice Date: Fri, 11 Oct 2024 11:55:38 -0500 Subject: [PATCH 18/76] add description to salad (#3397) --- pkg/detectors/saladcloudapikey/saladcloudapikey.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/pkg/detectors/saladcloudapikey/saladcloudapikey.go b/pkg/detectors/saladcloudapikey/saladcloudapikey.go index b6cf5d2611ea..910b7235cee5 100644 --- a/pkg/detectors/saladcloudapikey/saladcloudapikey.go +++ b/pkg/detectors/saladcloudapikey/saladcloudapikey.go @@ -31,6 +31,10 @@ func (s Scanner) Keywords() []string { return []string{"salad_cloud_"} } +func (s Scanner) Description() string { + return "Salad-API-Key detector" +} + // FromData will find and optionally verify SaladCloud API Key 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) From fe979781436b6f665d85c1ee6a55f9dfee616403 Mon Sep 17 00:00:00 2001 From: Miccah Date: Fri, 11 Oct 2024 11:49:23 -0700 Subject: [PATCH 19/76] [chore] Update custom detector default description (#3398) --- pkg/custom_detectors/custom_detectors.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/custom_detectors/custom_detectors.go b/pkg/custom_detectors/custom_detectors.go index f209fcd36abe..602e7f89bd52 100644 --- a/pkg/custom_detectors/custom_detectors.go +++ b/pkg/custom_detectors/custom_detectors.go @@ -255,7 +255,7 @@ func (c *CustomRegexWebhook) Type() detectorspb.DetectorType { return detectorspb.DetectorType_CustomRegex } -const defaultDescription = "This is a customer-defined detector with no description provided." +const defaultDescription = "This is a user-defined detector with no description provided." func (c *CustomRegexWebhook) Description() string { if c.GetDescription() == "" { From 67a3b6df355094b376bab06d0f612e989c05b01f Mon Sep 17 00:00:00 2001 From: ahrav Date: Fri, 11 Oct 2024 13:14:03 -0700 Subject: [PATCH 20/76] fix tests (#3400) --- pkg/handlers/handlers_test.go | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/pkg/handlers/handlers_test.go b/pkg/handlers/handlers_test.go index 418a54db8517..f4c3c54f26c8 100644 --- a/pkg/handlers/handlers_test.go +++ b/pkg/handlers/handlers_test.go @@ -468,15 +468,17 @@ func TestHandleZipCommandStdoutPipe(t *testing.T) { assert.NoError(t, err) }() - err = cmd.Wait() - assert.NoError(t, err) - wantCount := 8 count := 0 for range chunkCh { count++ } + // cmd.Wait() should be called after all the reading from the pipe is done. + // https://cs.opensource.google/go/go/+/refs/tags/go1.23.2:src/os/exec/exec.go;l=1051-1053 + err = cmd.Wait() + assert.NoError(t, err) + assert.Equal(t, wantCount, count) } @@ -543,14 +545,16 @@ func TestHandleGitCatFile(t *testing.T) { assert.NoError(t, err, "HandleFile should not return an error") }() - err = cmd.Wait() - assert.NoError(t, err, "git cat-file command should complete without error") - count := 0 for range chunkCh { count++ } + // cmd.Wait() should be called after all the reading from the pipe is done. + // https://cs.opensource.google/go/go/+/refs/tags/go1.23.2:src/os/exec/exec.go;l=1051-1053 + err = cmd.Wait() + assert.NoError(t, err, "git cat-file command should complete without error") + assert.Equal(t, tt.expectedChunks, count, "Number of chunks should match the expected value") }) } From cf54b71a9410df1960bad536b227958e776ace71 Mon Sep 17 00:00:00 2001 From: Kyle Dodson Date: Fri, 11 Oct 2024 15:55:29 -0700 Subject: [PATCH 21/76] Update SaladCloud description (#3399) --- pkg/detectors/saladcloudapikey/saladcloudapikey.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/detectors/saladcloudapikey/saladcloudapikey.go b/pkg/detectors/saladcloudapikey/saladcloudapikey.go index 910b7235cee5..3da22cc2d68a 100644 --- a/pkg/detectors/saladcloudapikey/saladcloudapikey.go +++ b/pkg/detectors/saladcloudapikey/saladcloudapikey.go @@ -32,7 +32,7 @@ func (s Scanner) Keywords() []string { } func (s Scanner) Description() string { - return "Salad-API-Key detector" + return "SaladCloud is a cloud service provider offering GPUs and NPUs for high-performance computing. SaladCloud API keys can be used to access and modify compute and data resources in your account." } // FromData will find and optionally verify SaladCloud API Key secrets in a given set of bytes. From eb8dc53f5e75fad4721f50045f89e50860b9e9f3 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 14 Oct 2024 12:55:41 -0700 Subject: [PATCH 22/76] fix(deps): update module github.com/gabriel-vasile/mimetype to v1.4.6 (#3407) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- go.mod | 2 +- go.sum | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/go.mod b/go.mod index f4f0358ea0a9..820254700bcd 100644 --- a/go.mod +++ b/go.mod @@ -40,7 +40,7 @@ require ( github.com/envoyproxy/protoc-gen-validate v1.1.0 github.com/fatih/color v1.17.0 github.com/felixge/fgprof v0.9.5 - github.com/gabriel-vasile/mimetype v1.4.5 + github.com/gabriel-vasile/mimetype v1.4.6 github.com/getsentry/sentry-go v0.29.0 github.com/go-errors/errors v1.5.1 github.com/go-git/go-git/v5 v5.12.0 diff --git a/go.sum b/go.sum index 35fe649bb046..b4c940cb2fe2 100644 --- a/go.sum +++ b/go.sum @@ -301,6 +301,8 @@ github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4 github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= github.com/gabriel-vasile/mimetype v1.4.5 h1:J7wGKdGu33ocBOhGy0z653k/lFKLFDPJMG8Gql0kxn4= github.com/gabriel-vasile/mimetype v1.4.5/go.mod h1:ibHel+/kbxn9x2407k1izTA1S81ku1z/DlgOW2QE0M4= +github.com/gabriel-vasile/mimetype v1.4.6 h1:3+PzJTKLkvgjeTbts6msPJt4DixhT4YtFNf1gtGe3zc= +github.com/gabriel-vasile/mimetype v1.4.6/go.mod h1:JX1qVKqZd40hUPpAfiNTe0Sne7hdfKSbOqqmkq8GCXc= github.com/getsentry/sentry-go v0.29.0 h1:YtWluuCFg9OfcqnaujpY918N/AhCCwarIDWOYSBAjCA= github.com/getsentry/sentry-go v0.29.0/go.mod h1:jhPesDAL0Q0W2+2YEuVOvdWmVtdsr1+jtBrlDEVWwLY= github.com/gliderlabs/ssh v0.3.7 h1:iV3Bqi942d9huXnzEF2Mt+CY9gLu8DNM4Obd+8bODRE= From e62939fb6e44834f91c4d70023a4385e927b3e81 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 14 Oct 2024 13:21:07 -0700 Subject: [PATCH 23/76] fix(deps): update module github.com/getsentry/sentry-go to v0.29.1 (#3408) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- go.mod | 2 +- go.sum | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/go.mod b/go.mod index 820254700bcd..6eb1a144a98e 100644 --- a/go.mod +++ b/go.mod @@ -41,7 +41,7 @@ require ( github.com/fatih/color v1.17.0 github.com/felixge/fgprof v0.9.5 github.com/gabriel-vasile/mimetype v1.4.6 - github.com/getsentry/sentry-go v0.29.0 + github.com/getsentry/sentry-go v0.29.1 github.com/go-errors/errors v1.5.1 github.com/go-git/go-git/v5 v5.12.0 github.com/go-ldap/ldap/v3 v3.4.8 diff --git a/go.sum b/go.sum index b4c940cb2fe2..ceb5c1e7b823 100644 --- a/go.sum +++ b/go.sum @@ -305,6 +305,8 @@ github.com/gabriel-vasile/mimetype v1.4.6 h1:3+PzJTKLkvgjeTbts6msPJt4DixhT4YtFNf github.com/gabriel-vasile/mimetype v1.4.6/go.mod h1:JX1qVKqZd40hUPpAfiNTe0Sne7hdfKSbOqqmkq8GCXc= github.com/getsentry/sentry-go v0.29.0 h1:YtWluuCFg9OfcqnaujpY918N/AhCCwarIDWOYSBAjCA= github.com/getsentry/sentry-go v0.29.0/go.mod h1:jhPesDAL0Q0W2+2YEuVOvdWmVtdsr1+jtBrlDEVWwLY= +github.com/getsentry/sentry-go v0.29.1 h1:DyZuChN8Hz3ARxGVV8ePaNXh1dQ7d76AiB117xcREwA= +github.com/getsentry/sentry-go v0.29.1/go.mod h1:x3AtIzN01d6SiWkderzaH28Tm0lgkafpJ5Bm3li39O0= github.com/gliderlabs/ssh v0.3.7 h1:iV3Bqi942d9huXnzEF2Mt+CY9gLu8DNM4Obd+8bODRE= github.com/gliderlabs/ssh v0.3.7/go.mod h1:zpHEXBstFnQYtGnB8k8kQLol82umzn/2/snG7alWVD8= github.com/go-asn1-ber/asn1-ber v1.5.5 h1:MNHlNMBDgEKD4TcKr36vQN68BA00aDfjIt3/bD50WnA= From e6281ca6412d412a57189398411495e955ed47bc Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 14 Oct 2024 17:11:56 -0700 Subject: [PATCH 24/76] fix(deps): update module github.com/xanzy/go-gitlab to v0.112.0 (#3410) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- go.mod | 2 +- go.sum | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/go.mod b/go.mod index 6eb1a144a98e..3b4d7ce80ff8 100644 --- a/go.mod +++ b/go.mod @@ -96,7 +96,7 @@ require ( github.com/testcontainers/testcontainers-go/modules/postgres v0.33.0 github.com/trufflesecurity/disk-buffer-reader v0.2.1 github.com/wasilibs/go-re2 v1.7.0 - github.com/xanzy/go-gitlab v0.111.0 + github.com/xanzy/go-gitlab v0.112.0 github.com/xo/dburl v0.23.2 go.mongodb.org/mongo-driver v1.17.1 go.uber.org/automaxprocs v1.6.0 diff --git a/go.sum b/go.sum index ceb5c1e7b823..90700c1ad38f 100644 --- a/go.sum +++ b/go.sum @@ -788,6 +788,8 @@ github.com/xanzy/go-gitlab v0.110.0 h1:hsFIFp01v/0D0sdUXoZfRk6CROzZbHQplk6NzKSFK github.com/xanzy/go-gitlab v0.110.0/go.mod h1:wKNKh3GkYDMOsGmnfuX+ITCmDuSDWFO0G+C4AygL9RY= github.com/xanzy/go-gitlab v0.111.0 h1:4zT52QdDVxGYAGxN2VY8upSvZIiuiI+Z4d+c+7D/lII= github.com/xanzy/go-gitlab v0.111.0/go.mod h1:wKNKh3GkYDMOsGmnfuX+ITCmDuSDWFO0G+C4AygL9RY= +github.com/xanzy/go-gitlab v0.112.0 h1:6Z0cqEooCvBMfBIHw+CgO4AKGRV8na/9781xOb0+DKw= +github.com/xanzy/go-gitlab v0.112.0/go.mod h1:wKNKh3GkYDMOsGmnfuX+ITCmDuSDWFO0G+C4AygL9RY= github.com/xanzy/ssh-agent v0.3.3 h1:+/15pJfg/RsTxqYcX6fHqOXZwwMP+2VyYWJeWM2qQFM= github.com/xanzy/ssh-agent v0.3.3/go.mod h1:6dzNDKs0J9rVPHPhaGCukekBHKqfl+L3KghI1Bc68Uw= github.com/xdg-go/pbkdf2 v1.0.0 h1:Su7DPu48wXMwC3bs7MCNG+z4FhcyEuz5dlvchbq0B0c= From 34e443adcf1548e573a9d8f8496efb49b5d8a9c1 Mon Sep 17 00:00:00 2001 From: Richard Gomez <32133502+rgmz@users.noreply.github.com> Date: Mon, 14 Oct 2024 20:13:39 -0400 Subject: [PATCH 25/76] feat: propagate file info in log context (#3405) --- pkg/sources/filesystem/filesystem.go | 6 +++--- pkg/sources/git/git.go | 31 ++++++++-------------------- pkg/sources/github/github.go | 6 ++++-- 3 files changed, 16 insertions(+), 27 deletions(-) diff --git a/pkg/sources/filesystem/filesystem.go b/pkg/sources/filesystem/filesystem.go index 74ae9bcae133..98805882d932 100644 --- a/pkg/sources/filesystem/filesystem.go +++ b/pkg/sources/filesystem/filesystem.go @@ -153,7 +153,7 @@ func (s *Source) scanDir(ctx context.Context, path string, chunksChan chan *sour var skipSymlinkErr = errors.New("skipping symlink") func (s *Source) scanFile(ctx context.Context, path string, chunksChan chan *sources.Chunk) error { - logger := ctx.Logger().WithValues("path", path) + fileCtx := context.WithValues(ctx, "path", path) fileStat, err := os.Lstat(path) if err != nil { return fmt.Errorf("unable to stat file: %w", err) @@ -168,7 +168,7 @@ func (s *Source) scanFile(ctx context.Context, path string, chunksChan chan *sou } defer inputFile.Close() - logger.V(3).Info("scanning file") + fileCtx.Logger().V(3).Info("scanning file") chunkSkel := &sources.Chunk{ SourceType: s.Type(), @@ -185,7 +185,7 @@ func (s *Source) scanFile(ctx context.Context, path string, chunksChan chan *sou Verify: s.verify, } - return handlers.HandleFile(ctx, inputFile, chunkSkel, sources.ChanReporter{Ch: chunksChan}) + return handlers.HandleFile(fileCtx, inputFile, chunkSkel, sources.ChanReporter{Ch: chunksChan}) } // Enumerate implements SourceUnitEnumerator interface. This implementation simply diff --git a/pkg/sources/git/git.go b/pkg/sources/git/git.go index ca6f82f967b6..c6d35c436e45 100644 --- a/pkg/sources/git/git.go +++ b/pkg/sources/git/git.go @@ -657,9 +657,8 @@ func (s *Git) ScanCommits(ctx context.Context, repo *git.Repository, path string logger.Error( err, "error handling binary file", - "filename", fileName, "commit", commitHash, - "file", diff.PathB, + "path", fileName, ) } continue @@ -677,9 +676,8 @@ func (s *Git) ScanCommits(ctx context.Context, repo *git.Repository, path string if err != nil { ctx.Logger().Error( err, "error creating reader for commits", - "filename", fileName, "commit", fullHash, - "file", diff.PathB, + "path", fileName, ) return nil } @@ -687,11 +685,10 @@ func (s *Git) ScanCommits(ctx context.Context, repo *git.Repository, path string data := make([]byte, d.Len()) if _, err := io.ReadFull(reader, data); err != nil { - ctx.Logger().Error( + logger.Error( err, "error reading diff content for commit", - "filename", fileName, "commit", fullHash, - "file", diff.PathB, + "path", fileName, ) return nil } @@ -829,7 +826,7 @@ func (s *Git) ScanStaged(ctx context.Context, repo *git.Repository, path string, ) for diff := range diffChan { fullHash := diff.Commit.Hash - logger := ctx.Logger().WithValues("filename", diff.PathB, "commit", fullHash, "file", diff.PathB) + logger := ctx.Logger().WithValues("commit", fullHash, "path", diff.PathB) logger.V(2).Info("scanning staged changes from git") if scanOptions.MaxDepth > 0 && depth >= scanOptions.MaxDepth { @@ -877,7 +874,7 @@ func (s *Git) ScanStaged(ctx context.Context, repo *git.Repository, path string, Verify: s.verify, } if err := s.handleBinary(ctx, gitDir, reporter, chunkSkel, commitHash, fileName); err != nil { - logger.Error(err, "error handling binary file", "filename", fileName) + logger.Error(err, "error handling binary file") } continue } @@ -887,24 +884,14 @@ func (s *Git) ScanStaged(ctx context.Context, repo *git.Repository, path string, reader, err := d.ReadCloser() if err != nil { - ctx.Logger().Error( - err, "error creating reader for staged", - "filename", fileName, - "commit", fullHash, - "file", diff.PathB, - ) + logger.Error(err, "error creating reader for staged") return nil } defer reader.Close() data := make([]byte, d.Len()) if _, err := reader.Read(data); err != nil { - ctx.Logger().Error( - err, "error reading diff content for staged", - "filename", fileName, - "commit", fullHash, - "file", diff.PathB, - ) + logger.Error(err, "error reading diff content for staged") return nil } chunk := sources.Chunk{ @@ -1255,7 +1242,7 @@ func (s *Git) handleBinary(ctx context.Context, gitDir string, reporter sources. defer func() { _ = cmd.Wait() }() - return handlers.HandleFile(ctx, stdout, chunkSkel, reporter, handlers.WithSkipArchives(s.skipArchives)) + return handlers.HandleFile(fileCtx, stdout, chunkSkel, reporter, handlers.WithSkipArchives(s.skipArchives)) } func (s *Source) Enumerate(ctx context.Context, reporter sources.UnitReporter) error { diff --git a/pkg/sources/github/github.go b/pkg/sources/github/github.go index b5d3ef90e487..8c945834731d 100644 --- a/pkg/sources/github/github.go +++ b/pkg/sources/github/github.go @@ -1492,8 +1492,10 @@ func (s *Source) scanTarget(ctx context.Context, target sources.ChunkingTarget, SourceMetadata: &source_metadatapb.MetaData{ Data: &source_metadatapb.MetaData_Github{Github: meta}, }, - Verify: s.verify} - return handlers.HandleFile(ctx, readCloser, &chunkSkel, reporter) + Verify: s.verify, + } + fileCtx := context.WithValues(ctx, "path", meta.GetFile()) + return handlers.HandleFile(fileCtx, readCloser, &chunkSkel, reporter) } func (s *Source) ChunkUnit(ctx context.Context, unit sources.SourceUnit, reporter sources.ChunkReporter) error { From aa17b8eba486bbdf19bc77aedb3c56f9cb00e1ac Mon Sep 17 00:00:00 2001 From: Abdul Basit Date: Tue, 15 Oct 2024 18:42:37 +0500 Subject: [PATCH 26/76] [detector] Implemented Box Detector (#3242) * Implemented a box detector with test cases. * corrected comments * remove generic keyword for box detector remove PII details of user. * Added Box Oauth detector Implemented description for Box detectors. Separated out test for Box detectors. * removed user information from ExtraData. --------- Co-authored-by: 0x1 <13666360+0x1@users.noreply.github.com> --- pkg/detectors/box/box.go | 127 + pkg/detectors/box/box_integration_test.go | 165 ++ pkg/detectors/box/box_test.go | 72 + pkg/detectors/boxoauth/boxoauth.go | 138 ++ .../boxoauth/boxoauth_integration_test.go | 129 + pkg/detectors/boxoauth/boxoauth_test.go | 91 + pkg/engine/defaults.go | 4 + pkg/pb/detectorspb/detectors.pb.go | 2065 +++++++++-------- proto/detectors.proto | 2 + 9 files changed, 1764 insertions(+), 1029 deletions(-) create mode 100644 pkg/detectors/box/box.go create mode 100644 pkg/detectors/box/box_integration_test.go create mode 100644 pkg/detectors/box/box_test.go create mode 100644 pkg/detectors/boxoauth/boxoauth.go create mode 100644 pkg/detectors/boxoauth/boxoauth_integration_test.go create mode 100644 pkg/detectors/boxoauth/boxoauth_test.go diff --git a/pkg/detectors/box/box.go b/pkg/detectors/box/box.go new file mode 100644 index 000000000000..fb92f1913fde --- /dev/null +++ b/pkg/detectors/box/box.go @@ -0,0 +1,127 @@ +package box + +import ( + "context" + "encoding/json" + "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" +) + +type Scanner struct { + client *http.Client +} + +// Ensure the Scanner satisfies the interface at compile time. +var _ detectors.Detector = (*Scanner)(nil) + +var ( + defaultClient = common.SaneHttpClient() + // Make sure that your group is surrounded in boundary characters such as below to reduce false positives. + keyPat = regexp.MustCompile(detectors.PrefixRegex([]string{"box"}) + `\b([0-9a-zA-Z]{32})\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{"box"} +} + +func (s Scanner) Description() string { + return "Box is a service offering various service for secure collaboration, content management, and workflow. Box token can be used to access and interact with this data." +} + +// FromData will find and optionally verify Box 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) + + uniqueMatches := make(map[string]struct{}) + for _, match := range keyPat.FindAllStringSubmatch(dataStr, -1) { + uniqueMatches[match[1]] = struct{}{} + } + + for match := range uniqueMatches { + s1 := detectors.Result{ + DetectorType: detectorspb.DetectorType_Box, + Raw: []byte(match), + } + + if verify { + client := s.client + if client == nil { + client = defaultClient + } + + isVerified, extraData, verificationErr := verifyMatch(ctx, client, match) + s1.Verified = isVerified + s1.ExtraData = extraData + s1.SetVerificationError(verificationErr, match) + } + + results = append(results, s1) + } + + return +} + +func verifyMatch(ctx context.Context, client *http.Client, token string) (bool, map[string]string, error) { + url := "https://api.box.com/2.0/users/me" + req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil) + if err != nil { + return false, nil, nil + } + + req.Header = http.Header{"Authorization": []string{"Bearer " + token}} + req.Header.Add("content-type", "application/json") + + res, err := client.Do(req) + if err != nil { + return false, nil, err + } + defer func() { + _, _ = io.Copy(io.Discard, res.Body) + _ = res.Body.Close() + }() + + switch res.StatusCode { + case http.StatusOK: + { + var u user + if err := json.NewDecoder(res.Body).Decode(&u); err != nil { + return false, nil, err + } + return true, bakeExtraDataFromUser(u), nil + } + case http.StatusUnauthorized: + // 401 access token not found + // The secret is determinately not verified (nothing to do) + return false, nil, nil + default: + return false, nil, fmt.Errorf("unexpected HTTP response status %d", res.StatusCode) + } +} + +func (s Scanner) Type() detectorspb.DetectorType { + return detectorspb.DetectorType_Box +} + +func bakeExtraDataFromUser(u user) map[string]string { + return map[string]string{ + "user_id": u.ID, + "username": u.Login, + "user_status": u.Status, + } +} + +// struct to represent a Box user. +type user struct { + ID string `json:"id"` + Login string `json:"login"` + Status string `json:"status"` +} diff --git a/pkg/detectors/box/box_integration_test.go b/pkg/detectors/box/box_integration_test.go new file mode 100644 index 000000000000..2c887d56bef1 --- /dev/null +++ b/pkg/detectors/box/box_integration_test.go @@ -0,0 +1,165 @@ +//go:build detectors +// +build detectors + +package box + +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 TestBox_FromChunk(t *testing.T) { + ctx, cancel := context.WithTimeout(context.Background(), time.Second*5) + defer cancel() + testSecrets, err := common.GetSecret(ctx, "trufflehog-testing", "detectors5") + if err != nil { + t.Fatalf("could not get test secrets from GCP: %s", err) + } + token := testSecrets.MustGetField("BOX_ACCESS_TOKEN") + inactiveToken := testSecrets.MustGetField("BOX_ACCESS_TOKEN_INACTIVE") + + 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", + s: Scanner{}, + args: args{ + ctx: context.Background(), + data: []byte(fmt.Sprintf("You can find a box token %s within", token)), + verify: true, + }, + want: []detectors.Result{ + { + DetectorType: detectorspb.DetectorType_Box, + Verified: true, + Raw: []byte(token), + }, + }, + wantErr: false, + wantVerificationErr: false, + }, + { + name: "found, unverified", + s: Scanner{}, + args: args{ + ctx: context.Background(), + data: []byte(fmt.Sprintf("You can find a box token %s within but not valid", inactiveToken)), // the secret would satisfy the regex but not pass validation + verify: true, + }, + want: []detectors.Result{ + { + DetectorType: detectorspb.DetectorType_Box, + Verified: false, + Raw: []byte(inactiveToken), + }, + }, + wantErr: false, + wantVerificationErr: false, + }, + { + name: "not found", + s: Scanner{}, + args: args{ + ctx: context.Background(), + data: []byte("You cannot find the secret within"), + verify: true, + }, + want: nil, + wantErr: false, + wantVerificationErr: false, + }, + { + name: "found, would be verified if not for timeout", + s: Scanner{client: common.SaneHttpClientTimeOut(1 * time.Microsecond)}, + args: args{ + ctx: context.Background(), + data: []byte(fmt.Sprintf("You can find a box token %s within", token)), + verify: true, + }, + want: []detectors.Result{ + { + DetectorType: detectorspb.DetectorType_Box, + Verified: false, + Raw: []byte(token), + }, + }, + wantErr: false, + wantVerificationErr: true, + }, + { + name: "found, verified but unexpected api surface", + s: Scanner{client: common.ConstantResponseHttpClient(500, "")}, + args: args{ + ctx: context.Background(), + data: []byte(fmt.Sprintf("You can find a box secret %s within", token)), + verify: true, + }, + want: []detectors.Result{ + { + DetectorType: detectorspb.DetectorType_Box, + Verified: false, + Raw: []byte(token), + }, + }, + wantErr: false, + wantVerificationErr: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := tt.s.FromData(tt.args.ctx, tt.args.verify, tt.args.data) + if (err != nil) != tt.wantErr { + t.Errorf("Box.FromData() error = %v, wantErr %v", err, tt.wantErr) + return + } + 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.Fatalf("wantVerificationError = %v, verification error = %v", tt.wantVerificationErr, got[i].VerificationError()) + } + } + ignoreOpts := cmpopts.IgnoreFields(detectors.Result{}, "verificationError", "ExtraData") + if diff := cmp.Diff(got, tt.want, ignoreOpts); diff != "" { + t.Errorf("Box.FromData() %s diff: (-got +want)\n%s", tt.name, diff) + } + }) + } +} + +func BenchmarkFromData(benchmark *testing.B) { + ctx := context.Background() + s := Scanner{} + for name, data := range detectors.MustGetBenchmarkData() { + benchmark.Run(name, func(b *testing.B) { + b.ResetTimer() + for n := 0; n < b.N; n++ { + _, err := s.FromData(ctx, false, data) + if err != nil { + b.Fatal(err) + } + } + }) + } +} diff --git a/pkg/detectors/box/box_test.go b/pkg/detectors/box/box_test.go new file mode 100644 index 000000000000..cea5ee94b503 --- /dev/null +++ b/pkg/detectors/box/box_test.go @@ -0,0 +1,72 @@ +//go:build detectors +// +build detectors + +package box + +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 TestBox_Pattern(t *testing.T) { + d := Scanner{} + ahoCorasickCore := ahocorasick.NewAhoCorasickCore([]detectors.Detector{d}) + tests := []struct { + name string + input string + want []string + }{ + { + name: "typical pattern", + input: "box_access_token = 'Ogowv5cj5AJJjO5F3daNHbKJDdPud0CZ'", + want: []string{"Ogowv5cj5AJJjO5F3daNHbKJDdPud0CZ"}, + }, + } + + 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/boxoauth/boxoauth.go b/pkg/detectors/boxoauth/boxoauth.go new file mode 100644 index 000000000000..dee8050f79dd --- /dev/null +++ b/pkg/detectors/boxoauth/boxoauth.go @@ -0,0 +1,138 @@ +package boxoauth + +import ( + "context" + "fmt" + "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" +) + +type Scanner struct { + client *http.Client +} + +// Ensure the Scanner satisfies the interface at compile time. +var _ detectors.Detector = (*Scanner)(nil) + +var ( + defaultClient = common.SaneHttpClient() + // Make sure that your group is surrounded in boundary characters such as below to reduce false positives. + clientIdPat = regexp.MustCompile(detectors.PrefixRegex([]string{"id"}) + `\b([a-zA-Z0-9]{32})\b`) + clientSecretPat = regexp.MustCompile(detectors.PrefixRegex([]string{"secret"}) + `\b([a-zA-Z0-9]{32})\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{"box"} +} + +func (s Scanner) Description() string { + return "Box is a service offering various service for secure collaboration, content management, and workflow. Box Oauth credentials can be used to access and interact with this data." +} + +// FromData will find and optionally verify Box 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) + + uniqueIdMatches := make(map[string]struct{}) + for _, match := range clientIdPat.FindAllStringSubmatch(dataStr, -1) { + uniqueIdMatches[match[1]] = struct{}{} + } + + uniqueSecretMatches := make(map[string]struct{}) + for _, match := range clientSecretPat.FindAllStringSubmatch(dataStr, -1) { + uniqueSecretMatches[match[1]] = struct{}{} + } + + for resIdMatch := range uniqueIdMatches { + for resSecretMatch := range uniqueSecretMatches { + + // ignore if the id and secret are the same + if resIdMatch == resSecretMatch { + continue + } + + s1 := detectors.Result{ + DetectorType: detectorspb.DetectorType_BoxOauth, + Raw: []byte(resIdMatch), + RawV2: []byte(resIdMatch + resSecretMatch), + } + + if verify { + client := s.client + if client == nil { + client = defaultClient + } + + isVerified, extraData, verificationErr := verifyMatch(ctx, client, resIdMatch, resSecretMatch) + s1.Verified = isVerified + s1.ExtraData = extraData + s1.SetVerificationError(verificationErr, resIdMatch) + } + + results = append(results, s1) + + // box client supportes only one client id and secret pair + if s1.Verified { + break + } + } + } + + return +} + +func verifyMatch(ctx context.Context, client *http.Client, id string, secret string) (bool, map[string]string, error) { + url := "https://api.box.com/oauth2/token" + payload := strings.NewReader("grant_type=client_credentials&client_id=" + id + "&client_secret=" + secret) + req, err := http.NewRequestWithContext(ctx, http.MethodPost, url, payload) + if err != nil { + return false, nil, nil + } + + req.Header = http.Header{"content-type": []string{"application/x-www-form-urlencoded"}} + + res, err := client.Do(req) + if err != nil { + return false, nil, err + } + defer func() { + _, _ = io.Copy(io.Discard, res.Body) + _ = res.Body.Close() + }() + + // We are using malformed request to check if the client id and secret are correct + // box oauth api returns 400 status code even if they are correct + // so we need to check the response body for the error message with 'unauthorized_client' keyword + // or if invalid_client keyword is present then the client id & secret are incorrect + switch res.StatusCode { + case http.StatusBadRequest: + { + bodyBytes, err := io.ReadAll(res.Body) + if err != nil { + return false, nil, err + } + body := string(bodyBytes) + + if strings.Contains(body, "unauthorized_client") { + return true, nil, nil + } + + return false, nil, nil + } + default: + return false, nil, fmt.Errorf("unexpected HTTP response status %d", res.StatusCode) + } +} + +func (s Scanner) Type() detectorspb.DetectorType { + return detectorspb.DetectorType_BoxOauth +} diff --git a/pkg/detectors/boxoauth/boxoauth_integration_test.go b/pkg/detectors/boxoauth/boxoauth_integration_test.go new file mode 100644 index 000000000000..e9790ef49224 --- /dev/null +++ b/pkg/detectors/boxoauth/boxoauth_integration_test.go @@ -0,0 +1,129 @@ +//go:build detectors +// +build detectors + +package boxoauth + +import ( + "context" + "fmt" + "testing" + "time" + + "github.com/kylelemons/godebug/pretty" + + "github.com/trufflesecurity/trufflehog/v3/pkg/common" + "github.com/trufflesecurity/trufflehog/v3/pkg/detectors" + "github.com/trufflesecurity/trufflehog/v3/pkg/pb/detectorspb" +) + +func TestBoxOauth_FromChunk(t *testing.T) { + ctx, cancel := context.WithTimeout(context.Background(), time.Second*5) + defer cancel() + testSecrets, err := common.GetSecret(ctx, "trufflehog-testing", "detectors5") + if err != nil { + t.Fatalf("could not get test secrets from GCP: %s", err) + } + + id := testSecrets.MustGetField("BOXOAUTH_ID") + secret := testSecrets.MustGetField("BOXOAUTH_SECRET") + invalidSecret := testSecrets.MustGetField("BOXOAUTH_INVALID_SECRET") + + type args struct { + ctx context.Context + data []byte + verify bool + } + tests := []struct { + name string + s Scanner + args args + want []detectors.Result + wantErr bool + }{ + { + name: "found, verified", + s: Scanner{}, + args: args{ + ctx: context.Background(), + data: []byte(fmt.Sprintf("You can find a box id %s with secret %s", id, secret)), + verify: true, + }, + want: []detectors.Result{ + { + DetectorType: detectorspb.DetectorType_BoxOauth, + Verified: true, + Raw: []byte(id), + RawV2: []byte(id + secret), + }, + }, + wantErr: false, + }, + { + name: "found, unverified", + s: Scanner{}, + args: args{ + ctx: context.Background(), + data: []byte(fmt.Sprintf("You can find a box id %s with secret %s", id, invalidSecret)), + verify: true, + }, + want: []detectors.Result{ + { + DetectorType: detectorspb.DetectorType_BoxOauth, + Verified: false, + Raw: []byte(id), + RawV2: []byte(id + invalidSecret), + }, + }, + wantErr: false, + }, + { + name: "not found", + s: Scanner{}, + args: args{ + ctx: context.Background(), + data: []byte("You cannot find the secret within"), + verify: true, + }, + want: nil, + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + s := Scanner{} + got, err := s.FromData(tt.args.ctx, tt.args.verify, tt.args.data) + if (err != nil) != tt.wantErr { + t.Errorf("BoxOauth.FromData() error = %v, wantErr %v", err, tt.wantErr) + return + } + for i := range got { + if len(got[i].Raw) == 0 { + t.Fatalf("no raw secret present: \n %+v", got[i]) + } + + if len(got[i].Raw) == 0 { + t.Fatalf("no rawV2 secret present: \n %+v", got[i]) + } + } + if diff := pretty.Compare(got, tt.want); diff != "" { + t.Errorf("BoxOauth.FromData() %s diff: (-got +want)\n%s", tt.name, diff) + } + }) + } +} + +func BenchmarkFromData(benchmark *testing.B) { + ctx := context.Background() + s := Scanner{} + for name, data := range detectors.MustGetBenchmarkData() { + benchmark.Run(name, func(b *testing.B) { + b.ResetTimer() + for n := 0; n < b.N; n++ { + _, err := s.FromData(ctx, false, data) + if err != nil { + b.Fatal(err) + } + } + }) + } +} diff --git a/pkg/detectors/boxoauth/boxoauth_test.go b/pkg/detectors/boxoauth/boxoauth_test.go new file mode 100644 index 000000000000..ae5d85e6e6d9 --- /dev/null +++ b/pkg/detectors/boxoauth/boxoauth_test.go @@ -0,0 +1,91 @@ +//go:build detectors +// +build detectors + +package boxoauth + +import ( + "context" + "fmt" + "testing" + + "github.com/google/go-cmp/cmp" + + "github.com/brianvoe/gofakeit/v7" + "github.com/trufflesecurity/trufflehog/v3/pkg/detectors" + "github.com/trufflesecurity/trufflehog/v3/pkg/engine/ahocorasick" +) + +var ( + clientId = gofakeit.Password(true, true, true, false, false, 32) + clientSecret = gofakeit.Password(true, true, true, false, false, 32) + invalidClientSecret = gofakeit.Password(true, true, true, true, false, 32) +) + +func TestBoxOauth_Pattern(t *testing.T) { + d := Scanner{} + ahoCorasickCore := ahocorasick.NewAhoCorasickCore([]detectors.Detector{d}) + + tests := []struct { + name string + input string + want []string + }{ + { + name: "valid pattern", + input: fmt.Sprintf("box id = '%s' box secret = '%s'", clientId, clientSecret), + want: []string{clientId + clientSecret}, + }, + { + name: "invalid pattern", + input: fmt.Sprintf("box id = '%s' box secret = '%s'", clientId, invalidClientSecret), + want: nil, + }, + { + name: "invalid pattern", + input: fmt.Sprintf("box = '%s|%s'", clientId, invalidClientSecret), + want: nil, + }, + } + + 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.go b/pkg/engine/defaults.go index 2283505655b9..96604628c3b5 100644 --- a/pkg/engine/defaults.go +++ b/pkg/engine/defaults.go @@ -90,6 +90,8 @@ import ( "github.com/trufflesecurity/trufflehog/v3/pkg/detectors/bombbomb" "github.com/trufflesecurity/trufflehog/v3/pkg/detectors/boostnote" "github.com/trufflesecurity/trufflehog/v3/pkg/detectors/borgbase" + "github.com/trufflesecurity/trufflehog/v3/pkg/detectors/box" + "github.com/trufflesecurity/trufflehog/v3/pkg/detectors/boxoauth" "github.com/trufflesecurity/trufflehog/v3/pkg/detectors/braintreepayments" "github.com/trufflesecurity/trufflehog/v3/pkg/detectors/brandfetch" "github.com/trufflesecurity/trufflehog/v3/pkg/detectors/browserstack" @@ -1633,11 +1635,13 @@ func DefaultDetectors() []detectors.Detector { atlassianv1.Scanner{}, atlassianv2.Scanner{}, netsuite.Scanner{}, + box.Scanner{}, robinhoodcrypto.Scanner{}, nvapi.Scanner{}, railwayapp.Scanner{}, meraki.Scanner{}, saladcloudapikey.Scanner{}, + boxoauth.Scanner{}, } // Automatically initialize all detectors that implement diff --git a/pkg/pb/detectorspb/detectors.pb.go b/pkg/pb/detectorspb/detectors.pb.go index d8febf22cae1..fabebd5dbf29 100644 --- a/pkg/pb/detectorspb/detectors.pb.go +++ b/pkg/pb/detectorspb/detectors.pb.go @@ -1103,6 +1103,8 @@ const ( DetectorType_RailwayApp DetectorType = 999 DetectorType_Meraki DetectorType = 1000 DetectorType_SaladCloudApiKey DetectorType = 1001 + DetectorType_Box DetectorType = 1002 + DetectorType_BoxOauth DetectorType = 1003 ) // Enum value maps for DetectorType. @@ -2106,6 +2108,8 @@ var ( 999: "RailwayApp", 1000: "Meraki", 1001: "SaladCloudApiKey", + 1002: "Box", + 1003: "BoxOauth", } DetectorType_value = map[string]int32{ "Alibaba": 0, @@ -3106,6 +3110,8 @@ var ( "RailwayApp": 999, "Meraki": 1000, "SaladCloudApiKey": 1001, + "Box": 1002, + "BoxOauth": 1003, } ) @@ -3559,1035 +3565,1036 @@ 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, 0xfa, 0x7f, 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, 0x0a, - 0x0a, 0x06, 0x43, 0x69, 0x72, 0x63, 0x6c, 0x65, 0x10, 0x04, 0x12, 0x0c, 0x0a, 0x08, 0x43, 0x6f, - 0x69, 0x6e, 0x62, 0x61, 0x73, 0x65, 0x10, 0x05, 0x12, 0x07, 0x0a, 0x03, 0x47, 0x43, 0x50, 0x10, - 0x06, 0x12, 0x0b, 0x0a, 0x07, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x69, 0x63, 0x10, 0x07, 0x12, 0x0a, - 0x0a, 0x06, 0x47, 0x69, 0x74, 0x68, 0x75, 0x62, 0x10, 0x08, 0x12, 0x0a, 0x0a, 0x06, 0x47, 0x69, - 0x74, 0x6c, 0x61, 0x62, 0x10, 0x09, 0x12, 0x08, 0x0a, 0x04, 0x4a, 0x44, 0x42, 0x43, 0x10, 0x0a, - 0x12, 0x0c, 0x0a, 0x08, 0x52, 0x61, 0x7a, 0x6f, 0x72, 0x50, 0x61, 0x79, 0x10, 0x0b, 0x12, 0x0c, - 0x0a, 0x08, 0x53, 0x65, 0x6e, 0x64, 0x47, 0x72, 0x69, 0x64, 0x10, 0x0c, 0x12, 0x09, 0x0a, 0x05, - 0x53, 0x6c, 0x61, 0x63, 0x6b, 0x10, 0x0d, 0x12, 0x0a, 0x0a, 0x06, 0x53, 0x71, 0x75, 0x61, 0x72, - 0x65, 0x10, 0x0e, 0x12, 0x0e, 0x0a, 0x0a, 0x50, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x4b, 0x65, - 0x79, 0x10, 0x0f, 0x12, 0x0a, 0x0a, 0x06, 0x53, 0x74, 0x72, 0x69, 0x70, 0x65, 0x10, 0x10, 0x12, - 0x07, 0x0a, 0x03, 0x55, 0x52, 0x49, 0x10, 0x11, 0x12, 0x0b, 0x0a, 0x07, 0x44, 0x72, 0x6f, 0x70, - 0x62, 0x6f, 0x78, 0x10, 0x12, 0x12, 0x0a, 0x0a, 0x06, 0x48, 0x65, 0x72, 0x6f, 0x6b, 0x75, 0x10, - 0x13, 0x12, 0x0d, 0x0a, 0x09, 0x4d, 0x61, 0x69, 0x6c, 0x63, 0x68, 0x69, 0x6d, 0x70, 0x10, 0x14, - 0x12, 0x08, 0x0a, 0x04, 0x4f, 0x6b, 0x74, 0x61, 0x10, 0x15, 0x12, 0x0c, 0x0a, 0x08, 0x4f, 0x6e, - 0x65, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x10, 0x16, 0x12, 0x12, 0x0a, 0x0e, 0x50, 0x69, 0x76, 0x6f, - 0x74, 0x61, 0x6c, 0x54, 0x72, 0x61, 0x63, 0x6b, 0x65, 0x72, 0x10, 0x17, 0x12, 0x0d, 0x0a, 0x09, - 0x53, 0x71, 0x75, 0x61, 0x72, 0x65, 0x41, 0x70, 0x70, 0x10, 0x19, 0x12, 0x0a, 0x0a, 0x06, 0x54, - 0x77, 0x69, 0x6c, 0x69, 0x6f, 0x10, 0x1a, 0x12, 0x08, 0x0a, 0x04, 0x54, 0x65, 0x73, 0x74, 0x10, - 0x1b, 0x12, 0x0c, 0x0a, 0x08, 0x54, 0x72, 0x61, 0x76, 0x69, 0x73, 0x43, 0x49, 0x10, 0x1d, 0x12, - 0x10, 0x0a, 0x0c, 0x53, 0x6c, 0x61, 0x63, 0x6b, 0x57, 0x65, 0x62, 0x68, 0x6f, 0x6f, 0x6b, 0x10, - 0x1e, 0x12, 0x0f, 0x0a, 0x0b, 0x50, 0x61, 0x79, 0x70, 0x61, 0x6c, 0x4f, 0x61, 0x75, 0x74, 0x68, - 0x10, 0x1f, 0x12, 0x13, 0x0a, 0x0f, 0x50, 0x61, 0x67, 0x65, 0x72, 0x44, 0x75, 0x74, 0x79, 0x41, - 0x70, 0x69, 0x4b, 0x65, 0x79, 0x10, 0x20, 0x12, 0x0c, 0x0a, 0x08, 0x46, 0x69, 0x72, 0x65, 0x62, - 0x61, 0x73, 0x65, 0x10, 0x21, 0x12, 0x0b, 0x0a, 0x07, 0x4d, 0x61, 0x69, 0x6c, 0x67, 0x75, 0x6e, - 0x10, 0x22, 0x12, 0x0b, 0x0a, 0x07, 0x48, 0x75, 0x62, 0x53, 0x70, 0x6f, 0x74, 0x10, 0x23, 0x12, - 0x0d, 0x0a, 0x09, 0x47, 0x69, 0x74, 0x48, 0x75, 0x62, 0x41, 0x70, 0x70, 0x10, 0x24, 0x12, 0x0c, - 0x0a, 0x08, 0x43, 0x69, 0x72, 0x63, 0x6c, 0x65, 0x43, 0x49, 0x10, 0x25, 0x12, 0x0c, 0x0a, 0x08, - 0x57, 0x70, 0x45, 0x6e, 0x67, 0x69, 0x6e, 0x65, 0x10, 0x26, 0x12, 0x10, 0x0a, 0x0c, 0x44, 0x61, - 0x74, 0x61, 0x64, 0x6f, 0x67, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x10, 0x27, 0x12, 0x11, 0x0a, 0x0d, - 0x46, 0x61, 0x63, 0x65, 0x62, 0x6f, 0x6f, 0x6b, 0x4f, 0x41, 0x75, 0x74, 0x68, 0x10, 0x28, 0x12, - 0x1c, 0x0a, 0x18, 0x41, 0x73, 0x61, 0x6e, 0x61, 0x50, 0x65, 0x72, 0x73, 0x6f, 0x6e, 0x61, 0x6c, - 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x10, 0x29, 0x12, 0x13, 0x0a, - 0x0f, 0x41, 0x6d, 0x70, 0x6c, 0x69, 0x74, 0x75, 0x64, 0x65, 0x41, 0x70, 0x69, 0x4b, 0x65, 0x79, - 0x10, 0x2a, 0x12, 0x14, 0x0a, 0x10, 0x42, 0x69, 0x74, 0x4c, 0x79, 0x41, 0x63, 0x63, 0x65, 0x73, - 0x73, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x10, 0x2b, 0x12, 0x12, 0x0a, 0x0e, 0x43, 0x61, 0x6c, 0x65, - 0x6e, 0x64, 0x6c, 0x79, 0x41, 0x70, 0x69, 0x4b, 0x65, 0x79, 0x10, 0x2c, 0x12, 0x11, 0x0a, 0x0d, - 0x5a, 0x61, 0x70, 0x69, 0x65, 0x72, 0x57, 0x65, 0x62, 0x68, 0x6f, 0x6f, 0x6b, 0x10, 0x2d, 0x12, - 0x11, 0x0a, 0x0d, 0x59, 0x6f, 0x75, 0x74, 0x75, 0x62, 0x65, 0x41, 0x70, 0x69, 0x4b, 0x65, 0x79, - 0x10, 0x2e, 0x12, 0x14, 0x0a, 0x10, 0x53, 0x61, 0x6c, 0x65, 0x73, 0x66, 0x6f, 0x72, 0x63, 0x65, - 0x4f, 0x61, 0x75, 0x74, 0x68, 0x32, 0x10, 0x2f, 0x12, 0x14, 0x0a, 0x10, 0x54, 0x77, 0x69, 0x74, - 0x74, 0x65, 0x72, 0x41, 0x70, 0x69, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x10, 0x30, 0x12, 0x0c, - 0x0a, 0x08, 0x4e, 0x70, 0x6d, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x10, 0x31, 0x12, 0x1a, 0x0a, 0x16, - 0x4e, 0x65, 0x77, 0x52, 0x65, 0x6c, 0x69, 0x63, 0x50, 0x65, 0x72, 0x73, 0x6f, 0x6e, 0x61, 0x6c, - 0x41, 0x70, 0x69, 0x4b, 0x65, 0x79, 0x10, 0x32, 0x12, 0x12, 0x0a, 0x0e, 0x41, 0x69, 0x72, 0x74, - 0x61, 0x62, 0x6c, 0x65, 0x41, 0x70, 0x69, 0x4b, 0x65, 0x79, 0x10, 0x33, 0x12, 0x0f, 0x0a, 0x0b, - 0x41, 0x6b, 0x61, 0x6d, 0x61, 0x69, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x10, 0x34, 0x12, 0x0d, 0x0a, - 0x09, 0x41, 0x6d, 0x61, 0x7a, 0x6f, 0x6e, 0x4d, 0x57, 0x53, 0x10, 0x35, 0x12, 0x0e, 0x0a, 0x0a, - 0x4b, 0x75, 0x62, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x10, 0x36, 0x12, 0x0e, 0x0a, 0x0a, - 0x41, 0x75, 0x74, 0x68, 0x30, 0x6f, 0x61, 0x75, 0x74, 0x68, 0x10, 0x37, 0x12, 0x0c, 0x0a, 0x08, - 0x42, 0x69, 0x74, 0x66, 0x69, 0x6e, 0x65, 0x78, 0x10, 0x38, 0x12, 0x0c, 0x0a, 0x08, 0x43, 0x6c, - 0x61, 0x72, 0x69, 0x66, 0x61, 0x69, 0x10, 0x39, 0x12, 0x1a, 0x0a, 0x16, 0x43, 0x6c, 0x6f, 0x75, - 0x64, 0x66, 0x6c, 0x61, 0x72, 0x65, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x41, 0x70, 0x69, 0x4b, - 0x65, 0x79, 0x10, 0x3a, 0x12, 0x13, 0x0a, 0x0f, 0x43, 0x6c, 0x6f, 0x75, 0x64, 0x66, 0x6c, 0x61, - 0x72, 0x65, 0x43, 0x61, 0x4b, 0x65, 0x79, 0x10, 0x3b, 0x12, 0x0d, 0x0a, 0x09, 0x43, 0x6f, 0x6e, - 0x66, 0x6c, 0x75, 0x65, 0x6e, 0x74, 0x10, 0x3c, 0x12, 0x16, 0x0a, 0x12, 0x43, 0x6f, 0x6e, 0x74, - 0x65, 0x6e, 0x74, 0x66, 0x75, 0x6c, 0x44, 0x65, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x79, 0x10, 0x3d, - 0x12, 0x13, 0x0a, 0x0f, 0x44, 0x61, 0x74, 0x61, 0x62, 0x72, 0x69, 0x63, 0x6b, 0x73, 0x54, 0x6f, - 0x6b, 0x65, 0x6e, 0x10, 0x3e, 0x12, 0x16, 0x0a, 0x12, 0x44, 0x69, 0x67, 0x69, 0x74, 0x61, 0x6c, - 0x4f, 0x63, 0x65, 0x61, 0x6e, 0x53, 0x70, 0x61, 0x63, 0x65, 0x73, 0x10, 0x3f, 0x12, 0x15, 0x0a, - 0x11, 0x44, 0x69, 0x67, 0x69, 0x74, 0x61, 0x6c, 0x4f, 0x63, 0x65, 0x61, 0x6e, 0x54, 0x6f, 0x6b, - 0x65, 0x6e, 0x10, 0x40, 0x12, 0x13, 0x0a, 0x0f, 0x44, 0x69, 0x73, 0x63, 0x6f, 0x72, 0x64, 0x42, - 0x6f, 0x74, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x10, 0x41, 0x12, 0x12, 0x0a, 0x0e, 0x44, 0x69, 0x73, - 0x63, 0x6f, 0x72, 0x64, 0x57, 0x65, 0x62, 0x68, 0x6f, 0x6f, 0x6b, 0x10, 0x42, 0x12, 0x12, 0x0a, - 0x0a, 0x45, 0x74, 0x73, 0x79, 0x41, 0x70, 0x69, 0x4b, 0x65, 0x79, 0x10, 0x43, 0x1a, 0x02, 0x08, - 0x01, 0x12, 0x17, 0x0a, 0x13, 0x46, 0x61, 0x73, 0x74, 0x6c, 0x79, 0x50, 0x65, 0x72, 0x73, 0x6f, - 0x6e, 0x61, 0x6c, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x10, 0x44, 0x12, 0x10, 0x0a, 0x0c, 0x47, 0x6f, - 0x6f, 0x67, 0x6c, 0x65, 0x4f, 0x61, 0x75, 0x74, 0x68, 0x32, 0x10, 0x45, 0x12, 0x0d, 0x0a, 0x09, - 0x52, 0x65, 0x43, 0x41, 0x50, 0x54, 0x43, 0x48, 0x41, 0x10, 0x46, 0x12, 0x10, 0x0a, 0x0c, 0x47, - 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x41, 0x70, 0x69, 0x4b, 0x65, 0x79, 0x10, 0x47, 0x12, 0x0a, 0x0a, - 0x06, 0x48, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x10, 0x48, 0x12, 0x13, 0x0a, 0x0f, 0x49, 0x62, 0x6d, - 0x43, 0x6c, 0x6f, 0x75, 0x64, 0x55, 0x73, 0x65, 0x72, 0x4b, 0x65, 0x79, 0x10, 0x49, 0x12, 0x0b, - 0x0a, 0x07, 0x4e, 0x65, 0x74, 0x6c, 0x69, 0x66, 0x79, 0x10, 0x4a, 0x12, 0x0a, 0x0a, 0x06, 0x56, - 0x6f, 0x6e, 0x61, 0x67, 0x65, 0x10, 0x4b, 0x12, 0x10, 0x0a, 0x0c, 0x45, 0x71, 0x75, 0x69, 0x6e, - 0x69, 0x78, 0x4f, 0x61, 0x75, 0x74, 0x68, 0x10, 0x4c, 0x12, 0x0c, 0x0a, 0x08, 0x50, 0x61, 0x79, - 0x73, 0x74, 0x61, 0x63, 0x6b, 0x10, 0x4d, 0x12, 0x0e, 0x0a, 0x0a, 0x50, 0x6c, 0x61, 0x69, 0x64, - 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x10, 0x4e, 0x12, 0x0c, 0x0a, 0x08, 0x50, 0x6c, 0x61, 0x69, 0x64, - 0x4b, 0x65, 0x79, 0x10, 0x4f, 0x12, 0x09, 0x0a, 0x05, 0x50, 0x6c, 0x69, 0x76, 0x6f, 0x10, 0x50, - 0x12, 0x0c, 0x0a, 0x08, 0x50, 0x6f, 0x73, 0x74, 0x6d, 0x61, 0x72, 0x6b, 0x10, 0x51, 0x12, 0x14, - 0x0a, 0x10, 0x50, 0x75, 0x62, 0x4e, 0x75, 0x62, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x4b, - 0x65, 0x79, 0x10, 0x52, 0x12, 0x19, 0x0a, 0x15, 0x50, 0x75, 0x62, 0x4e, 0x75, 0x62, 0x53, 0x75, - 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x4b, 0x65, 0x79, 0x10, 0x53, 0x12, - 0x14, 0x0a, 0x10, 0x50, 0x75, 0x73, 0x68, 0x65, 0x72, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, - 0x4b, 0x65, 0x79, 0x10, 0x54, 0x12, 0x0f, 0x0a, 0x0b, 0x53, 0x63, 0x61, 0x6c, 0x65, 0x77, 0x61, - 0x79, 0x4b, 0x65, 0x79, 0x10, 0x55, 0x12, 0x10, 0x0a, 0x0c, 0x53, 0x65, 0x6e, 0x64, 0x69, 0x6e, - 0x42, 0x6c, 0x75, 0x65, 0x56, 0x32, 0x10, 0x56, 0x12, 0x0f, 0x0a, 0x0b, 0x53, 0x65, 0x6e, 0x74, - 0x72, 0x79, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x10, 0x57, 0x12, 0x0d, 0x0a, 0x09, 0x53, 0x68, 0x6f, - 0x64, 0x61, 0x6e, 0x4b, 0x65, 0x79, 0x10, 0x58, 0x12, 0x0b, 0x0a, 0x07, 0x53, 0x6e, 0x79, 0x6b, - 0x4b, 0x65, 0x79, 0x10, 0x59, 0x12, 0x0e, 0x0a, 0x0a, 0x53, 0x70, 0x6f, 0x74, 0x69, 0x66, 0x79, - 0x4b, 0x65, 0x79, 0x10, 0x5a, 0x12, 0x14, 0x0a, 0x10, 0x54, 0x65, 0x6c, 0x65, 0x67, 0x72, 0x61, - 0x6d, 0x42, 0x6f, 0x74, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x10, 0x5b, 0x12, 0x13, 0x0a, 0x0f, 0x54, - 0x65, 0x6e, 0x63, 0x65, 0x6e, 0x74, 0x43, 0x6c, 0x6f, 0x75, 0x64, 0x4b, 0x65, 0x79, 0x10, 0x5c, - 0x12, 0x1f, 0x0a, 0x1b, 0x54, 0x65, 0x72, 0x72, 0x61, 0x66, 0x6f, 0x72, 0x6d, 0x43, 0x6c, 0x6f, - 0x75, 0x64, 0x50, 0x65, 0x72, 0x73, 0x6f, 0x6e, 0x61, 0x6c, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x10, - 0x5d, 0x12, 0x10, 0x0a, 0x0c, 0x54, 0x72, 0x65, 0x6c, 0x6c, 0x6f, 0x41, 0x70, 0x69, 0x4b, 0x65, - 0x79, 0x10, 0x5e, 0x12, 0x0e, 0x0a, 0x0a, 0x5a, 0x65, 0x6e, 0x64, 0x65, 0x73, 0x6b, 0x41, 0x70, - 0x69, 0x10, 0x5f, 0x12, 0x12, 0x0a, 0x0e, 0x4d, 0x61, 0x78, 0x4d, 0x69, 0x6e, 0x64, 0x4c, 0x69, - 0x63, 0x65, 0x6e, 0x73, 0x65, 0x10, 0x60, 0x12, 0x1a, 0x0a, 0x16, 0x41, 0x69, 0x72, 0x74, 0x61, - 0x62, 0x6c, 0x65, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x41, 0x70, 0x69, 0x4b, 0x65, - 0x79, 0x10, 0x61, 0x12, 0x0e, 0x0a, 0x0a, 0x41, 0x73, 0x61, 0x6e, 0x61, 0x4f, 0x61, 0x75, 0x74, - 0x68, 0x10, 0x62, 0x12, 0x0c, 0x0a, 0x08, 0x52, 0x61, 0x70, 0x69, 0x64, 0x41, 0x70, 0x69, 0x10, - 0x63, 0x12, 0x16, 0x0a, 0x12, 0x43, 0x6c, 0x6f, 0x75, 0x64, 0x66, 0x6c, 0x61, 0x72, 0x65, 0x41, - 0x70, 0x69, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x10, 0x64, 0x12, 0x09, 0x0a, 0x05, 0x57, 0x65, 0x62, - 0x65, 0x78, 0x10, 0x65, 0x12, 0x1a, 0x0a, 0x16, 0x46, 0x69, 0x72, 0x65, 0x62, 0x61, 0x73, 0x65, - 0x43, 0x6c, 0x6f, 0x75, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x69, 0x6e, 0x67, 0x10, 0x66, - 0x12, 0x21, 0x0a, 0x1d, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x66, 0x75, 0x6c, 0x50, 0x65, - 0x72, 0x73, 0x6f, 0x6e, 0x61, 0x6c, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x54, 0x6f, 0x6b, 0x65, - 0x6e, 0x10, 0x67, 0x12, 0x0a, 0x0a, 0x06, 0x4d, 0x61, 0x70, 0x42, 0x6f, 0x78, 0x10, 0x68, 0x12, - 0x14, 0x0a, 0x10, 0x4d, 0x61, 0x69, 0x6c, 0x4a, 0x65, 0x74, 0x42, 0x61, 0x73, 0x69, 0x63, 0x41, - 0x75, 0x74, 0x68, 0x10, 0x69, 0x12, 0x0e, 0x0a, 0x0a, 0x4d, 0x61, 0x69, 0x6c, 0x4a, 0x65, 0x74, - 0x53, 0x4d, 0x53, 0x10, 0x6a, 0x12, 0x11, 0x0a, 0x0d, 0x48, 0x75, 0x62, 0x53, 0x70, 0x6f, 0x74, - 0x41, 0x70, 0x69, 0x4b, 0x65, 0x79, 0x10, 0x6b, 0x12, 0x10, 0x0a, 0x0c, 0x48, 0x75, 0x62, 0x53, - 0x70, 0x6f, 0x74, 0x4f, 0x61, 0x75, 0x74, 0x68, 0x10, 0x6c, 0x12, 0x0b, 0x0a, 0x07, 0x53, 0x73, - 0x6c, 0x4d, 0x61, 0x74, 0x65, 0x10, 0x6d, 0x12, 0x1b, 0x0a, 0x17, 0x41, 0x75, 0x74, 0x68, 0x30, - 0x4d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x41, 0x70, 0x69, 0x54, 0x6f, 0x6b, - 0x65, 0x6e, 0x10, 0x6e, 0x12, 0x0f, 0x0a, 0x0b, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x42, - 0x69, 0x72, 0x64, 0x10, 0x6f, 0x12, 0x10, 0x0a, 0x0c, 0x45, 0x6c, 0x61, 0x73, 0x74, 0x69, 0x63, - 0x45, 0x6d, 0x61, 0x69, 0x6c, 0x10, 0x70, 0x12, 0x1c, 0x0a, 0x18, 0x46, 0x69, 0x67, 0x6d, 0x61, - 0x50, 0x65, 0x72, 0x73, 0x6f, 0x6e, 0x61, 0x6c, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x54, 0x6f, - 0x6b, 0x65, 0x6e, 0x10, 0x71, 0x12, 0x19, 0x0a, 0x15, 0x4d, 0x69, 0x63, 0x72, 0x6f, 0x73, 0x6f, - 0x66, 0x74, 0x54, 0x65, 0x61, 0x6d, 0x73, 0x57, 0x65, 0x62, 0x68, 0x6f, 0x6f, 0x6b, 0x10, 0x72, - 0x12, 0x0d, 0x0a, 0x09, 0x47, 0x69, 0x74, 0x48, 0x75, 0x62, 0x4f, 0x6c, 0x64, 0x10, 0x73, 0x12, - 0x0f, 0x0a, 0x0b, 0x56, 0x75, 0x6c, 0x74, 0x72, 0x41, 0x70, 0x69, 0x4b, 0x65, 0x79, 0x10, 0x74, - 0x12, 0x0c, 0x0a, 0x08, 0x50, 0x65, 0x70, 0x69, 0x70, 0x6f, 0x73, 0x74, 0x10, 0x75, 0x12, 0x0b, - 0x0a, 0x07, 0x50, 0x6f, 0x73, 0x74, 0x6d, 0x61, 0x6e, 0x10, 0x76, 0x12, 0x11, 0x0a, 0x0d, 0x43, - 0x6c, 0x6f, 0x75, 0x64, 0x73, 0x69, 0x67, 0x68, 0x74, 0x4b, 0x65, 0x79, 0x10, 0x77, 0x12, 0x0d, - 0x0a, 0x09, 0x4a, 0x69, 0x72, 0x61, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x10, 0x78, 0x12, 0x0f, 0x0a, - 0x0b, 0x4e, 0x65, 0x78, 0x6d, 0x6f, 0x41, 0x70, 0x69, 0x4b, 0x65, 0x79, 0x10, 0x79, 0x12, 0x11, - 0x0a, 0x0d, 0x53, 0x65, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x41, 0x70, 0x69, 0x4b, 0x65, 0x79, 0x10, - 0x7a, 0x12, 0x10, 0x0a, 0x0c, 0x53, 0x75, 0x6d, 0x6f, 0x4c, 0x6f, 0x67, 0x69, 0x63, 0x4b, 0x65, - 0x79, 0x10, 0x7b, 0x12, 0x14, 0x0a, 0x10, 0x50, 0x75, 0x73, 0x68, 0x42, 0x75, 0x6c, 0x6c, 0x65, - 0x74, 0x41, 0x70, 0x69, 0x4b, 0x65, 0x79, 0x10, 0x7c, 0x12, 0x16, 0x0a, 0x12, 0x41, 0x69, 0x72, - 0x62, 0x72, 0x61, 0x6b, 0x65, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x4b, 0x65, 0x79, 0x10, - 0x7d, 0x12, 0x13, 0x0a, 0x0f, 0x41, 0x69, 0x72, 0x62, 0x72, 0x61, 0x6b, 0x65, 0x55, 0x73, 0x65, - 0x72, 0x4b, 0x65, 0x79, 0x10, 0x7e, 0x12, 0x17, 0x0a, 0x13, 0x50, 0x65, 0x6e, 0x64, 0x6f, 0x49, - 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4b, 0x65, 0x79, 0x10, 0x7f, 0x12, - 0x1f, 0x0a, 0x1a, 0x53, 0x70, 0x6c, 0x75, 0x6e, 0x6b, 0x4f, 0x62, 0x65, 0x72, 0x73, 0x65, 0x72, - 0x76, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x10, 0x80, 0x01, - 0x12, 0x12, 0x0a, 0x0d, 0x4c, 0x6f, 0x6b, 0x61, 0x6c, 0x69, 0x73, 0x65, 0x54, 0x6f, 0x6b, 0x65, - 0x6e, 0x10, 0x81, 0x01, 0x12, 0x11, 0x0a, 0x0c, 0x43, 0x61, 0x6c, 0x65, 0x6e, 0x64, 0x61, 0x72, - 0x69, 0x66, 0x69, 0x63, 0x10, 0x82, 0x01, 0x12, 0x0e, 0x0a, 0x09, 0x4a, 0x75, 0x6d, 0x70, 0x63, - 0x6c, 0x6f, 0x75, 0x64, 0x10, 0x83, 0x01, 0x12, 0x0c, 0x0a, 0x07, 0x49, 0x70, 0x53, 0x74, 0x61, - 0x63, 0x6b, 0x10, 0x85, 0x01, 0x12, 0x0b, 0x0a, 0x06, 0x4e, 0x6f, 0x74, 0x69, 0x6f, 0x6e, 0x10, - 0x86, 0x01, 0x12, 0x0c, 0x0a, 0x07, 0x44, 0x72, 0x6f, 0x6e, 0x65, 0x43, 0x49, 0x10, 0x87, 0x01, - 0x12, 0x0c, 0x0a, 0x07, 0x41, 0x64, 0x6f, 0x62, 0x65, 0x49, 0x4f, 0x10, 0x88, 0x01, 0x12, 0x0f, - 0x0a, 0x0a, 0x54, 0x77, 0x65, 0x6c, 0x76, 0x65, 0x44, 0x61, 0x74, 0x61, 0x10, 0x89, 0x01, 0x12, - 0x0e, 0x0a, 0x09, 0x44, 0x37, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x10, 0x8a, 0x01, 0x12, - 0x10, 0x0a, 0x0b, 0x53, 0x63, 0x72, 0x61, 0x70, 0x69, 0x6e, 0x67, 0x42, 0x65, 0x65, 0x10, 0x8b, - 0x01, 0x12, 0x0b, 0x0a, 0x06, 0x4b, 0x65, 0x65, 0x6e, 0x49, 0x4f, 0x10, 0x8c, 0x01, 0x12, 0x0d, - 0x0a, 0x08, 0x57, 0x61, 0x6b, 0x61, 0x74, 0x69, 0x6d, 0x65, 0x10, 0x8d, 0x01, 0x12, 0x0e, 0x0a, - 0x09, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x6b, 0x69, 0x74, 0x65, 0x10, 0x8e, 0x01, 0x12, 0x0d, 0x0a, - 0x08, 0x56, 0x65, 0x72, 0x69, 0x6d, 0x61, 0x69, 0x6c, 0x10, 0x8f, 0x01, 0x12, 0x0f, 0x0a, 0x0a, - 0x5a, 0x65, 0x72, 0x6f, 0x62, 0x6f, 0x75, 0x6e, 0x63, 0x65, 0x10, 0x90, 0x01, 0x12, 0x11, 0x0a, - 0x0c, 0x4d, 0x61, 0x69, 0x6c, 0x62, 0x6f, 0x78, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x10, 0x91, 0x01, - 0x12, 0x0f, 0x0a, 0x0a, 0x46, 0x61, 0x73, 0x74, 0x73, 0x70, 0x72, 0x69, 0x6e, 0x67, 0x10, 0x92, - 0x01, 0x12, 0x0b, 0x0a, 0x06, 0x50, 0x61, 0x64, 0x64, 0x6c, 0x65, 0x10, 0x93, 0x01, 0x12, 0x0b, - 0x0a, 0x06, 0x53, 0x65, 0x6c, 0x6c, 0x66, 0x79, 0x10, 0x94, 0x01, 0x12, 0x0c, 0x0a, 0x07, 0x46, - 0x69, 0x78, 0x65, 0x72, 0x49, 0x4f, 0x10, 0x95, 0x01, 0x12, 0x0e, 0x0a, 0x09, 0x42, 0x75, 0x74, - 0x74, 0x65, 0x72, 0x43, 0x4d, 0x53, 0x10, 0x96, 0x01, 0x12, 0x0b, 0x0a, 0x06, 0x54, 0x61, 0x78, - 0x6a, 0x61, 0x72, 0x10, 0x97, 0x01, 0x12, 0x0c, 0x0a, 0x07, 0x41, 0x76, 0x61, 0x6c, 0x61, 0x72, - 0x61, 0x10, 0x98, 0x01, 0x12, 0x0e, 0x0a, 0x09, 0x48, 0x65, 0x6c, 0x70, 0x73, 0x63, 0x6f, 0x75, - 0x74, 0x10, 0x99, 0x01, 0x12, 0x10, 0x0a, 0x0b, 0x45, 0x6c, 0x61, 0x73, 0x74, 0x69, 0x63, 0x50, - 0x61, 0x74, 0x68, 0x10, 0x9a, 0x01, 0x12, 0x0b, 0x0a, 0x06, 0x5a, 0x65, 0x70, 0x6c, 0x69, 0x6e, - 0x10, 0x9b, 0x01, 0x12, 0x0d, 0x0a, 0x08, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x63, 0x6f, 0x6d, 0x10, - 0x9c, 0x01, 0x12, 0x0d, 0x0a, 0x08, 0x4d, 0x61, 0x69, 0x6c, 0x6d, 0x6f, 0x64, 0x6f, 0x10, 0x9d, - 0x01, 0x12, 0x0c, 0x0a, 0x07, 0x43, 0x61, 0x6e, 0x6e, 0x79, 0x49, 0x6f, 0x10, 0x9e, 0x01, 0x12, - 0x0e, 0x0a, 0x09, 0x50, 0x69, 0x70, 0x65, 0x64, 0x72, 0x69, 0x76, 0x65, 0x10, 0x9f, 0x01, 0x12, - 0x0b, 0x0a, 0x06, 0x56, 0x65, 0x72, 0x63, 0x65, 0x6c, 0x10, 0xa0, 0x01, 0x12, 0x0f, 0x0a, 0x0a, - 0x50, 0x6f, 0x73, 0x74, 0x68, 0x6f, 0x67, 0x41, 0x70, 0x70, 0x10, 0xa1, 0x01, 0x12, 0x11, 0x0a, - 0x0c, 0x53, 0x69, 0x6e, 0x63, 0x68, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x10, 0xa2, 0x01, - 0x12, 0x0d, 0x0a, 0x08, 0x41, 0x79, 0x72, 0x73, 0x68, 0x61, 0x72, 0x65, 0x10, 0xa3, 0x01, 0x12, - 0x0f, 0x0a, 0x0a, 0x48, 0x65, 0x6c, 0x70, 0x43, 0x72, 0x75, 0x6e, 0x63, 0x68, 0x10, 0xa4, 0x01, - 0x12, 0x0e, 0x0a, 0x09, 0x4c, 0x69, 0x76, 0x65, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x10, 0xa5, 0x01, - 0x12, 0x0b, 0x0a, 0x06, 0x42, 0x65, 0x61, 0x6d, 0x65, 0x72, 0x10, 0xa6, 0x01, 0x12, 0x11, 0x0a, - 0x0c, 0x57, 0x65, 0x43, 0x68, 0x61, 0x74, 0x41, 0x70, 0x70, 0x4b, 0x65, 0x79, 0x10, 0xa7, 0x01, - 0x12, 0x12, 0x0a, 0x0d, 0x4c, 0x69, 0x6e, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x69, 0x6e, - 0x67, 0x10, 0xa8, 0x01, 0x12, 0x14, 0x0a, 0x0f, 0x55, 0x62, 0x65, 0x72, 0x53, 0x65, 0x72, 0x76, - 0x65, 0x72, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x10, 0xa9, 0x01, 0x12, 0x14, 0x0a, 0x0f, 0x41, 0x6c, - 0x67, 0x6f, 0x6c, 0x69, 0x61, 0x41, 0x64, 0x6d, 0x69, 0x6e, 0x4b, 0x65, 0x79, 0x10, 0xaa, 0x01, - 0x12, 0x10, 0x0a, 0x0b, 0x46, 0x75, 0x6c, 0x6c, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x10, - 0xab, 0x01, 0x12, 0x0d, 0x0a, 0x08, 0x4d, 0x61, 0x6e, 0x64, 0x72, 0x69, 0x6c, 0x6c, 0x10, 0xac, - 0x01, 0x12, 0x10, 0x0a, 0x0b, 0x46, 0x6c, 0x75, 0x74, 0x74, 0x65, 0x72, 0x77, 0x61, 0x76, 0x65, - 0x10, 0xad, 0x01, 0x12, 0x1c, 0x0a, 0x17, 0x4d, 0x61, 0x74, 0x74, 0x65, 0x72, 0x6d, 0x6f, 0x73, - 0x74, 0x50, 0x65, 0x72, 0x73, 0x6f, 0x6e, 0x61, 0x6c, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x10, 0xae, - 0x01, 0x12, 0x0d, 0x0a, 0x08, 0x43, 0x6c, 0x6f, 0x75, 0x64, 0x61, 0x6e, 0x74, 0x10, 0xaf, 0x01, - 0x12, 0x0f, 0x0a, 0x0a, 0x4c, 0x69, 0x6e, 0x65, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x10, 0xb0, - 0x01, 0x12, 0x0e, 0x0a, 0x09, 0x4c, 0x69, 0x6e, 0x65, 0x61, 0x72, 0x41, 0x50, 0x49, 0x10, 0xb1, - 0x01, 0x12, 0x0c, 0x0a, 0x07, 0x55, 0x62, 0x69, 0x64, 0x6f, 0x74, 0x73, 0x10, 0xb2, 0x01, 0x12, - 0x0d, 0x0a, 0x08, 0x41, 0x6e, 0x79, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x10, 0xb3, 0x01, 0x12, 0x0b, - 0x0a, 0x06, 0x44, 0x77, 0x6f, 0x6c, 0x6c, 0x61, 0x10, 0xb4, 0x01, 0x12, 0x1b, 0x0a, 0x16, 0x41, - 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x6f, 0x72, 0x79, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, - 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x10, 0xb5, 0x01, 0x12, 0x0a, 0x0a, 0x05, 0x53, 0x75, 0x72, 0x67, - 0x65, 0x10, 0xb6, 0x01, 0x12, 0x0e, 0x0a, 0x09, 0x53, 0x70, 0x61, 0x72, 0x6b, 0x70, 0x6f, 0x73, - 0x74, 0x10, 0xb7, 0x01, 0x12, 0x0f, 0x0a, 0x0a, 0x47, 0x6f, 0x43, 0x61, 0x72, 0x64, 0x6c, 0x65, - 0x73, 0x73, 0x10, 0xb8, 0x01, 0x12, 0x0b, 0x0a, 0x06, 0x43, 0x6f, 0x64, 0x61, 0x63, 0x79, 0x10, - 0xb9, 0x01, 0x12, 0x0b, 0x0a, 0x06, 0x4b, 0x72, 0x61, 0x6b, 0x65, 0x6e, 0x10, 0xba, 0x01, 0x12, - 0x0d, 0x0a, 0x08, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x6f, 0x75, 0x74, 0x10, 0xbb, 0x01, 0x12, 0x0b, - 0x0a, 0x06, 0x4b, 0x61, 0x69, 0x72, 0x6f, 0x73, 0x10, 0xbc, 0x01, 0x12, 0x11, 0x0a, 0x0c, 0x43, - 0x6c, 0x6f, 0x63, 0x6b, 0x77, 0x6f, 0x72, 0x6b, 0x53, 0x4d, 0x53, 0x10, 0xbd, 0x01, 0x12, 0x0e, - 0x0a, 0x09, 0x41, 0x74, 0x6c, 0x61, 0x73, 0x73, 0x69, 0x61, 0x6e, 0x10, 0xbe, 0x01, 0x12, 0x11, - 0x0a, 0x0c, 0x4c, 0x61, 0x75, 0x6e, 0x63, 0x68, 0x44, 0x61, 0x72, 0x6b, 0x6c, 0x79, 0x10, 0xbf, - 0x01, 0x12, 0x0e, 0x0a, 0x09, 0x43, 0x6f, 0x76, 0x65, 0x72, 0x61, 0x6c, 0x6c, 0x73, 0x10, 0xc0, - 0x01, 0x12, 0x0b, 0x0a, 0x06, 0x4c, 0x69, 0x6e, 0x6f, 0x64, 0x65, 0x10, 0xc1, 0x01, 0x12, 0x0a, - 0x0a, 0x05, 0x57, 0x65, 0x50, 0x61, 0x79, 0x10, 0xc2, 0x01, 0x12, 0x10, 0x0a, 0x0b, 0x50, 0x6c, - 0x61, 0x6e, 0x65, 0x74, 0x53, 0x63, 0x61, 0x6c, 0x65, 0x10, 0xc3, 0x01, 0x12, 0x0c, 0x0a, 0x07, - 0x44, 0x6f, 0x70, 0x70, 0x6c, 0x65, 0x72, 0x10, 0xc4, 0x01, 0x12, 0x0a, 0x0a, 0x05, 0x41, 0x67, - 0x6f, 0x72, 0x61, 0x10, 0xc5, 0x01, 0x12, 0x0c, 0x0a, 0x07, 0x53, 0x61, 0x6d, 0x73, 0x61, 0x72, - 0x61, 0x10, 0xc6, 0x01, 0x12, 0x0c, 0x0a, 0x07, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x49, 0x4f, 0x10, - 0xc7, 0x01, 0x12, 0x0d, 0x0a, 0x08, 0x52, 0x75, 0x62, 0x79, 0x47, 0x65, 0x6d, 0x73, 0x10, 0xc8, - 0x01, 0x12, 0x0b, 0x0a, 0x06, 0x4f, 0x70, 0x65, 0x6e, 0x41, 0x49, 0x10, 0xc9, 0x01, 0x12, 0x12, - 0x0a, 0x0d, 0x53, 0x75, 0x72, 0x76, 0x65, 0x79, 0x53, 0x70, 0x61, 0x72, 0x72, 0x6f, 0x77, 0x10, - 0xca, 0x01, 0x12, 0x0c, 0x0a, 0x07, 0x53, 0x69, 0x6d, 0x76, 0x6f, 0x6c, 0x79, 0x10, 0xcb, 0x01, - 0x12, 0x0e, 0x0a, 0x09, 0x53, 0x75, 0x72, 0x76, 0x69, 0x63, 0x61, 0x74, 0x65, 0x10, 0xcc, 0x01, - 0x12, 0x0d, 0x0a, 0x08, 0x4f, 0x6d, 0x6e, 0x69, 0x73, 0x65, 0x6e, 0x64, 0x10, 0xcd, 0x01, 0x12, - 0x0d, 0x0a, 0x08, 0x47, 0x72, 0x6f, 0x6f, 0x76, 0x65, 0x68, 0x71, 0x10, 0xce, 0x01, 0x12, 0x0c, - 0x0a, 0x07, 0x4e, 0x65, 0x77, 0x73, 0x61, 0x70, 0x69, 0x10, 0xcf, 0x01, 0x12, 0x0c, 0x0a, 0x07, - 0x43, 0x68, 0x61, 0x74, 0x62, 0x6f, 0x74, 0x10, 0xd0, 0x01, 0x12, 0x11, 0x0a, 0x0c, 0x43, 0x6c, - 0x69, 0x63, 0x6b, 0x53, 0x65, 0x6e, 0x64, 0x73, 0x6d, 0x73, 0x10, 0xd1, 0x01, 0x12, 0x0c, 0x0a, - 0x07, 0x47, 0x65, 0x74, 0x67, 0x69, 0x73, 0x74, 0x10, 0xd2, 0x01, 0x12, 0x0f, 0x0a, 0x0a, 0x43, - 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x65, 0x72, 0x49, 0x4f, 0x10, 0xd3, 0x01, 0x12, 0x0c, 0x0a, 0x07, - 0x41, 0x70, 0x69, 0x44, 0x65, 0x63, 0x6b, 0x10, 0xd4, 0x01, 0x12, 0x0c, 0x0a, 0x07, 0x4e, 0x66, - 0x74, 0x70, 0x6f, 0x72, 0x74, 0x10, 0xd5, 0x01, 0x12, 0x0b, 0x0a, 0x06, 0x43, 0x6f, 0x70, 0x70, - 0x65, 0x72, 0x10, 0xd6, 0x01, 0x12, 0x0a, 0x0a, 0x05, 0x43, 0x6c, 0x6f, 0x73, 0x65, 0x10, 0xd7, - 0x01, 0x12, 0x11, 0x0a, 0x0c, 0x4d, 0x79, 0x66, 0x72, 0x65, 0x73, 0x68, 0x77, 0x6f, 0x72, 0x6b, - 0x73, 0x10, 0xd8, 0x01, 0x12, 0x0f, 0x0a, 0x0a, 0x53, 0x61, 0x6c, 0x65, 0x73, 0x66, 0x6c, 0x61, - 0x72, 0x65, 0x10, 0xd9, 0x01, 0x12, 0x0c, 0x0a, 0x07, 0x57, 0x65, 0x62, 0x66, 0x6c, 0x6f, 0x77, - 0x10, 0xda, 0x01, 0x12, 0x09, 0x0a, 0x04, 0x44, 0x75, 0x64, 0x61, 0x10, 0xdb, 0x01, 0x12, 0x09, - 0x0a, 0x04, 0x59, 0x65, 0x78, 0x74, 0x10, 0xdc, 0x01, 0x12, 0x11, 0x0a, 0x0c, 0x43, 0x6f, 0x6e, - 0x74, 0x65, 0x6e, 0x74, 0x53, 0x74, 0x61, 0x63, 0x6b, 0x10, 0xdd, 0x01, 0x12, 0x0e, 0x0a, 0x09, - 0x53, 0x74, 0x6f, 0x72, 0x79, 0x62, 0x6c, 0x6f, 0x6b, 0x10, 0xde, 0x01, 0x12, 0x0d, 0x0a, 0x08, - 0x47, 0x72, 0x61, 0x70, 0x68, 0x43, 0x4d, 0x53, 0x10, 0xdf, 0x01, 0x12, 0x10, 0x0a, 0x0b, 0x43, - 0x68, 0x65, 0x63, 0x6b, 0x6d, 0x61, 0x72, 0x6b, 0x65, 0x74, 0x10, 0xe0, 0x01, 0x12, 0x0f, 0x0a, - 0x0a, 0x43, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x74, 0x6b, 0x69, 0x74, 0x10, 0xe1, 0x01, 0x12, 0x11, - 0x0a, 0x0c, 0x43, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x65, 0x72, 0x47, 0x75, 0x72, 0x75, 0x10, 0xe2, - 0x01, 0x12, 0x0c, 0x0a, 0x07, 0x4b, 0x61, 0x6c, 0x65, 0x79, 0x72, 0x61, 0x10, 0xe3, 0x01, 0x12, - 0x0f, 0x0a, 0x0a, 0x4d, 0x61, 0x69, 0x6c, 0x65, 0x72, 0x6c, 0x69, 0x74, 0x65, 0x10, 0xe4, 0x01, - 0x12, 0x0d, 0x0a, 0x08, 0x51, 0x75, 0x61, 0x6c, 0x61, 0x72, 0x6f, 0x6f, 0x10, 0xe5, 0x01, 0x12, - 0x19, 0x0a, 0x14, 0x53, 0x61, 0x74, 0x69, 0x73, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x50, 0x72, 0x6f, - 0x6a, 0x65, 0x63, 0x74, 0x6b, 0x65, 0x79, 0x10, 0xe6, 0x01, 0x12, 0x17, 0x0a, 0x12, 0x53, 0x61, - 0x74, 0x69, 0x73, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x57, 0x72, 0x69, 0x74, 0x65, 0x6b, 0x65, 0x79, - 0x10, 0xe7, 0x01, 0x12, 0x0e, 0x0a, 0x09, 0x53, 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x61, 0x74, - 0x10, 0xe8, 0x01, 0x12, 0x13, 0x0a, 0x0e, 0x53, 0x75, 0x72, 0x76, 0x65, 0x79, 0x41, 0x6e, 0x79, - 0x70, 0x6c, 0x61, 0x63, 0x65, 0x10, 0xe9, 0x01, 0x12, 0x0e, 0x0a, 0x09, 0x53, 0x75, 0x72, 0x76, - 0x65, 0x79, 0x42, 0x6f, 0x74, 0x10, 0xea, 0x01, 0x12, 0x0e, 0x0a, 0x09, 0x57, 0x65, 0x62, 0x65, - 0x6e, 0x67, 0x61, 0x67, 0x65, 0x10, 0xeb, 0x01, 0x12, 0x12, 0x0a, 0x0d, 0x5a, 0x6f, 0x6e, 0x6b, - 0x61, 0x46, 0x65, 0x65, 0x64, 0x62, 0x61, 0x63, 0x6b, 0x10, 0xec, 0x01, 0x12, 0x0e, 0x0a, 0x09, - 0x44, 0x65, 0x6c, 0x69, 0x67, 0x68, 0x74, 0x65, 0x64, 0x10, 0xed, 0x01, 0x12, 0x0c, 0x0a, 0x07, - 0x46, 0x65, 0x65, 0x64, 0x69, 0x65, 0x72, 0x10, 0xee, 0x01, 0x12, 0x0d, 0x0a, 0x08, 0x41, 0x62, - 0x62, 0x79, 0x73, 0x61, 0x6c, 0x65, 0x10, 0xef, 0x01, 0x12, 0x0d, 0x0a, 0x08, 0x4d, 0x61, 0x67, - 0x6e, 0x65, 0x74, 0x69, 0x63, 0x10, 0xf0, 0x01, 0x12, 0x10, 0x0a, 0x07, 0x4e, 0x79, 0x74, 0x69, - 0x6d, 0x65, 0x73, 0x10, 0xf1, 0x01, 0x1a, 0x02, 0x08, 0x01, 0x12, 0x0c, 0x0a, 0x07, 0x50, 0x6f, - 0x6c, 0x79, 0x67, 0x6f, 0x6e, 0x10, 0xf2, 0x01, 0x12, 0x0c, 0x0a, 0x07, 0x50, 0x6f, 0x77, 0x72, - 0x62, 0x6f, 0x74, 0x10, 0xf3, 0x01, 0x12, 0x13, 0x0a, 0x0a, 0x50, 0x72, 0x6f, 0x73, 0x70, 0x65, - 0x63, 0x74, 0x49, 0x4f, 0x10, 0xf4, 0x01, 0x1a, 0x02, 0x08, 0x01, 0x12, 0x0d, 0x0a, 0x08, 0x53, - 0x6b, 0x72, 0x61, 0x70, 0x70, 0x69, 0x6f, 0x10, 0xf5, 0x01, 0x12, 0x0b, 0x0a, 0x06, 0x4d, 0x6f, - 0x6e, 0x64, 0x61, 0x79, 0x10, 0xf6, 0x01, 0x12, 0x10, 0x0a, 0x0b, 0x53, 0x6d, 0x61, 0x72, 0x74, - 0x73, 0x68, 0x65, 0x65, 0x74, 0x73, 0x10, 0xf7, 0x01, 0x12, 0x0a, 0x0a, 0x05, 0x57, 0x72, 0x69, - 0x6b, 0x65, 0x10, 0xf8, 0x01, 0x12, 0x0a, 0x0a, 0x05, 0x46, 0x6c, 0x6f, 0x61, 0x74, 0x10, 0xf9, - 0x01, 0x12, 0x0d, 0x0a, 0x08, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x6b, 0x69, 0x74, 0x10, 0xfa, 0x01, - 0x12, 0x13, 0x0a, 0x0a, 0x49, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x6f, 0x6d, 0x61, 0x74, 0x10, 0xfb, - 0x01, 0x1a, 0x02, 0x08, 0x01, 0x12, 0x0f, 0x0a, 0x0a, 0x53, 0x61, 0x6c, 0x65, 0x73, 0x62, 0x6c, - 0x69, 0x6e, 0x6b, 0x10, 0xfc, 0x01, 0x12, 0x0a, 0x0a, 0x05, 0x42, 0x6f, 0x72, 0x65, 0x64, 0x10, - 0xfd, 0x01, 0x12, 0x0c, 0x0a, 0x07, 0x43, 0x61, 0x6d, 0x70, 0x61, 0x79, 0x6e, 0x10, 0xfe, 0x01, - 0x12, 0x0e, 0x0a, 0x09, 0x43, 0x6c, 0x69, 0x6e, 0x63, 0x68, 0x70, 0x61, 0x64, 0x10, 0xff, 0x01, - 0x12, 0x0f, 0x0a, 0x0a, 0x43, 0x6f, 0x6d, 0x70, 0x61, 0x6e, 0x79, 0x48, 0x75, 0x62, 0x10, 0x80, - 0x02, 0x12, 0x0d, 0x0a, 0x08, 0x44, 0x65, 0x62, 0x6f, 0x75, 0x6e, 0x63, 0x65, 0x10, 0x81, 0x02, - 0x12, 0x0d, 0x0a, 0x08, 0x44, 0x79, 0x73, 0x70, 0x61, 0x74, 0x63, 0x68, 0x10, 0x82, 0x02, 0x12, - 0x10, 0x0a, 0x0b, 0x47, 0x75, 0x61, 0x72, 0x64, 0x69, 0x61, 0x6e, 0x61, 0x70, 0x69, 0x10, 0x83, - 0x02, 0x12, 0x0c, 0x0a, 0x07, 0x48, 0x61, 0x72, 0x76, 0x65, 0x73, 0x74, 0x10, 0x84, 0x02, 0x12, - 0x0c, 0x0a, 0x07, 0x4d, 0x6f, 0x6f, 0x73, 0x65, 0x6e, 0x64, 0x10, 0x85, 0x02, 0x12, 0x10, 0x0a, - 0x0b, 0x4f, 0x70, 0x65, 0x6e, 0x57, 0x65, 0x61, 0x74, 0x68, 0x65, 0x72, 0x10, 0x86, 0x02, 0x12, - 0x0d, 0x0a, 0x08, 0x53, 0x69, 0x74, 0x65, 0x6c, 0x65, 0x61, 0x66, 0x10, 0x87, 0x02, 0x12, 0x10, - 0x0a, 0x0b, 0x53, 0x71, 0x75, 0x61, 0x72, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x10, 0x88, 0x02, - 0x12, 0x0c, 0x0a, 0x07, 0x46, 0x6c, 0x6f, 0x77, 0x46, 0x6c, 0x75, 0x10, 0x89, 0x02, 0x12, 0x0b, - 0x0a, 0x06, 0x4e, 0x69, 0x6d, 0x62, 0x6c, 0x65, 0x10, 0x8a, 0x02, 0x12, 0x14, 0x0a, 0x0f, 0x4c, - 0x65, 0x73, 0x73, 0x41, 0x6e, 0x6e, 0x6f, 0x79, 0x69, 0x6e, 0x67, 0x43, 0x52, 0x4d, 0x10, 0x8b, - 0x02, 0x12, 0x0c, 0x0a, 0x07, 0x4e, 0x65, 0x74, 0x68, 0x75, 0x6e, 0x74, 0x10, 0x8c, 0x02, 0x12, - 0x0c, 0x0a, 0x07, 0x41, 0x70, 0x70, 0x74, 0x69, 0x76, 0x6f, 0x10, 0x8d, 0x02, 0x12, 0x0f, 0x0a, - 0x0a, 0x43, 0x61, 0x70, 0x73, 0x75, 0x6c, 0x65, 0x43, 0x52, 0x4d, 0x10, 0x8e, 0x02, 0x12, 0x0e, - 0x0a, 0x09, 0x49, 0x6e, 0x73, 0x69, 0x67, 0x68, 0x74, 0x6c, 0x79, 0x10, 0x8f, 0x02, 0x12, 0x0a, - 0x0a, 0x05, 0x4b, 0x79, 0x6c, 0x61, 0x73, 0x10, 0x90, 0x02, 0x12, 0x0f, 0x0a, 0x0a, 0x4f, 0x6e, - 0x65, 0x70, 0x61, 0x67, 0x65, 0x43, 0x52, 0x4d, 0x10, 0x91, 0x02, 0x12, 0x09, 0x0a, 0x04, 0x55, - 0x73, 0x65, 0x72, 0x10, 0x92, 0x02, 0x12, 0x10, 0x0a, 0x0b, 0x50, 0x72, 0x6f, 0x73, 0x70, 0x65, - 0x63, 0x74, 0x43, 0x52, 0x4d, 0x10, 0x93, 0x02, 0x12, 0x18, 0x0a, 0x13, 0x52, 0x65, 0x61, 0x6c, - 0x6c, 0x79, 0x53, 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x73, 0x10, - 0x94, 0x02, 0x12, 0x0c, 0x0a, 0x07, 0x41, 0x69, 0x72, 0x73, 0x68, 0x69, 0x70, 0x10, 0x95, 0x02, - 0x12, 0x0a, 0x0a, 0x05, 0x41, 0x72, 0x74, 0x73, 0x79, 0x10, 0x96, 0x02, 0x12, 0x0b, 0x0a, 0x06, - 0x59, 0x61, 0x6e, 0x64, 0x65, 0x78, 0x10, 0x97, 0x02, 0x12, 0x0d, 0x0a, 0x08, 0x43, 0x6c, 0x6f, - 0x63, 0x6b, 0x69, 0x66, 0x79, 0x10, 0x98, 0x02, 0x12, 0x0d, 0x0a, 0x08, 0x44, 0x6e, 0x73, 0x63, - 0x68, 0x65, 0x63, 0x6b, 0x10, 0x99, 0x02, 0x12, 0x10, 0x0a, 0x0b, 0x45, 0x61, 0x73, 0x79, 0x49, - 0x6e, 0x73, 0x69, 0x67, 0x68, 0x74, 0x10, 0x9a, 0x02, 0x12, 0x0e, 0x0a, 0x09, 0x45, 0x74, 0x68, - 0x70, 0x6c, 0x6f, 0x72, 0x65, 0x72, 0x10, 0x9b, 0x02, 0x12, 0x0d, 0x0a, 0x08, 0x45, 0x76, 0x65, - 0x72, 0x68, 0x6f, 0x75, 0x72, 0x10, 0x9c, 0x02, 0x12, 0x0c, 0x0a, 0x07, 0x46, 0x75, 0x6c, 0x63, - 0x72, 0x75, 0x6d, 0x10, 0x9d, 0x02, 0x12, 0x0d, 0x0a, 0x08, 0x47, 0x65, 0x6f, 0x49, 0x70, 0x69, - 0x66, 0x69, 0x10, 0x9e, 0x02, 0x12, 0x0c, 0x0a, 0x07, 0x4a, 0x6f, 0x74, 0x66, 0x6f, 0x72, 0x6d, - 0x10, 0x9f, 0x02, 0x12, 0x0c, 0x0a, 0x07, 0x52, 0x65, 0x66, 0x69, 0x6e, 0x65, 0x72, 0x10, 0xa0, - 0x02, 0x12, 0x10, 0x0a, 0x0b, 0x54, 0x69, 0x6d, 0x65, 0x7a, 0x6f, 0x6e, 0x65, 0x61, 0x70, 0x69, - 0x10, 0xa1, 0x02, 0x12, 0x0f, 0x0a, 0x0a, 0x54, 0x6f, 0x67, 0x67, 0x6c, 0x54, 0x72, 0x61, 0x63, - 0x6b, 0x10, 0xa2, 0x02, 0x12, 0x0b, 0x0a, 0x06, 0x56, 0x70, 0x6e, 0x61, 0x70, 0x69, 0x10, 0xa3, - 0x02, 0x12, 0x0e, 0x0a, 0x09, 0x57, 0x6f, 0x72, 0x6b, 0x73, 0x74, 0x61, 0x63, 0x6b, 0x10, 0xa4, - 0x02, 0x12, 0x0b, 0x0a, 0x06, 0x41, 0x70, 0x6f, 0x6c, 0x6c, 0x6f, 0x10, 0xa5, 0x02, 0x12, 0x0d, - 0x0a, 0x08, 0x45, 0x76, 0x65, 0x72, 0x73, 0x69, 0x67, 0x6e, 0x10, 0xa6, 0x02, 0x12, 0x09, 0x0a, - 0x04, 0x4a, 0x75, 0x72, 0x6f, 0x10, 0xa7, 0x02, 0x12, 0x0d, 0x0a, 0x08, 0x4b, 0x61, 0x72, 0x6d, - 0x61, 0x43, 0x52, 0x4d, 0x10, 0xa8, 0x02, 0x12, 0x0c, 0x0a, 0x07, 0x4d, 0x65, 0x74, 0x72, 0x69, - 0x6c, 0x6f, 0x10, 0xa9, 0x02, 0x12, 0x0d, 0x0a, 0x08, 0x50, 0x61, 0x6e, 0x64, 0x61, 0x64, 0x6f, - 0x63, 0x10, 0xaa, 0x02, 0x12, 0x0e, 0x0a, 0x09, 0x52, 0x65, 0x76, 0x61, 0x6d, 0x70, 0x43, 0x52, - 0x4d, 0x10, 0xab, 0x02, 0x12, 0x10, 0x0a, 0x0b, 0x53, 0x61, 0x6c, 0x65, 0x73, 0x63, 0x6f, 0x6f, - 0x6b, 0x69, 0x65, 0x10, 0xac, 0x02, 0x12, 0x0d, 0x0a, 0x08, 0x41, 0x6c, 0x63, 0x6f, 0x6e, 0x6f, - 0x73, 0x74, 0x10, 0xad, 0x02, 0x12, 0x0c, 0x0a, 0x07, 0x42, 0x6c, 0x6f, 0x67, 0x67, 0x65, 0x72, - 0x10, 0xae, 0x02, 0x12, 0x10, 0x0a, 0x0b, 0x41, 0x63, 0x63, 0x75, 0x77, 0x65, 0x61, 0x74, 0x68, - 0x65, 0x72, 0x10, 0xaf, 0x02, 0x12, 0x13, 0x0a, 0x0a, 0x4f, 0x70, 0x65, 0x6e, 0x67, 0x72, 0x61, - 0x70, 0x68, 0x72, 0x10, 0xb0, 0x02, 0x1a, 0x02, 0x08, 0x01, 0x12, 0x09, 0x0a, 0x04, 0x52, 0x61, - 0x77, 0x67, 0x10, 0xb1, 0x02, 0x12, 0x0e, 0x0a, 0x09, 0x52, 0x69, 0x6f, 0x74, 0x67, 0x61, 0x6d, - 0x65, 0x73, 0x10, 0xb2, 0x02, 0x12, 0x0d, 0x0a, 0x08, 0x52, 0x6f, 0x6e, 0x69, 0x6e, 0x41, 0x70, - 0x70, 0x10, 0xb3, 0x02, 0x12, 0x0f, 0x0a, 0x0a, 0x53, 0x74, 0x6f, 0x72, 0x6d, 0x67, 0x6c, 0x61, - 0x73, 0x73, 0x10, 0xb4, 0x02, 0x12, 0x0b, 0x0a, 0x06, 0x54, 0x6f, 0x6d, 0x74, 0x6f, 0x6d, 0x10, - 0xb5, 0x02, 0x12, 0x0b, 0x0a, 0x06, 0x54, 0x77, 0x69, 0x74, 0x63, 0x68, 0x10, 0xb6, 0x02, 0x12, - 0x0b, 0x0a, 0x06, 0x44, 0x6f, 0x63, 0x75, 0x6d, 0x6f, 0x10, 0xb7, 0x02, 0x12, 0x0e, 0x0a, 0x09, - 0x43, 0x6c, 0x6f, 0x75, 0x64, 0x77, 0x61, 0x79, 0x73, 0x10, 0xb8, 0x02, 0x12, 0x0f, 0x0a, 0x0a, - 0x56, 0x65, 0x65, 0x76, 0x61, 0x76, 0x61, 0x75, 0x6c, 0x74, 0x10, 0xb9, 0x02, 0x12, 0x10, 0x0a, - 0x0b, 0x4b, 0x69, 0x74, 0x65, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x10, 0xba, 0x02, 0x12, - 0x17, 0x0a, 0x12, 0x53, 0x68, 0x6f, 0x70, 0x65, 0x65, 0x4f, 0x70, 0x65, 0x6e, 0x50, 0x6c, 0x61, - 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x10, 0xbb, 0x02, 0x12, 0x0f, 0x0a, 0x0a, 0x54, 0x65, 0x61, 0x6d, - 0x56, 0x69, 0x65, 0x77, 0x65, 0x72, 0x10, 0xbc, 0x02, 0x12, 0x0b, 0x0a, 0x06, 0x42, 0x75, 0x6c, - 0x62, 0x75, 0x6c, 0x10, 0xbd, 0x02, 0x12, 0x16, 0x0a, 0x11, 0x43, 0x65, 0x6e, 0x74, 0x72, 0x61, - 0x6c, 0x53, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x52, 0x4d, 0x10, 0xbe, 0x02, 0x12, 0x0d, - 0x0a, 0x08, 0x54, 0x65, 0x61, 0x6d, 0x67, 0x61, 0x74, 0x65, 0x10, 0xbf, 0x02, 0x12, 0x0c, 0x0a, - 0x07, 0x41, 0x78, 0x6f, 0x6e, 0x61, 0x75, 0x74, 0x10, 0xc0, 0x02, 0x12, 0x0b, 0x0a, 0x06, 0x54, - 0x79, 0x6e, 0x74, 0x65, 0x63, 0x10, 0xc1, 0x02, 0x12, 0x0c, 0x0a, 0x07, 0x41, 0x70, 0x70, 0x63, - 0x75, 0x65, 0x73, 0x10, 0xc2, 0x02, 0x12, 0x0e, 0x0a, 0x09, 0x41, 0x75, 0x74, 0x6f, 0x6b, 0x6c, - 0x6f, 0x73, 0x65, 0x10, 0xc3, 0x02, 0x12, 0x0e, 0x0a, 0x09, 0x43, 0x6c, 0x6f, 0x75, 0x64, 0x70, - 0x6c, 0x61, 0x6e, 0x10, 0xc4, 0x02, 0x12, 0x0e, 0x0a, 0x09, 0x44, 0x6f, 0x74, 0x6d, 0x61, 0x69, - 0x6c, 0x65, 0x72, 0x10, 0xc5, 0x02, 0x12, 0x0d, 0x0a, 0x08, 0x47, 0x65, 0x74, 0x45, 0x6d, 0x61, - 0x69, 0x6c, 0x10, 0xc6, 0x02, 0x12, 0x0e, 0x0a, 0x09, 0x47, 0x65, 0x74, 0x45, 0x6d, 0x61, 0x69, - 0x6c, 0x73, 0x10, 0xc7, 0x02, 0x12, 0x0c, 0x0a, 0x07, 0x4b, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, - 0x10, 0xc8, 0x02, 0x12, 0x0f, 0x0a, 0x0a, 0x4c, 0x65, 0x61, 0x64, 0x66, 0x65, 0x65, 0x64, 0x65, - 0x72, 0x10, 0xc9, 0x02, 0x12, 0x0a, 0x0a, 0x05, 0x52, 0x61, 0x76, 0x65, 0x6e, 0x10, 0xca, 0x02, - 0x12, 0x10, 0x0a, 0x0b, 0x52, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x52, 0x65, 0x61, 0x63, 0x68, 0x10, - 0xcb, 0x02, 0x12, 0x0b, 0x0a, 0x06, 0x55, 0x70, 0x6c, 0x65, 0x61, 0x64, 0x10, 0xcc, 0x02, 0x12, - 0x0f, 0x0a, 0x0a, 0x42, 0x72, 0x61, 0x6e, 0x64, 0x66, 0x65, 0x74, 0x63, 0x68, 0x10, 0xcd, 0x02, - 0x12, 0x0d, 0x0a, 0x08, 0x43, 0x6c, 0x65, 0x61, 0x72, 0x62, 0x69, 0x74, 0x10, 0xce, 0x02, 0x12, - 0x0c, 0x0a, 0x07, 0x43, 0x72, 0x6f, 0x77, 0x64, 0x69, 0x6e, 0x10, 0xcf, 0x02, 0x12, 0x0d, 0x0a, - 0x08, 0x4d, 0x61, 0x70, 0x71, 0x75, 0x65, 0x73, 0x74, 0x10, 0xd0, 0x02, 0x12, 0x0f, 0x0a, 0x0a, - 0x4e, 0x6f, 0x74, 0x69, 0x63, 0x65, 0x61, 0x62, 0x6c, 0x65, 0x10, 0xd1, 0x02, 0x12, 0x0b, 0x0a, - 0x06, 0x4f, 0x6e, 0x62, 0x75, 0x6b, 0x61, 0x10, 0xd2, 0x02, 0x12, 0x0c, 0x0a, 0x07, 0x54, 0x6f, - 0x64, 0x6f, 0x69, 0x73, 0x74, 0x10, 0xd3, 0x02, 0x12, 0x0f, 0x0a, 0x0a, 0x53, 0x74, 0x6f, 0x72, - 0x79, 0x63, 0x68, 0x69, 0x65, 0x66, 0x10, 0xd4, 0x02, 0x12, 0x0d, 0x0a, 0x08, 0x4c, 0x69, 0x6e, - 0x6b, 0x65, 0x64, 0x49, 0x6e, 0x10, 0xd5, 0x02, 0x12, 0x0c, 0x0a, 0x07, 0x59, 0x6f, 0x75, 0x53, - 0x69, 0x67, 0x6e, 0x10, 0xd6, 0x02, 0x12, 0x0b, 0x0a, 0x06, 0x44, 0x6f, 0x63, 0x6b, 0x65, 0x72, - 0x10, 0xd7, 0x02, 0x12, 0x0d, 0x0a, 0x08, 0x54, 0x65, 0x6c, 0x65, 0x73, 0x69, 0x67, 0x6e, 0x10, - 0xd8, 0x02, 0x12, 0x10, 0x0a, 0x0b, 0x53, 0x70, 0x6f, 0x6f, 0x6e, 0x61, 0x63, 0x75, 0x6c, 0x61, - 0x72, 0x10, 0xd9, 0x02, 0x12, 0x11, 0x0a, 0x0c, 0x41, 0x65, 0x72, 0x69, 0x73, 0x77, 0x65, 0x61, - 0x74, 0x68, 0x65, 0x72, 0x10, 0xda, 0x02, 0x12, 0x11, 0x0a, 0x0c, 0x41, 0x6c, 0x70, 0x68, 0x61, - 0x76, 0x61, 0x6e, 0x74, 0x61, 0x67, 0x65, 0x10, 0xdb, 0x02, 0x12, 0x0a, 0x0a, 0x05, 0x49, 0x6d, - 0x67, 0x75, 0x72, 0x10, 0xdc, 0x02, 0x12, 0x0b, 0x0a, 0x06, 0x49, 0x6d, 0x61, 0x67, 0x67, 0x61, - 0x10, 0xdd, 0x02, 0x12, 0x0b, 0x0a, 0x06, 0x53, 0x4d, 0x53, 0x41, 0x70, 0x69, 0x10, 0xde, 0x02, - 0x12, 0x11, 0x0a, 0x0c, 0x44, 0x69, 0x73, 0x74, 0x72, 0x69, 0x62, 0x75, 0x73, 0x69, 0x6f, 0x6e, - 0x10, 0xdf, 0x02, 0x12, 0x12, 0x0a, 0x09, 0x42, 0x6c, 0x61, 0x62, 0x6c, 0x61, 0x62, 0x75, 0x73, - 0x10, 0xe0, 0x02, 0x1a, 0x02, 0x08, 0x01, 0x12, 0x0d, 0x0a, 0x08, 0x57, 0x6f, 0x72, 0x64, 0x73, - 0x41, 0x70, 0x69, 0x10, 0xe1, 0x02, 0x12, 0x12, 0x0a, 0x0d, 0x43, 0x75, 0x72, 0x72, 0x65, 0x6e, - 0x63, 0x79, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x10, 0xe2, 0x02, 0x12, 0x0d, 0x0a, 0x08, 0x48, 0x74, - 0x6d, 0x6c, 0x32, 0x50, 0x64, 0x66, 0x10, 0xe3, 0x02, 0x12, 0x12, 0x0a, 0x0d, 0x49, 0x50, 0x47, - 0x65, 0x6f, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x10, 0xe4, 0x02, 0x12, 0x0b, 0x0a, - 0x06, 0x4f, 0x77, 0x6c, 0x62, 0x6f, 0x74, 0x10, 0xe5, 0x02, 0x12, 0x11, 0x0a, 0x0c, 0x43, 0x6c, - 0x6f, 0x75, 0x64, 0x6d, 0x65, 0x72, 0x73, 0x69, 0x76, 0x65, 0x10, 0xe6, 0x02, 0x12, 0x0d, 0x0a, - 0x08, 0x44, 0x79, 0x6e, 0x61, 0x6c, 0x69, 0x73, 0x74, 0x10, 0xe7, 0x02, 0x12, 0x14, 0x0a, 0x0f, - 0x45, 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x52, 0x61, 0x74, 0x65, 0x41, 0x50, 0x49, 0x10, - 0xe8, 0x02, 0x12, 0x0f, 0x0a, 0x0a, 0x48, 0x6f, 0x6c, 0x69, 0x64, 0x61, 0x79, 0x41, 0x50, 0x49, - 0x10, 0xe9, 0x02, 0x12, 0x0a, 0x0a, 0x05, 0x49, 0x70, 0x61, 0x70, 0x69, 0x10, 0xea, 0x02, 0x12, - 0x10, 0x0a, 0x0b, 0x4d, 0x61, 0x72, 0x6b, 0x65, 0x74, 0x73, 0x74, 0x61, 0x63, 0x6b, 0x10, 0xeb, - 0x02, 0x12, 0x10, 0x0a, 0x0b, 0x4e, 0x75, 0x74, 0x72, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x69, 0x78, - 0x10, 0xec, 0x02, 0x12, 0x0a, 0x0a, 0x05, 0x53, 0x77, 0x65, 0x6c, 0x6c, 0x10, 0xed, 0x02, 0x12, - 0x19, 0x0a, 0x14, 0x43, 0x6c, 0x69, 0x63, 0x6b, 0x75, 0x70, 0x50, 0x65, 0x72, 0x73, 0x6f, 0x6e, - 0x61, 0x6c, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x10, 0xee, 0x02, 0x12, 0x0e, 0x0a, 0x05, 0x4e, 0x69, - 0x74, 0x72, 0x6f, 0x10, 0xef, 0x02, 0x1a, 0x02, 0x08, 0x01, 0x12, 0x08, 0x0a, 0x03, 0x52, 0x65, - 0x76, 0x10, 0xf0, 0x02, 0x12, 0x0d, 0x0a, 0x08, 0x52, 0x75, 0x6e, 0x52, 0x75, 0x6e, 0x49, 0x74, - 0x10, 0xf1, 0x02, 0x12, 0x0d, 0x0a, 0x08, 0x54, 0x79, 0x70, 0x65, 0x66, 0x6f, 0x72, 0x6d, 0x10, - 0xf2, 0x02, 0x12, 0x0d, 0x0a, 0x08, 0x4d, 0x69, 0x78, 0x70, 0x61, 0x6e, 0x65, 0x6c, 0x10, 0xf3, - 0x02, 0x12, 0x0c, 0x0a, 0x07, 0x54, 0x72, 0x61, 0x64, 0x69, 0x65, 0x72, 0x10, 0xf4, 0x02, 0x12, - 0x0d, 0x0a, 0x08, 0x56, 0x65, 0x72, 0x69, 0x66, 0x69, 0x65, 0x72, 0x10, 0xf5, 0x02, 0x12, 0x0d, - 0x0a, 0x08, 0x56, 0x6f, 0x75, 0x63, 0x68, 0x65, 0x72, 0x79, 0x10, 0xf6, 0x02, 0x12, 0x0b, 0x0a, - 0x06, 0x41, 0x6c, 0x65, 0x67, 0x72, 0x61, 0x10, 0xf7, 0x02, 0x12, 0x09, 0x0a, 0x04, 0x41, 0x75, - 0x64, 0x64, 0x10, 0xf8, 0x02, 0x12, 0x10, 0x0a, 0x0b, 0x42, 0x61, 0x72, 0x65, 0x6d, 0x65, 0x74, - 0x72, 0x69, 0x63, 0x73, 0x10, 0xf9, 0x02, 0x12, 0x0c, 0x0a, 0x07, 0x43, 0x6f, 0x69, 0x6e, 0x6c, - 0x69, 0x62, 0x10, 0xfa, 0x02, 0x12, 0x15, 0x0a, 0x10, 0x45, 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, - 0x65, 0x52, 0x61, 0x74, 0x65, 0x73, 0x41, 0x50, 0x49, 0x10, 0xfb, 0x02, 0x12, 0x12, 0x0a, 0x0d, - 0x43, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x53, 0x63, 0x6f, 0x6f, 0x70, 0x10, 0xfc, 0x02, - 0x12, 0x0d, 0x0a, 0x08, 0x46, 0x58, 0x4d, 0x61, 0x72, 0x6b, 0x65, 0x74, 0x10, 0xfd, 0x02, 0x12, - 0x12, 0x0a, 0x0d, 0x43, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x43, 0x6c, 0x6f, 0x75, 0x64, - 0x10, 0xfe, 0x02, 0x12, 0x0e, 0x0a, 0x09, 0x47, 0x65, 0x74, 0x47, 0x65, 0x6f, 0x41, 0x50, 0x49, - 0x10, 0xff, 0x02, 0x12, 0x0d, 0x0a, 0x08, 0x41, 0x62, 0x73, 0x74, 0x72, 0x61, 0x63, 0x74, 0x10, - 0x80, 0x03, 0x12, 0x0d, 0x0a, 0x08, 0x42, 0x69, 0x6c, 0x6c, 0x6f, 0x6d, 0x61, 0x74, 0x10, 0x81, - 0x03, 0x12, 0x0b, 0x0a, 0x06, 0x44, 0x6f, 0x76, 0x69, 0x63, 0x6f, 0x10, 0x82, 0x03, 0x12, 0x0b, - 0x0a, 0x06, 0x42, 0x69, 0x74, 0x62, 0x61, 0x72, 0x10, 0x83, 0x03, 0x12, 0x0c, 0x0a, 0x07, 0x42, - 0x75, 0x67, 0x73, 0x6e, 0x61, 0x67, 0x10, 0x84, 0x03, 0x12, 0x0f, 0x0a, 0x0a, 0x41, 0x73, 0x73, - 0x65, 0x6d, 0x62, 0x6c, 0x79, 0x41, 0x49, 0x10, 0x85, 0x03, 0x12, 0x0f, 0x0a, 0x0a, 0x41, 0x64, - 0x61, 0x66, 0x72, 0x75, 0x69, 0x74, 0x49, 0x4f, 0x10, 0x86, 0x03, 0x12, 0x0a, 0x0a, 0x05, 0x41, - 0x70, 0x69, 0x66, 0x79, 0x10, 0x87, 0x03, 0x12, 0x0e, 0x0a, 0x09, 0x43, 0x6f, 0x69, 0x6e, 0x47, - 0x65, 0x63, 0x6b, 0x6f, 0x10, 0x88, 0x03, 0x12, 0x12, 0x0a, 0x0d, 0x43, 0x72, 0x79, 0x70, 0x74, - 0x6f, 0x43, 0x6f, 0x6d, 0x70, 0x61, 0x72, 0x65, 0x10, 0x89, 0x03, 0x12, 0x0e, 0x0a, 0x09, 0x46, - 0x75, 0x6c, 0x6c, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x10, 0x8a, 0x03, 0x12, 0x0e, 0x0a, 0x09, 0x48, - 0x65, 0x6c, 0x6c, 0x6f, 0x53, 0x69, 0x67, 0x6e, 0x10, 0x8b, 0x03, 0x12, 0x0d, 0x0a, 0x08, 0x4c, - 0x6f, 0x79, 0x76, 0x65, 0x72, 0x73, 0x65, 0x10, 0x8c, 0x03, 0x12, 0x0c, 0x0a, 0x07, 0x4e, 0x65, - 0x74, 0x43, 0x6f, 0x72, 0x65, 0x10, 0x8d, 0x03, 0x12, 0x0e, 0x0a, 0x09, 0x53, 0x61, 0x75, 0x63, - 0x65, 0x4c, 0x61, 0x62, 0x73, 0x10, 0x8e, 0x03, 0x12, 0x0f, 0x0a, 0x0a, 0x41, 0x6c, 0x69, 0x65, - 0x6e, 0x56, 0x61, 0x75, 0x6c, 0x74, 0x10, 0x8f, 0x03, 0x12, 0x0d, 0x0a, 0x08, 0x41, 0x70, 0x69, - 0x66, 0x6c, 0x61, 0x73, 0x68, 0x10, 0x91, 0x03, 0x12, 0x0e, 0x0a, 0x09, 0x43, 0x6f, 0x69, 0x6e, - 0x6c, 0x61, 0x79, 0x65, 0x72, 0x10, 0x92, 0x03, 0x12, 0x10, 0x0a, 0x0b, 0x43, 0x75, 0x72, 0x72, - 0x65, 0x6e, 0x74, 0x73, 0x41, 0x50, 0x49, 0x10, 0x93, 0x03, 0x12, 0x0c, 0x0a, 0x07, 0x44, 0x61, - 0x74, 0x61, 0x47, 0x6f, 0x76, 0x10, 0x94, 0x03, 0x12, 0x0b, 0x0a, 0x06, 0x45, 0x6e, 0x69, 0x67, - 0x6d, 0x61, 0x10, 0x95, 0x03, 0x12, 0x1a, 0x0a, 0x15, 0x46, 0x69, 0x6e, 0x61, 0x6e, 0x63, 0x69, - 0x61, 0x6c, 0x4d, 0x6f, 0x64, 0x65, 0x6c, 0x69, 0x6e, 0x67, 0x50, 0x72, 0x65, 0x70, 0x10, 0x96, - 0x03, 0x12, 0x0d, 0x0a, 0x08, 0x47, 0x65, 0x6f, 0x63, 0x6f, 0x64, 0x69, 0x6f, 0x10, 0x97, 0x03, - 0x12, 0x0c, 0x0a, 0x07, 0x48, 0x65, 0x72, 0x65, 0x41, 0x50, 0x49, 0x10, 0x98, 0x03, 0x12, 0x13, - 0x0a, 0x0a, 0x4d, 0x61, 0x63, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x10, 0x99, 0x03, 0x1a, - 0x02, 0x08, 0x01, 0x12, 0x0c, 0x0a, 0x07, 0x4f, 0x4f, 0x50, 0x53, 0x70, 0x61, 0x6d, 0x10, 0x9a, - 0x03, 0x12, 0x10, 0x0a, 0x0b, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x73, 0x49, 0x4f, - 0x10, 0x9b, 0x03, 0x12, 0x0f, 0x0a, 0x0a, 0x53, 0x63, 0x72, 0x61, 0x70, 0x65, 0x72, 0x41, 0x50, - 0x49, 0x10, 0x9c, 0x03, 0x12, 0x13, 0x0a, 0x0e, 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, - 0x54, 0x72, 0x61, 0x69, 0x6c, 0x73, 0x10, 0x9d, 0x03, 0x12, 0x0f, 0x0a, 0x0a, 0x54, 0x6f, 0x6d, - 0x6f, 0x72, 0x72, 0x6f, 0x77, 0x49, 0x4f, 0x10, 0x9e, 0x03, 0x12, 0x13, 0x0a, 0x0e, 0x57, 0x6f, - 0x72, 0x6c, 0x64, 0x43, 0x6f, 0x69, 0x6e, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x10, 0x9f, 0x03, 0x12, - 0x11, 0x0a, 0x0c, 0x46, 0x61, 0x63, 0x65, 0x50, 0x6c, 0x75, 0x73, 0x50, 0x6c, 0x75, 0x73, 0x10, - 0xa0, 0x03, 0x12, 0x0e, 0x0a, 0x09, 0x56, 0x6f, 0x69, 0x63, 0x65, 0x67, 0x61, 0x69, 0x6e, 0x10, - 0xa1, 0x03, 0x12, 0x0d, 0x0a, 0x08, 0x44, 0x65, 0x65, 0x70, 0x67, 0x72, 0x61, 0x6d, 0x10, 0xa2, - 0x03, 0x12, 0x13, 0x0a, 0x0e, 0x56, 0x69, 0x73, 0x75, 0x61, 0x6c, 0x43, 0x72, 0x6f, 0x73, 0x73, - 0x69, 0x6e, 0x67, 0x10, 0xa3, 0x03, 0x12, 0x0c, 0x0a, 0x07, 0x46, 0x69, 0x6e, 0x6e, 0x68, 0x75, - 0x62, 0x10, 0xa4, 0x03, 0x12, 0x0b, 0x0a, 0x06, 0x54, 0x69, 0x69, 0x6e, 0x67, 0x6f, 0x10, 0xa5, - 0x03, 0x12, 0x10, 0x0a, 0x0b, 0x52, 0x69, 0x6e, 0x67, 0x43, 0x65, 0x6e, 0x74, 0x72, 0x61, 0x6c, - 0x10, 0xa6, 0x03, 0x12, 0x0b, 0x0a, 0x06, 0x46, 0x69, 0x6e, 0x61, 0x67, 0x65, 0x10, 0xa7, 0x03, - 0x12, 0x0b, 0x0a, 0x06, 0x45, 0x64, 0x61, 0x6d, 0x61, 0x6d, 0x10, 0xa8, 0x03, 0x12, 0x10, 0x0a, - 0x0b, 0x48, 0x79, 0x70, 0x65, 0x41, 0x75, 0x64, 0x69, 0x74, 0x6f, 0x72, 0x10, 0xa9, 0x03, 0x12, - 0x0a, 0x0a, 0x05, 0x47, 0x65, 0x6e, 0x67, 0x6f, 0x10, 0xaa, 0x03, 0x12, 0x0a, 0x0a, 0x05, 0x46, - 0x72, 0x6f, 0x6e, 0x74, 0x10, 0xab, 0x03, 0x12, 0x0e, 0x0a, 0x09, 0x46, 0x6c, 0x65, 0x65, 0x74, - 0x62, 0x61, 0x73, 0x65, 0x10, 0xac, 0x03, 0x12, 0x0b, 0x0a, 0x06, 0x42, 0x75, 0x62, 0x62, 0x6c, - 0x65, 0x10, 0xad, 0x03, 0x12, 0x0f, 0x0a, 0x0a, 0x42, 0x61, 0x6e, 0x6e, 0x65, 0x72, 0x62, 0x65, - 0x61, 0x72, 0x10, 0xae, 0x03, 0x12, 0x0b, 0x0a, 0x06, 0x41, 0x64, 0x7a, 0x75, 0x6e, 0x61, 0x10, - 0xaf, 0x03, 0x12, 0x13, 0x0a, 0x0e, 0x42, 0x69, 0x74, 0x63, 0x6f, 0x69, 0x6e, 0x41, 0x76, 0x65, - 0x72, 0x61, 0x67, 0x65, 0x10, 0xb0, 0x03, 0x12, 0x0f, 0x0a, 0x0a, 0x43, 0x6f, 0x6d, 0x6d, 0x65, - 0x72, 0x63, 0x65, 0x4a, 0x53, 0x10, 0xb1, 0x03, 0x12, 0x13, 0x0a, 0x0e, 0x44, 0x65, 0x74, 0x65, - 0x63, 0x74, 0x4c, 0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65, 0x10, 0xb2, 0x03, 0x12, 0x11, 0x0a, - 0x08, 0x46, 0x61, 0x6b, 0x65, 0x4a, 0x53, 0x4f, 0x4e, 0x10, 0xb3, 0x03, 0x1a, 0x02, 0x08, 0x01, - 0x12, 0x10, 0x0a, 0x0b, 0x47, 0x72, 0x61, 0x70, 0x68, 0x68, 0x6f, 0x70, 0x70, 0x65, 0x72, 0x10, - 0xb4, 0x03, 0x12, 0x0d, 0x0a, 0x08, 0x4c, 0x65, 0x78, 0x69, 0x67, 0x72, 0x61, 0x6d, 0x10, 0xb5, - 0x03, 0x12, 0x10, 0x0a, 0x0b, 0x4c, 0x69, 0x6e, 0x6b, 0x50, 0x72, 0x65, 0x76, 0x69, 0x65, 0x77, - 0x10, 0xb6, 0x03, 0x12, 0x0e, 0x0a, 0x09, 0x4e, 0x75, 0x6d, 0x76, 0x65, 0x72, 0x69, 0x66, 0x79, - 0x10, 0xb7, 0x03, 0x12, 0x0f, 0x0a, 0x0a, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x43, 0x72, 0x61, 0x77, - 0x6c, 0x10, 0xb8, 0x03, 0x12, 0x0f, 0x0a, 0x0a, 0x5a, 0x69, 0x70, 0x43, 0x6f, 0x64, 0x65, 0x41, - 0x50, 0x49, 0x10, 0xb9, 0x03, 0x12, 0x0e, 0x0a, 0x09, 0x43, 0x6f, 0x6d, 0x65, 0x74, 0x63, 0x68, - 0x61, 0x74, 0x10, 0xba, 0x03, 0x12, 0x0b, 0x0a, 0x06, 0x4b, 0x65, 0x79, 0x67, 0x65, 0x6e, 0x10, - 0xbb, 0x03, 0x12, 0x0d, 0x0a, 0x08, 0x4d, 0x69, 0x78, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x10, 0xbc, - 0x03, 0x12, 0x0c, 0x0a, 0x07, 0x54, 0x61, 0x74, 0x75, 0x6d, 0x49, 0x4f, 0x10, 0xbd, 0x03, 0x12, - 0x0c, 0x0a, 0x07, 0x54, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x10, 0xbe, 0x03, 0x12, 0x0f, 0x0a, - 0x06, 0x4c, 0x61, 0x73, 0x74, 0x66, 0x6d, 0x10, 0xbf, 0x03, 0x1a, 0x02, 0x08, 0x01, 0x12, 0x0d, - 0x0a, 0x08, 0x42, 0x72, 0x6f, 0x77, 0x73, 0x68, 0x6f, 0x74, 0x10, 0xc0, 0x03, 0x12, 0x0c, 0x0a, - 0x07, 0x4a, 0x53, 0x4f, 0x4e, 0x62, 0x69, 0x6e, 0x10, 0xc1, 0x03, 0x12, 0x0f, 0x0a, 0x0a, 0x4c, - 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x51, 0x10, 0xc2, 0x03, 0x12, 0x12, 0x0a, 0x0d, - 0x53, 0x63, 0x72, 0x65, 0x65, 0x6e, 0x73, 0x68, 0x6f, 0x74, 0x41, 0x50, 0x49, 0x10, 0xc3, 0x03, - 0x12, 0x11, 0x0a, 0x0c, 0x57, 0x65, 0x61, 0x74, 0x68, 0x65, 0x72, 0x53, 0x74, 0x61, 0x63, 0x6b, - 0x10, 0xc4, 0x03, 0x12, 0x0c, 0x0a, 0x07, 0x41, 0x6d, 0x61, 0x64, 0x65, 0x75, 0x73, 0x10, 0xc5, - 0x03, 0x12, 0x0f, 0x0a, 0x0a, 0x46, 0x6f, 0x75, 0x72, 0x53, 0x71, 0x75, 0x61, 0x72, 0x65, 0x10, - 0xc6, 0x03, 0x12, 0x0b, 0x0a, 0x06, 0x46, 0x6c, 0x69, 0x63, 0x6b, 0x72, 0x10, 0xc7, 0x03, 0x12, - 0x0e, 0x0a, 0x09, 0x43, 0x6c, 0x69, 0x63, 0x6b, 0x48, 0x65, 0x6c, 0x70, 0x10, 0xc8, 0x03, 0x12, - 0x0a, 0x0a, 0x05, 0x41, 0x6d, 0x62, 0x65, 0x65, 0x10, 0xc9, 0x03, 0x12, 0x0d, 0x0a, 0x08, 0x41, - 0x70, 0x69, 0x32, 0x43, 0x61, 0x72, 0x74, 0x10, 0xca, 0x03, 0x12, 0x0f, 0x0a, 0x0a, 0x48, 0x79, - 0x70, 0x65, 0x72, 0x74, 0x72, 0x61, 0x63, 0x6b, 0x10, 0xcb, 0x03, 0x12, 0x0e, 0x0a, 0x09, 0x4b, - 0x61, 0x6b, 0x61, 0x6f, 0x54, 0x61, 0x6c, 0x6b, 0x10, 0xcc, 0x03, 0x12, 0x0c, 0x0a, 0x07, 0x52, - 0x69, 0x74, 0x65, 0x4b, 0x69, 0x74, 0x10, 0xcd, 0x03, 0x12, 0x11, 0x0a, 0x0c, 0x53, 0x68, 0x75, - 0x74, 0x74, 0x65, 0x72, 0x73, 0x74, 0x6f, 0x63, 0x6b, 0x10, 0xce, 0x03, 0x12, 0x12, 0x0a, 0x09, - 0x54, 0x65, 0x78, 0x74, 0x32, 0x44, 0x61, 0x74, 0x61, 0x10, 0xcf, 0x03, 0x1a, 0x02, 0x08, 0x01, - 0x12, 0x13, 0x0a, 0x0e, 0x59, 0x6f, 0x75, 0x4e, 0x65, 0x65, 0x64, 0x41, 0x42, 0x75, 0x64, 0x67, - 0x65, 0x74, 0x10, 0xd0, 0x03, 0x12, 0x0c, 0x0a, 0x07, 0x43, 0x72, 0x69, 0x63, 0x6b, 0x65, 0x74, - 0x10, 0xd1, 0x03, 0x12, 0x0e, 0x0a, 0x09, 0x46, 0x69, 0x6c, 0x65, 0x73, 0x74, 0x61, 0x63, 0x6b, - 0x10, 0xd2, 0x03, 0x12, 0x0a, 0x0a, 0x05, 0x47, 0x79, 0x61, 0x7a, 0x6f, 0x10, 0xd3, 0x03, 0x12, - 0x0e, 0x0a, 0x09, 0x4d, 0x61, 0x76, 0x65, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x10, 0xd4, 0x03, 0x12, - 0x0b, 0x0a, 0x06, 0x53, 0x68, 0x65, 0x65, 0x74, 0x79, 0x10, 0xd5, 0x03, 0x12, 0x0f, 0x0a, 0x0a, - 0x53, 0x70, 0x6f, 0x72, 0x74, 0x73, 0x6d, 0x6f, 0x6e, 0x6b, 0x10, 0xd6, 0x03, 0x12, 0x0e, 0x0a, - 0x09, 0x53, 0x74, 0x6f, 0x63, 0x6b, 0x64, 0x61, 0x74, 0x61, 0x10, 0xd7, 0x03, 0x12, 0x0d, 0x0a, - 0x08, 0x55, 0x6e, 0x73, 0x70, 0x6c, 0x61, 0x73, 0x68, 0x10, 0xd8, 0x03, 0x12, 0x0e, 0x0a, 0x09, - 0x41, 0x6c, 0x6c, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x73, 0x10, 0xd9, 0x03, 0x12, 0x11, 0x0a, 0x0c, - 0x43, 0x61, 0x6c, 0x6f, 0x72, 0x69, 0x65, 0x4e, 0x69, 0x6e, 0x6a, 0x61, 0x10, 0xda, 0x03, 0x12, - 0x0e, 0x0a, 0x09, 0x57, 0x61, 0x6c, 0x6b, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x10, 0xdb, 0x03, 0x12, - 0x0b, 0x0a, 0x06, 0x53, 0x74, 0x72, 0x61, 0x76, 0x61, 0x10, 0xdc, 0x03, 0x12, 0x0b, 0x0a, 0x06, - 0x43, 0x69, 0x63, 0x65, 0x72, 0x6f, 0x10, 0xdd, 0x03, 0x12, 0x0e, 0x0a, 0x09, 0x49, 0x50, 0x51, - 0x75, 0x61, 0x6c, 0x69, 0x74, 0x79, 0x10, 0xde, 0x03, 0x12, 0x11, 0x0a, 0x0c, 0x50, 0x61, 0x72, - 0x61, 0x6c, 0x6c, 0x65, 0x6c, 0x44, 0x6f, 0x74, 0x73, 0x10, 0xdf, 0x03, 0x12, 0x0c, 0x0a, 0x07, - 0x52, 0x6f, 0x61, 0x72, 0x69, 0x6e, 0x67, 0x10, 0xe0, 0x03, 0x12, 0x0c, 0x0a, 0x07, 0x4d, 0x61, - 0x69, 0x6c, 0x73, 0x61, 0x63, 0x10, 0xe1, 0x03, 0x12, 0x0a, 0x0a, 0x05, 0x57, 0x68, 0x6f, 0x78, - 0x79, 0x10, 0xe2, 0x03, 0x12, 0x11, 0x0a, 0x0c, 0x57, 0x6f, 0x72, 0x6c, 0x64, 0x57, 0x65, 0x61, - 0x74, 0x68, 0x65, 0x72, 0x10, 0xe3, 0x03, 0x12, 0x0e, 0x0a, 0x09, 0x41, 0x70, 0x69, 0x46, 0x6f, - 0x6e, 0x69, 0x63, 0x61, 0x10, 0xe4, 0x03, 0x12, 0x0b, 0x0a, 0x06, 0x41, 0x79, 0x6c, 0x69, 0x65, - 0x6e, 0x10, 0xe5, 0x03, 0x12, 0x0c, 0x0a, 0x07, 0x47, 0x65, 0x6f, 0x63, 0x6f, 0x64, 0x65, 0x10, - 0xe6, 0x03, 0x12, 0x0f, 0x0a, 0x0a, 0x49, 0x63, 0x6f, 0x6e, 0x46, 0x69, 0x6e, 0x64, 0x65, 0x72, - 0x10, 0xe7, 0x03, 0x12, 0x0e, 0x0a, 0x05, 0x49, 0x70, 0x69, 0x66, 0x79, 0x10, 0xe8, 0x03, 0x1a, - 0x02, 0x08, 0x01, 0x12, 0x12, 0x0a, 0x0d, 0x4c, 0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65, 0x4c, - 0x61, 0x79, 0x65, 0x72, 0x10, 0xe9, 0x03, 0x12, 0x08, 0x0a, 0x03, 0x4c, 0x6f, 0x62, 0x10, 0xea, - 0x03, 0x12, 0x12, 0x0a, 0x09, 0x4f, 0x6e, 0x57, 0x61, 0x74, 0x65, 0x72, 0x49, 0x4f, 0x10, 0xeb, - 0x03, 0x1a, 0x02, 0x08, 0x01, 0x12, 0x0d, 0x0a, 0x08, 0x50, 0x61, 0x73, 0x74, 0x65, 0x62, 0x69, - 0x6e, 0x10, 0xec, 0x03, 0x12, 0x0d, 0x0a, 0x08, 0x50, 0x64, 0x66, 0x4c, 0x61, 0x79, 0x65, 0x72, - 0x10, 0xed, 0x03, 0x12, 0x0c, 0x0a, 0x07, 0x50, 0x69, 0x78, 0x61, 0x62, 0x61, 0x79, 0x10, 0xee, - 0x03, 0x12, 0x0b, 0x0a, 0x06, 0x52, 0x65, 0x61, 0x64, 0x4d, 0x65, 0x10, 0xef, 0x03, 0x12, 0x0d, - 0x0a, 0x08, 0x56, 0x61, 0x74, 0x4c, 0x61, 0x79, 0x65, 0x72, 0x10, 0xf0, 0x03, 0x12, 0x0f, 0x0a, - 0x0a, 0x56, 0x69, 0x72, 0x75, 0x73, 0x54, 0x6f, 0x74, 0x61, 0x6c, 0x10, 0xf1, 0x03, 0x12, 0x0e, - 0x0a, 0x09, 0x41, 0x69, 0x72, 0x56, 0x69, 0x73, 0x75, 0x61, 0x6c, 0x10, 0xf2, 0x03, 0x12, 0x13, - 0x0a, 0x0e, 0x43, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x66, 0x72, 0x65, 0x61, 0x6b, 0x73, - 0x10, 0xf3, 0x03, 0x12, 0x0b, 0x0a, 0x06, 0x44, 0x75, 0x66, 0x66, 0x65, 0x6c, 0x10, 0xf4, 0x03, - 0x12, 0x0b, 0x0a, 0x06, 0x46, 0x6c, 0x61, 0x74, 0x49, 0x4f, 0x10, 0xf5, 0x03, 0x12, 0x08, 0x0a, - 0x03, 0x4d, 0x33, 0x6f, 0x10, 0xf6, 0x03, 0x12, 0x0b, 0x0a, 0x06, 0x4d, 0x65, 0x73, 0x69, 0x62, - 0x6f, 0x10, 0xf7, 0x03, 0x12, 0x0b, 0x0a, 0x06, 0x4f, 0x70, 0x65, 0x6e, 0x75, 0x76, 0x10, 0xf8, - 0x03, 0x12, 0x0d, 0x0a, 0x08, 0x53, 0x6e, 0x69, 0x70, 0x63, 0x61, 0x72, 0x74, 0x10, 0xf9, 0x03, - 0x12, 0x0d, 0x0a, 0x08, 0x42, 0x65, 0x73, 0x74, 0x74, 0x69, 0x6d, 0x65, 0x10, 0xfa, 0x03, 0x12, - 0x10, 0x0a, 0x0b, 0x48, 0x61, 0x70, 0x70, 0x79, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x10, 0xfb, - 0x03, 0x12, 0x0d, 0x0a, 0x08, 0x48, 0x75, 0x6d, 0x61, 0x6e, 0x69, 0x74, 0x79, 0x10, 0xfc, 0x03, - 0x12, 0x0b, 0x0a, 0x06, 0x49, 0x6d, 0x70, 0x61, 0x6c, 0x61, 0x10, 0xfd, 0x03, 0x12, 0x10, 0x0a, - 0x0b, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x72, 0x61, 0x64, 0x69, 0x75, 0x73, 0x10, 0xfe, 0x03, 0x12, - 0x0e, 0x0a, 0x09, 0x41, 0x75, 0x74, 0x6f, 0x50, 0x69, 0x6c, 0x6f, 0x74, 0x10, 0xff, 0x03, 0x12, - 0x0b, 0x0a, 0x06, 0x42, 0x69, 0x74, 0x6d, 0x65, 0x78, 0x10, 0x80, 0x04, 0x12, 0x0d, 0x0a, 0x08, - 0x43, 0x6c, 0x75, 0x73, 0x74, 0x44, 0x6f, 0x63, 0x10, 0x81, 0x04, 0x12, 0x0c, 0x0a, 0x07, 0x4d, - 0x65, 0x73, 0x73, 0x61, 0x72, 0x69, 0x10, 0x82, 0x04, 0x12, 0x0d, 0x0a, 0x08, 0x50, 0x64, 0x66, - 0x53, 0x68, 0x69, 0x66, 0x74, 0x10, 0x83, 0x04, 0x12, 0x0d, 0x0a, 0x08, 0x50, 0x6f, 0x6c, 0x6f, - 0x6e, 0x69, 0x65, 0x78, 0x10, 0x84, 0x04, 0x12, 0x19, 0x0a, 0x14, 0x52, 0x65, 0x73, 0x74, 0x70, - 0x61, 0x63, 0x6b, 0x48, 0x74, 0x6d, 0x6c, 0x54, 0x6f, 0x50, 0x64, 0x66, 0x41, 0x50, 0x49, 0x10, - 0x85, 0x04, 0x12, 0x1a, 0x0a, 0x15, 0x52, 0x65, 0x73, 0x74, 0x70, 0x61, 0x63, 0x6b, 0x53, 0x63, - 0x72, 0x65, 0x65, 0x6e, 0x73, 0x68, 0x6f, 0x74, 0x41, 0x50, 0x49, 0x10, 0x86, 0x04, 0x12, 0x16, - 0x0a, 0x11, 0x53, 0x68, 0x75, 0x74, 0x74, 0x65, 0x72, 0x73, 0x74, 0x6f, 0x63, 0x6b, 0x4f, 0x41, - 0x75, 0x74, 0x68, 0x10, 0x87, 0x04, 0x12, 0x10, 0x0a, 0x0b, 0x53, 0x6b, 0x79, 0x42, 0x69, 0x6f, - 0x6d, 0x65, 0x74, 0x72, 0x79, 0x10, 0x88, 0x04, 0x12, 0x0e, 0x0a, 0x09, 0x41, 0x62, 0x75, 0x73, - 0x65, 0x49, 0x50, 0x44, 0x42, 0x10, 0x89, 0x04, 0x12, 0x10, 0x0a, 0x0b, 0x41, 0x6c, 0x65, 0x74, - 0x68, 0x65, 0x69, 0x61, 0x41, 0x70, 0x69, 0x10, 0x8a, 0x04, 0x12, 0x0c, 0x0a, 0x07, 0x42, 0x6c, - 0x69, 0x74, 0x41, 0x70, 0x70, 0x10, 0x8b, 0x04, 0x12, 0x0b, 0x0a, 0x06, 0x43, 0x65, 0x6e, 0x73, - 0x79, 0x73, 0x10, 0x8c, 0x04, 0x12, 0x0d, 0x0a, 0x08, 0x43, 0x6c, 0x6f, 0x76, 0x65, 0x72, 0x6c, - 0x79, 0x10, 0x8d, 0x04, 0x12, 0x11, 0x0a, 0x0c, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x72, 0x79, 0x4c, - 0x61, 0x79, 0x65, 0x72, 0x10, 0x8e, 0x04, 0x12, 0x0b, 0x0a, 0x06, 0x46, 0x69, 0x6c, 0x65, 0x49, - 0x4f, 0x10, 0x8f, 0x04, 0x12, 0x0e, 0x0a, 0x09, 0x46, 0x6c, 0x69, 0x67, 0x68, 0x74, 0x41, 0x70, - 0x69, 0x10, 0x90, 0x04, 0x12, 0x0d, 0x0a, 0x08, 0x47, 0x65, 0x6f, 0x61, 0x70, 0x69, 0x66, 0x79, - 0x10, 0x91, 0x04, 0x12, 0x0d, 0x0a, 0x08, 0x49, 0x50, 0x69, 0x6e, 0x66, 0x6f, 0x44, 0x42, 0x10, - 0x92, 0x04, 0x12, 0x0f, 0x0a, 0x0a, 0x4d, 0x65, 0x64, 0x69, 0x61, 0x53, 0x74, 0x61, 0x63, 0x6b, - 0x10, 0x93, 0x04, 0x12, 0x13, 0x0a, 0x0e, 0x4e, 0x61, 0x73, 0x64, 0x61, 0x71, 0x44, 0x61, 0x74, - 0x61, 0x4c, 0x69, 0x6e, 0x6b, 0x10, 0x94, 0x04, 0x12, 0x11, 0x0a, 0x0c, 0x4f, 0x70, 0x65, 0x6e, - 0x43, 0x61, 0x67, 0x65, 0x44, 0x61, 0x74, 0x61, 0x10, 0x95, 0x04, 0x12, 0x0d, 0x0a, 0x08, 0x50, - 0x61, 0x79, 0x6d, 0x6f, 0x6e, 0x67, 0x6f, 0x10, 0x96, 0x04, 0x12, 0x12, 0x0a, 0x0d, 0x50, 0x6f, - 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x63, 0x6b, 0x10, 0x97, 0x04, 0x12, 0x0e, - 0x0a, 0x09, 0x52, 0x65, 0x62, 0x72, 0x61, 0x6e, 0x64, 0x6c, 0x79, 0x10, 0x98, 0x04, 0x12, 0x14, - 0x0a, 0x0f, 0x53, 0x63, 0x72, 0x65, 0x65, 0x6e, 0x73, 0x68, 0x6f, 0x74, 0x4c, 0x61, 0x79, 0x65, - 0x72, 0x10, 0x99, 0x04, 0x12, 0x0b, 0x0a, 0x06, 0x53, 0x74, 0x79, 0x74, 0x63, 0x68, 0x10, 0x9a, - 0x04, 0x12, 0x0c, 0x0a, 0x07, 0x55, 0x6e, 0x70, 0x6c, 0x75, 0x67, 0x67, 0x10, 0x9b, 0x04, 0x12, - 0x10, 0x0a, 0x0b, 0x55, 0x50, 0x43, 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x10, 0x9c, - 0x04, 0x12, 0x0e, 0x0a, 0x09, 0x55, 0x73, 0x65, 0x72, 0x53, 0x74, 0x61, 0x63, 0x6b, 0x10, 0x9d, - 0x04, 0x12, 0x0e, 0x0a, 0x09, 0x47, 0x65, 0x6f, 0x63, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x10, 0x9e, - 0x04, 0x12, 0x10, 0x0a, 0x0b, 0x4e, 0x65, 0x77, 0x73, 0x63, 0x61, 0x74, 0x63, 0x68, 0x65, 0x72, - 0x10, 0x9f, 0x04, 0x12, 0x0e, 0x0a, 0x09, 0x4e, 0x69, 0x63, 0x65, 0x72, 0x65, 0x70, 0x6c, 0x79, - 0x10, 0xa0, 0x04, 0x12, 0x11, 0x0a, 0x0c, 0x50, 0x61, 0x72, 0x74, 0x6e, 0x65, 0x72, 0x73, 0x74, - 0x61, 0x63, 0x6b, 0x10, 0xa1, 0x04, 0x12, 0x0d, 0x0a, 0x08, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x34, - 0x6d, 0x65, 0x10, 0xa2, 0x04, 0x12, 0x0e, 0x0a, 0x09, 0x53, 0x63, 0x72, 0x61, 0x70, 0x65, 0x6f, - 0x77, 0x6c, 0x10, 0xa3, 0x04, 0x12, 0x10, 0x0a, 0x0b, 0x53, 0x63, 0x72, 0x61, 0x70, 0x69, 0x6e, - 0x67, 0x44, 0x6f, 0x67, 0x10, 0xa4, 0x04, 0x12, 0x0b, 0x0a, 0x06, 0x53, 0x74, 0x72, 0x65, 0x61, - 0x6b, 0x10, 0xa5, 0x04, 0x12, 0x0e, 0x0a, 0x09, 0x56, 0x65, 0x72, 0x69, 0x70, 0x68, 0x6f, 0x6e, - 0x65, 0x10, 0xa6, 0x04, 0x12, 0x10, 0x0a, 0x0b, 0x57, 0x65, 0x62, 0x73, 0x63, 0x72, 0x61, 0x70, - 0x69, 0x6e, 0x67, 0x10, 0xa7, 0x04, 0x12, 0x0e, 0x0a, 0x09, 0x5a, 0x65, 0x6e, 0x73, 0x63, 0x72, - 0x61, 0x70, 0x65, 0x10, 0xa8, 0x04, 0x12, 0x0c, 0x0a, 0x07, 0x5a, 0x65, 0x6e, 0x73, 0x65, 0x72, - 0x70, 0x10, 0xa9, 0x04, 0x12, 0x0c, 0x0a, 0x07, 0x43, 0x6f, 0x69, 0x6e, 0x41, 0x70, 0x69, 0x10, - 0xaa, 0x04, 0x12, 0x0b, 0x0a, 0x06, 0x47, 0x69, 0x74, 0x74, 0x65, 0x72, 0x10, 0xab, 0x04, 0x12, - 0x09, 0x0a, 0x04, 0x48, 0x6f, 0x73, 0x74, 0x10, 0xac, 0x04, 0x12, 0x0d, 0x0a, 0x08, 0x49, 0x65, - 0x78, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x10, 0xad, 0x04, 0x12, 0x0d, 0x0a, 0x08, 0x52, 0x65, 0x73, - 0x74, 0x70, 0x61, 0x63, 0x6b, 0x10, 0xae, 0x04, 0x12, 0x0f, 0x0a, 0x0a, 0x53, 0x63, 0x72, 0x61, - 0x70, 0x65, 0x72, 0x42, 0x6f, 0x78, 0x10, 0xaf, 0x04, 0x12, 0x10, 0x0a, 0x0b, 0x53, 0x63, 0x72, - 0x61, 0x70, 0x69, 0x6e, 0x67, 0x41, 0x6e, 0x74, 0x10, 0xb0, 0x04, 0x12, 0x0e, 0x0a, 0x09, 0x53, - 0x65, 0x72, 0x70, 0x53, 0x74, 0x61, 0x63, 0x6b, 0x10, 0xb1, 0x04, 0x12, 0x12, 0x0a, 0x0d, 0x53, - 0x6d, 0x61, 0x72, 0x74, 0x79, 0x53, 0x74, 0x72, 0x65, 0x65, 0x74, 0x73, 0x10, 0xb2, 0x04, 0x12, - 0x11, 0x0a, 0x0c, 0x54, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x4d, 0x61, 0x73, 0x74, 0x65, 0x72, 0x10, - 0xb3, 0x04, 0x12, 0x12, 0x0a, 0x0d, 0x41, 0x76, 0x69, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, - 0x61, 0x63, 0x6b, 0x10, 0xb4, 0x04, 0x12, 0x0d, 0x0a, 0x08, 0x42, 0x6f, 0x6d, 0x62, 0x42, 0x6f, - 0x6d, 0x62, 0x10, 0xb5, 0x04, 0x12, 0x10, 0x0a, 0x0b, 0x43, 0x6f, 0x6d, 0x6d, 0x6f, 0x64, 0x69, - 0x74, 0x69, 0x65, 0x73, 0x10, 0xb6, 0x04, 0x12, 0x0a, 0x0a, 0x05, 0x44, 0x66, 0x75, 0x73, 0x65, - 0x10, 0xb7, 0x04, 0x12, 0x0b, 0x0a, 0x06, 0x45, 0x64, 0x65, 0x6e, 0x41, 0x49, 0x10, 0xb8, 0x04, - 0x12, 0x0e, 0x0a, 0x09, 0x47, 0x6c, 0x61, 0x73, 0x73, 0x6e, 0x6f, 0x64, 0x65, 0x10, 0xb9, 0x04, - 0x12, 0x09, 0x0a, 0x04, 0x47, 0x75, 0x72, 0x75, 0x10, 0xba, 0x04, 0x12, 0x09, 0x0a, 0x04, 0x48, - 0x69, 0x76, 0x65, 0x10, 0xbb, 0x04, 0x12, 0x0c, 0x0a, 0x07, 0x48, 0x69, 0x76, 0x65, 0x61, 0x67, - 0x65, 0x10, 0xbc, 0x04, 0x12, 0x0c, 0x0a, 0x07, 0x4b, 0x69, 0x63, 0x6b, 0x62, 0x6f, 0x78, 0x10, - 0xbd, 0x04, 0x12, 0x11, 0x0a, 0x08, 0x50, 0x61, 0x73, 0x73, 0x62, 0x61, 0x73, 0x65, 0x10, 0xbe, - 0x04, 0x1a, 0x02, 0x08, 0x01, 0x12, 0x0f, 0x0a, 0x0a, 0x50, 0x6f, 0x73, 0x74, 0x61, 0x67, 0x65, - 0x41, 0x70, 0x70, 0x10, 0xbf, 0x04, 0x12, 0x0e, 0x0a, 0x09, 0x50, 0x75, 0x72, 0x65, 0x53, 0x74, - 0x61, 0x6b, 0x65, 0x10, 0xc0, 0x04, 0x12, 0x0b, 0x0a, 0x06, 0x51, 0x75, 0x62, 0x6f, 0x6c, 0x65, - 0x10, 0xc1, 0x04, 0x12, 0x14, 0x0a, 0x0f, 0x43, 0x61, 0x72, 0x62, 0x6f, 0x6e, 0x49, 0x6e, 0x74, - 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, 0x10, 0xc2, 0x04, 0x12, 0x0d, 0x0a, 0x08, 0x49, 0x6e, 0x74, - 0x72, 0x69, 0x6e, 0x69, 0x6f, 0x10, 0xc3, 0x04, 0x12, 0x15, 0x0a, 0x0c, 0x51, 0x75, 0x69, 0x63, - 0x6b, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x10, 0xc4, 0x04, 0x1a, 0x02, 0x08, 0x01, 0x12, - 0x10, 0x0a, 0x0b, 0x53, 0x63, 0x72, 0x61, 0x70, 0x65, 0x53, 0x74, 0x61, 0x63, 0x6b, 0x10, 0xc5, - 0x04, 0x12, 0x19, 0x0a, 0x14, 0x54, 0x65, 0x63, 0x68, 0x6e, 0x69, 0x63, 0x61, 0x6c, 0x41, 0x6e, - 0x61, 0x6c, 0x79, 0x73, 0x69, 0x73, 0x41, 0x70, 0x69, 0x10, 0xc6, 0x04, 0x12, 0x0c, 0x0a, 0x07, - 0x55, 0x72, 0x6c, 0x73, 0x63, 0x61, 0x6e, 0x10, 0xc7, 0x04, 0x12, 0x0e, 0x0a, 0x09, 0x42, 0x61, - 0x73, 0x65, 0x41, 0x70, 0x69, 0x49, 0x4f, 0x10, 0xc8, 0x04, 0x12, 0x0c, 0x0a, 0x07, 0x44, 0x61, - 0x69, 0x6c, 0x79, 0x43, 0x4f, 0x10, 0xc9, 0x04, 0x12, 0x08, 0x0a, 0x03, 0x54, 0x4c, 0x79, 0x10, - 0xca, 0x04, 0x12, 0x0d, 0x0a, 0x08, 0x53, 0x68, 0x6f, 0x72, 0x74, 0x63, 0x75, 0x74, 0x10, 0xcb, - 0x04, 0x12, 0x0e, 0x0a, 0x09, 0x41, 0x70, 0x70, 0x66, 0x6f, 0x6c, 0x6c, 0x6f, 0x77, 0x10, 0xcc, - 0x04, 0x12, 0x0e, 0x0a, 0x09, 0x54, 0x68, 0x69, 0x6e, 0x6b, 0x69, 0x66, 0x69, 0x63, 0x10, 0xcd, - 0x04, 0x12, 0x0b, 0x0a, 0x06, 0x46, 0x65, 0x65, 0x64, 0x6c, 0x79, 0x10, 0xce, 0x04, 0x12, 0x0f, - 0x0a, 0x0a, 0x53, 0x74, 0x69, 0x74, 0x63, 0x68, 0x64, 0x61, 0x74, 0x61, 0x10, 0xcf, 0x04, 0x12, - 0x0d, 0x0a, 0x08, 0x46, 0x65, 0x74, 0x63, 0x68, 0x72, 0x73, 0x73, 0x10, 0xd0, 0x04, 0x12, 0x11, - 0x0a, 0x0c, 0x53, 0x69, 0x67, 0x6e, 0x75, 0x70, 0x67, 0x65, 0x6e, 0x69, 0x75, 0x73, 0x10, 0xd1, - 0x04, 0x12, 0x0f, 0x0a, 0x0a, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x69, 0x74, 0x10, - 0xd2, 0x04, 0x12, 0x0f, 0x0a, 0x0a, 0x4f, 0x70, 0x74, 0x69, 0x6d, 0x69, 0x7a, 0x65, 0x6c, 0x79, - 0x10, 0xd3, 0x04, 0x12, 0x0d, 0x0a, 0x08, 0x4f, 0x63, 0x72, 0x53, 0x70, 0x61, 0x63, 0x65, 0x10, - 0xd4, 0x04, 0x12, 0x0f, 0x0a, 0x0a, 0x57, 0x65, 0x61, 0x74, 0x68, 0x65, 0x72, 0x42, 0x69, 0x74, - 0x10, 0xd5, 0x04, 0x12, 0x0c, 0x0a, 0x07, 0x42, 0x75, 0x64, 0x64, 0x79, 0x4e, 0x53, 0x10, 0xd6, - 0x04, 0x12, 0x0b, 0x0a, 0x06, 0x5a, 0x69, 0x70, 0x41, 0x50, 0x49, 0x10, 0xd7, 0x04, 0x12, 0x0d, - 0x0a, 0x08, 0x5a, 0x69, 0x70, 0x42, 0x6f, 0x6f, 0x6b, 0x73, 0x10, 0xd8, 0x04, 0x12, 0x0c, 0x0a, - 0x07, 0x4f, 0x6e, 0x65, 0x64, 0x65, 0x73, 0x6b, 0x10, 0xd9, 0x04, 0x12, 0x0c, 0x0a, 0x07, 0x42, - 0x75, 0x67, 0x68, 0x65, 0x72, 0x64, 0x10, 0xda, 0x04, 0x12, 0x0f, 0x0a, 0x0a, 0x42, 0x6c, 0x61, - 0x7a, 0x65, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x10, 0xdb, 0x04, 0x12, 0x0d, 0x0a, 0x08, 0x41, 0x75, - 0x74, 0x6f, 0x64, 0x65, 0x73, 0x6b, 0x10, 0xdc, 0x04, 0x12, 0x08, 0x0a, 0x03, 0x54, 0x72, 0x75, - 0x10, 0xdd, 0x04, 0x12, 0x0c, 0x0a, 0x07, 0x55, 0x6e, 0x69, 0x66, 0x79, 0x49, 0x44, 0x10, 0xde, - 0x04, 0x12, 0x0c, 0x0a, 0x07, 0x54, 0x72, 0x69, 0x6d, 0x62, 0x6c, 0x65, 0x10, 0xdf, 0x04, 0x12, - 0x0b, 0x0a, 0x06, 0x53, 0x6d, 0x6f, 0x6f, 0x63, 0x68, 0x10, 0xe0, 0x04, 0x12, 0x0e, 0x0a, 0x09, - 0x53, 0x65, 0x6d, 0x61, 0x70, 0x68, 0x6f, 0x72, 0x65, 0x10, 0xe1, 0x04, 0x12, 0x0b, 0x0a, 0x06, - 0x54, 0x65, 0x6c, 0x6e, 0x79, 0x78, 0x10, 0xe2, 0x04, 0x12, 0x0f, 0x0a, 0x0a, 0x53, 0x69, 0x67, - 0x6e, 0x61, 0x6c, 0x77, 0x69, 0x72, 0x65, 0x10, 0xe3, 0x04, 0x12, 0x0e, 0x0a, 0x09, 0x54, 0x65, - 0x78, 0x74, 0x6d, 0x61, 0x67, 0x69, 0x63, 0x10, 0xe4, 0x04, 0x12, 0x0e, 0x0a, 0x09, 0x53, 0x65, - 0x72, 0x70, 0x68, 0x6f, 0x75, 0x73, 0x65, 0x10, 0xe5, 0x04, 0x12, 0x0b, 0x0a, 0x06, 0x50, 0x6c, - 0x61, 0x6e, 0x79, 0x6f, 0x10, 0xe6, 0x04, 0x12, 0x0f, 0x0a, 0x0a, 0x53, 0x69, 0x6d, 0x70, 0x6c, - 0x79, 0x62, 0x6f, 0x6f, 0x6b, 0x10, 0xe7, 0x04, 0x12, 0x09, 0x0a, 0x04, 0x56, 0x79, 0x74, 0x65, - 0x10, 0xe8, 0x04, 0x12, 0x0a, 0x0a, 0x05, 0x4e, 0x79, 0x6c, 0x61, 0x73, 0x10, 0xe9, 0x04, 0x12, - 0x0d, 0x0a, 0x08, 0x53, 0x71, 0x75, 0x61, 0x72, 0x65, 0x75, 0x70, 0x10, 0xea, 0x04, 0x12, 0x0e, - 0x0a, 0x09, 0x44, 0x61, 0x6e, 0x64, 0x65, 0x6c, 0x69, 0x6f, 0x6e, 0x10, 0xeb, 0x04, 0x12, 0x11, - 0x0a, 0x08, 0x44, 0x61, 0x74, 0x61, 0x46, 0x69, 0x72, 0x65, 0x10, 0xec, 0x04, 0x1a, 0x02, 0x08, - 0x01, 0x12, 0x0b, 0x0a, 0x06, 0x44, 0x65, 0x65, 0x70, 0x41, 0x49, 0x10, 0xed, 0x04, 0x12, 0x11, - 0x0a, 0x0c, 0x4d, 0x65, 0x61, 0x6e, 0x69, 0x6e, 0x67, 0x43, 0x6c, 0x6f, 0x75, 0x64, 0x10, 0xee, - 0x04, 0x12, 0x10, 0x0a, 0x0b, 0x4e, 0x65, 0x75, 0x74, 0x72, 0x69, 0x6e, 0x6f, 0x41, 0x70, 0x69, - 0x10, 0xef, 0x04, 0x12, 0x0e, 0x0a, 0x09, 0x53, 0x74, 0x6f, 0x72, 0x65, 0x63, 0x6f, 0x76, 0x65, - 0x10, 0xf0, 0x04, 0x12, 0x0c, 0x0a, 0x07, 0x53, 0x68, 0x69, 0x70, 0x64, 0x61, 0x79, 0x10, 0xf1, - 0x04, 0x12, 0x12, 0x0a, 0x09, 0x53, 0x65, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x6e, 0x74, 0x10, 0xf2, - 0x04, 0x1a, 0x02, 0x08, 0x01, 0x12, 0x18, 0x0a, 0x13, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x43, - 0x68, 0x61, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x69, 0x6e, 0x67, 0x10, 0xf3, 0x04, 0x12, - 0x10, 0x0a, 0x0b, 0x54, 0x65, 0x61, 0x6d, 0x77, 0x6f, 0x72, 0x6b, 0x43, 0x52, 0x4d, 0x10, 0xf4, - 0x04, 0x12, 0x11, 0x0a, 0x0c, 0x54, 0x65, 0x61, 0x6d, 0x77, 0x6f, 0x72, 0x6b, 0x44, 0x65, 0x73, - 0x6b, 0x10, 0xf5, 0x04, 0x12, 0x13, 0x0a, 0x0e, 0x54, 0x65, 0x61, 0x6d, 0x77, 0x6f, 0x72, 0x6b, - 0x53, 0x70, 0x61, 0x63, 0x65, 0x73, 0x10, 0xf6, 0x04, 0x12, 0x0f, 0x0a, 0x0a, 0x54, 0x68, 0x65, - 0x4f, 0x64, 0x64, 0x73, 0x41, 0x70, 0x69, 0x10, 0xf7, 0x04, 0x12, 0x0b, 0x0a, 0x06, 0x41, 0x70, - 0x61, 0x63, 0x74, 0x61, 0x10, 0xf8, 0x04, 0x12, 0x0f, 0x0a, 0x0a, 0x47, 0x65, 0x74, 0x53, 0x61, - 0x6e, 0x64, 0x62, 0x6f, 0x78, 0x10, 0xf9, 0x04, 0x12, 0x0e, 0x0a, 0x05, 0x48, 0x61, 0x70, 0x70, - 0x69, 0x10, 0xfa, 0x04, 0x1a, 0x02, 0x08, 0x01, 0x12, 0x0a, 0x0a, 0x05, 0x4f, 0x61, 0x6e, 0x64, - 0x61, 0x10, 0xfb, 0x04, 0x12, 0x0e, 0x0a, 0x09, 0x46, 0x61, 0x73, 0x74, 0x46, 0x6f, 0x72, 0x65, - 0x78, 0x10, 0xfc, 0x04, 0x12, 0x0d, 0x0a, 0x08, 0x41, 0x50, 0x49, 0x4d, 0x61, 0x74, 0x69, 0x63, - 0x10, 0xfd, 0x04, 0x12, 0x0f, 0x0a, 0x0a, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x45, 0x79, - 0x65, 0x10, 0xfe, 0x04, 0x12, 0x15, 0x0a, 0x10, 0x45, 0x61, 0x67, 0x6c, 0x65, 0x45, 0x79, 0x65, - 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x10, 0xff, 0x04, 0x12, 0x11, 0x0a, 0x0c, 0x54, - 0x68, 0x6f, 0x75, 0x73, 0x61, 0x6e, 0x64, 0x45, 0x79, 0x65, 0x73, 0x10, 0x80, 0x05, 0x12, 0x0e, - 0x0a, 0x09, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x50, 0x44, 0x46, 0x10, 0x81, 0x05, 0x12, 0x10, - 0x0a, 0x0b, 0x46, 0x6c, 0x69, 0x67, 0x68, 0x74, 0x73, 0x74, 0x61, 0x74, 0x73, 0x10, 0x82, 0x05, - 0x12, 0x0b, 0x0a, 0x06, 0x43, 0x68, 0x65, 0x63, 0x49, 0x4f, 0x10, 0x83, 0x05, 0x12, 0x0d, 0x0a, - 0x08, 0x4d, 0x61, 0x6e, 0x69, 0x66, 0x65, 0x73, 0x74, 0x10, 0x84, 0x05, 0x12, 0x0f, 0x0a, 0x0a, - 0x41, 0x70, 0x69, 0x53, 0x63, 0x69, 0x65, 0x6e, 0x63, 0x65, 0x10, 0x85, 0x05, 0x12, 0x0f, 0x0a, - 0x0a, 0x41, 0x70, 0x70, 0x53, 0x79, 0x6e, 0x65, 0x72, 0x67, 0x79, 0x10, 0x86, 0x05, 0x12, 0x0b, - 0x0a, 0x06, 0x43, 0x61, 0x66, 0x6c, 0x6f, 0x75, 0x10, 0x87, 0x05, 0x12, 0x0b, 0x0a, 0x06, 0x43, - 0x61, 0x73, 0x70, 0x69, 0x6f, 0x10, 0x88, 0x05, 0x12, 0x0e, 0x0a, 0x09, 0x43, 0x68, 0x65, 0x63, - 0x6b, 0x6c, 0x79, 0x48, 0x51, 0x10, 0x89, 0x05, 0x12, 0x12, 0x0a, 0x0d, 0x43, 0x6c, 0x6f, 0x75, - 0x64, 0x45, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x10, 0x8a, 0x05, 0x12, 0x0c, 0x0a, 0x07, - 0x44, 0x72, 0x6f, 0x6e, 0x61, 0x48, 0x51, 0x10, 0x8b, 0x05, 0x12, 0x0c, 0x0a, 0x07, 0x45, 0x6e, - 0x61, 0x62, 0x6c, 0x65, 0x78, 0x10, 0x8c, 0x05, 0x12, 0x09, 0x0a, 0x04, 0x46, 0x6d, 0x66, 0x77, - 0x10, 0x8d, 0x05, 0x12, 0x0c, 0x0a, 0x07, 0x47, 0x6f, 0x6f, 0x64, 0x44, 0x61, 0x79, 0x10, 0x8e, - 0x05, 0x12, 0x09, 0x0a, 0x04, 0x4c, 0x75, 0x6e, 0x6f, 0x10, 0x8f, 0x05, 0x12, 0x10, 0x0a, 0x0b, - 0x4d, 0x65, 0x69, 0x73, 0x74, 0x65, 0x72, 0x74, 0x61, 0x73, 0x6b, 0x10, 0x90, 0x05, 0x12, 0x10, - 0x0a, 0x0b, 0x4d, 0x69, 0x6e, 0x64, 0x6d, 0x65, 0x69, 0x73, 0x74, 0x65, 0x72, 0x10, 0x91, 0x05, - 0x12, 0x13, 0x0a, 0x0e, 0x50, 0x65, 0x6f, 0x70, 0x6c, 0x65, 0x44, 0x61, 0x74, 0x61, 0x4c, 0x61, - 0x62, 0x73, 0x10, 0x92, 0x05, 0x12, 0x14, 0x0a, 0x0b, 0x53, 0x63, 0x72, 0x61, 0x70, 0x65, 0x72, - 0x53, 0x69, 0x74, 0x65, 0x10, 0x93, 0x05, 0x1a, 0x02, 0x08, 0x01, 0x12, 0x0d, 0x0a, 0x08, 0x53, - 0x63, 0x72, 0x61, 0x70, 0x66, 0x6c, 0x79, 0x10, 0x94, 0x05, 0x12, 0x10, 0x0a, 0x0b, 0x53, 0x69, - 0x6d, 0x70, 0x6c, 0x79, 0x4e, 0x6f, 0x74, 0x65, 0x64, 0x10, 0x95, 0x05, 0x12, 0x12, 0x0a, 0x0d, - 0x54, 0x72, 0x61, 0x76, 0x65, 0x6c, 0x50, 0x61, 0x79, 0x6f, 0x75, 0x74, 0x73, 0x10, 0x96, 0x05, - 0x12, 0x0f, 0x0a, 0x0a, 0x57, 0x65, 0x62, 0x53, 0x63, 0x72, 0x61, 0x70, 0x65, 0x72, 0x10, 0x97, - 0x05, 0x12, 0x0c, 0x0a, 0x07, 0x43, 0x6f, 0x6e, 0x76, 0x69, 0x65, 0x72, 0x10, 0x98, 0x05, 0x12, - 0x0c, 0x0a, 0x07, 0x43, 0x6f, 0x75, 0x72, 0x69, 0x65, 0x72, 0x10, 0x99, 0x05, 0x12, 0x0a, 0x0a, - 0x05, 0x44, 0x69, 0x74, 0x74, 0x6f, 0x10, 0x9a, 0x05, 0x12, 0x0a, 0x0a, 0x05, 0x46, 0x69, 0x6e, - 0x64, 0x6c, 0x10, 0x9b, 0x05, 0x12, 0x0d, 0x0a, 0x08, 0x4c, 0x65, 0x6e, 0x64, 0x66, 0x6c, 0x6f, - 0x77, 0x10, 0x9c, 0x05, 0x12, 0x0f, 0x0a, 0x0a, 0x4d, 0x6f, 0x64, 0x65, 0x72, 0x61, 0x74, 0x69, - 0x6f, 0x6e, 0x10, 0x9d, 0x05, 0x12, 0x11, 0x0a, 0x0c, 0x4f, 0x70, 0x65, 0x6e, 0x64, 0x61, 0x74, - 0x61, 0x73, 0x6f, 0x66, 0x74, 0x10, 0x9e, 0x05, 0x12, 0x0a, 0x0a, 0x05, 0x50, 0x6f, 0x64, 0x69, - 0x6f, 0x10, 0x9f, 0x05, 0x12, 0x0c, 0x0a, 0x07, 0x52, 0x6f, 0x63, 0x6b, 0x73, 0x65, 0x74, 0x10, - 0xa0, 0x05, 0x12, 0x0a, 0x0a, 0x05, 0x52, 0x6f, 0x77, 0x6e, 0x64, 0x10, 0xa1, 0x05, 0x12, 0x0e, - 0x0a, 0x09, 0x53, 0x68, 0x6f, 0x74, 0x73, 0x74, 0x61, 0x63, 0x6b, 0x10, 0xa2, 0x05, 0x12, 0x0d, - 0x0a, 0x08, 0x53, 0x77, 0x69, 0x66, 0x74, 0x79, 0x70, 0x65, 0x10, 0xa3, 0x05, 0x12, 0x0c, 0x0a, - 0x07, 0x54, 0x77, 0x69, 0x74, 0x74, 0x65, 0x72, 0x10, 0xa4, 0x05, 0x12, 0x0a, 0x0a, 0x05, 0x48, - 0x6f, 0x6e, 0x65, 0x79, 0x10, 0xa5, 0x05, 0x12, 0x0e, 0x0a, 0x09, 0x46, 0x72, 0x65, 0x73, 0x68, - 0x64, 0x65, 0x73, 0x6b, 0x10, 0xa6, 0x05, 0x12, 0x0b, 0x0a, 0x06, 0x55, 0x70, 0x77, 0x61, 0x76, - 0x65, 0x10, 0xa7, 0x05, 0x12, 0x0d, 0x0a, 0x08, 0x46, 0x6f, 0x75, 0x6e, 0x74, 0x61, 0x69, 0x6e, - 0x10, 0xa8, 0x05, 0x12, 0x0f, 0x0a, 0x0a, 0x46, 0x72, 0x65, 0x73, 0x68, 0x62, 0x6f, 0x6f, 0x6b, - 0x73, 0x10, 0xa9, 0x05, 0x12, 0x09, 0x0a, 0x04, 0x4d, 0x69, 0x74, 0x65, 0x10, 0xaa, 0x05, 0x12, - 0x0b, 0x0a, 0x06, 0x44, 0x65, 0x70, 0x75, 0x74, 0x79, 0x10, 0xab, 0x05, 0x12, 0x0c, 0x0a, 0x07, - 0x42, 0x65, 0x65, 0x62, 0x6f, 0x6c, 0x65, 0x10, 0xac, 0x05, 0x12, 0x0e, 0x0a, 0x09, 0x43, 0x61, - 0x73, 0x68, 0x62, 0x6f, 0x61, 0x72, 0x64, 0x10, 0xad, 0x05, 0x12, 0x0b, 0x0a, 0x06, 0x4b, 0x61, - 0x6e, 0x62, 0x61, 0x6e, 0x10, 0xae, 0x05, 0x12, 0x0e, 0x0a, 0x09, 0x57, 0x6f, 0x72, 0x6b, 0x73, - 0x6e, 0x61, 0x70, 0x73, 0x10, 0xaf, 0x05, 0x12, 0x10, 0x0a, 0x0b, 0x4d, 0x79, 0x49, 0x6e, 0x74, - 0x65, 0x72, 0x76, 0x61, 0x6c, 0x73, 0x10, 0xb0, 0x05, 0x12, 0x11, 0x0a, 0x0c, 0x49, 0x6e, 0x76, - 0x6f, 0x69, 0x63, 0x65, 0x4f, 0x63, 0x65, 0x61, 0x6e, 0x10, 0xb1, 0x05, 0x12, 0x0f, 0x0a, 0x0a, - 0x53, 0x68, 0x65, 0x72, 0x70, 0x61, 0x64, 0x65, 0x73, 0x6b, 0x10, 0xb2, 0x05, 0x12, 0x0f, 0x0a, - 0x0a, 0x4d, 0x72, 0x74, 0x69, 0x63, 0x6b, 0x74, 0x6f, 0x63, 0x6b, 0x10, 0xb3, 0x05, 0x12, 0x0d, - 0x0a, 0x08, 0x43, 0x68, 0x61, 0x74, 0x66, 0x75, 0x6c, 0x65, 0x10, 0xb4, 0x05, 0x12, 0x11, 0x0a, - 0x0c, 0x41, 0x65, 0x72, 0x6f, 0x77, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x10, 0xb5, 0x05, - 0x12, 0x11, 0x0a, 0x0c, 0x45, 0x6d, 0x61, 0x69, 0x6c, 0x6f, 0x63, 0x74, 0x6f, 0x70, 0x75, 0x73, - 0x10, 0xb6, 0x05, 0x12, 0x11, 0x0a, 0x08, 0x46, 0x75, 0x73, 0x65, 0x62, 0x69, 0x6c, 0x6c, 0x10, - 0xb7, 0x05, 0x1a, 0x02, 0x08, 0x01, 0x12, 0x0f, 0x0a, 0x0a, 0x47, 0x65, 0x63, 0x6b, 0x6f, 0x62, - 0x6f, 0x61, 0x72, 0x64, 0x10, 0xb8, 0x05, 0x12, 0x0e, 0x0a, 0x09, 0x47, 0x6f, 0x73, 0x71, 0x75, - 0x61, 0x72, 0x65, 0x64, 0x10, 0xb9, 0x05, 0x12, 0x0e, 0x0a, 0x09, 0x4d, 0x6f, 0x6f, 0x6e, 0x63, - 0x6c, 0x65, 0x72, 0x6b, 0x10, 0xba, 0x05, 0x12, 0x0d, 0x0a, 0x08, 0x50, 0x61, 0x79, 0x6d, 0x6f, - 0x61, 0x70, 0x70, 0x10, 0xbb, 0x05, 0x12, 0x0b, 0x0a, 0x06, 0x4d, 0x69, 0x78, 0x6d, 0x61, 0x78, - 0x10, 0xbc, 0x05, 0x12, 0x0e, 0x0a, 0x09, 0x50, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x73, 0x74, - 0x10, 0xbd, 0x05, 0x12, 0x10, 0x0a, 0x0b, 0x52, 0x65, 0x70, 0x61, 0x69, 0x72, 0x73, 0x68, 0x6f, - 0x70, 0x72, 0x10, 0xbe, 0x05, 0x12, 0x0d, 0x0a, 0x08, 0x47, 0x6f, 0x73, 0x68, 0x69, 0x70, 0x70, - 0x6f, 0x10, 0xbf, 0x05, 0x12, 0x0b, 0x0a, 0x06, 0x53, 0x69, 0x67, 0x6f, 0x70, 0x74, 0x10, 0xc0, - 0x05, 0x12, 0x0d, 0x0a, 0x08, 0x53, 0x75, 0x67, 0x65, 0x73, 0x74, 0x65, 0x72, 0x10, 0xc1, 0x05, - 0x12, 0x0c, 0x0a, 0x07, 0x56, 0x69, 0x65, 0x77, 0x6e, 0x65, 0x6f, 0x10, 0xc2, 0x05, 0x12, 0x0e, - 0x0a, 0x09, 0x42, 0x6f, 0x6f, 0x73, 0x74, 0x4e, 0x6f, 0x74, 0x65, 0x10, 0xc3, 0x05, 0x12, 0x10, - 0x0a, 0x0b, 0x43, 0x61, 0x70, 0x74, 0x61, 0x69, 0x6e, 0x44, 0x61, 0x74, 0x61, 0x10, 0xc4, 0x05, - 0x12, 0x0e, 0x0a, 0x09, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x76, 0x69, 0x73, 0x74, 0x10, 0xc5, 0x05, - 0x12, 0x0c, 0x0a, 0x07, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x67, 0x6f, 0x10, 0xc6, 0x05, 0x12, 0x0a, - 0x0a, 0x05, 0x43, 0x6c, 0x6f, 0x7a, 0x65, 0x10, 0xc7, 0x05, 0x12, 0x0b, 0x0a, 0x06, 0x46, 0x6f, - 0x72, 0x6d, 0x49, 0x4f, 0x10, 0xc8, 0x05, 0x12, 0x0f, 0x0a, 0x0a, 0x46, 0x6f, 0x72, 0x6d, 0x42, - 0x75, 0x63, 0x6b, 0x65, 0x74, 0x10, 0xc9, 0x05, 0x12, 0x0d, 0x0a, 0x08, 0x47, 0x6f, 0x43, 0x61, - 0x6e, 0x76, 0x61, 0x73, 0x10, 0xca, 0x05, 0x12, 0x0c, 0x0a, 0x07, 0x4d, 0x61, 0x64, 0x4b, 0x75, - 0x64, 0x75, 0x10, 0xcb, 0x05, 0x12, 0x0f, 0x0a, 0x0a, 0x4e, 0x6f, 0x7a, 0x62, 0x65, 0x54, 0x65, - 0x61, 0x6d, 0x73, 0x10, 0xcc, 0x05, 0x12, 0x0b, 0x0a, 0x06, 0x50, 0x61, 0x70, 0x79, 0x72, 0x73, - 0x10, 0xcd, 0x05, 0x12, 0x12, 0x0a, 0x0d, 0x53, 0x75, 0x70, 0x65, 0x72, 0x4e, 0x6f, 0x74, 0x65, - 0x73, 0x41, 0x50, 0x49, 0x10, 0xce, 0x05, 0x12, 0x0c, 0x0a, 0x07, 0x54, 0x61, 0x6c, 0x6c, 0x79, - 0x66, 0x79, 0x10, 0xcf, 0x05, 0x12, 0x0e, 0x0a, 0x09, 0x5a, 0x65, 0x6e, 0x6b, 0x69, 0x74, 0x41, - 0x50, 0x49, 0x10, 0xd0, 0x05, 0x12, 0x0f, 0x0a, 0x0a, 0x43, 0x6c, 0x6f, 0x75, 0x64, 0x49, 0x6d, - 0x61, 0x67, 0x65, 0x10, 0xd1, 0x05, 0x12, 0x0f, 0x0a, 0x0a, 0x55, 0x70, 0x6c, 0x6f, 0x61, 0x64, - 0x43, 0x61, 0x72, 0x65, 0x10, 0xd2, 0x05, 0x12, 0x0d, 0x0a, 0x08, 0x42, 0x6f, 0x72, 0x67, 0x62, - 0x61, 0x73, 0x65, 0x10, 0xd3, 0x05, 0x12, 0x0e, 0x0a, 0x09, 0x50, 0x69, 0x70, 0x65, 0x64, 0x72, - 0x65, 0x61, 0x6d, 0x10, 0xd4, 0x05, 0x12, 0x09, 0x0a, 0x04, 0x53, 0x69, 0x72, 0x76, 0x10, 0xd5, - 0x05, 0x12, 0x0c, 0x0a, 0x07, 0x44, 0x69, 0x66, 0x66, 0x62, 0x6f, 0x74, 0x10, 0xd6, 0x05, 0x12, - 0x10, 0x0a, 0x0b, 0x45, 0x69, 0x67, 0x68, 0x74, 0x78, 0x45, 0x69, 0x67, 0x68, 0x74, 0x10, 0xd7, - 0x05, 0x12, 0x0c, 0x0a, 0x07, 0x53, 0x65, 0x6e, 0x64, 0x6f, 0x73, 0x6f, 0x10, 0xd8, 0x05, 0x12, - 0x11, 0x0a, 0x0c, 0x50, 0x72, 0x69, 0x6e, 0x74, 0x66, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x10, - 0xd9, 0x05, 0x12, 0x0e, 0x0a, 0x09, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x10, - 0xda, 0x05, 0x12, 0x0f, 0x0a, 0x0a, 0x50, 0x61, 0x6e, 0x64, 0x61, 0x53, 0x63, 0x6f, 0x72, 0x65, - 0x10, 0xdb, 0x05, 0x12, 0x0a, 0x0a, 0x05, 0x50, 0x61, 0x79, 0x6d, 0x6f, 0x10, 0xdc, 0x05, 0x12, - 0x1d, 0x0a, 0x18, 0x41, 0x76, 0x61, 0x7a, 0x61, 0x50, 0x65, 0x72, 0x73, 0x6f, 0x6e, 0x61, 0x6c, - 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x10, 0xdd, 0x05, 0x12, 0x14, - 0x0a, 0x0f, 0x50, 0x6c, 0x61, 0x6e, 0x76, 0x69, 0x65, 0x77, 0x4c, 0x65, 0x61, 0x6e, 0x4b, 0x69, - 0x74, 0x10, 0xde, 0x05, 0x12, 0x0e, 0x0a, 0x09, 0x4c, 0x69, 0x76, 0x65, 0x73, 0x74, 0x6f, 0x72, - 0x6d, 0x10, 0xdf, 0x05, 0x12, 0x0b, 0x0a, 0x06, 0x4b, 0x75, 0x43, 0x6f, 0x69, 0x6e, 0x10, 0xe0, - 0x05, 0x12, 0x0c, 0x0a, 0x07, 0x4d, 0x65, 0x74, 0x61, 0x41, 0x50, 0x49, 0x10, 0xe1, 0x05, 0x12, - 0x0d, 0x0a, 0x08, 0x4e, 0x69, 0x63, 0x65, 0x48, 0x61, 0x73, 0x68, 0x10, 0xe2, 0x05, 0x12, 0x0a, - 0x0a, 0x05, 0x43, 0x65, 0x78, 0x49, 0x4f, 0x10, 0xe3, 0x05, 0x12, 0x0e, 0x0a, 0x09, 0x4b, 0x6c, - 0x69, 0x70, 0x66, 0x6f, 0x6c, 0x69, 0x6f, 0x10, 0xe4, 0x05, 0x12, 0x0e, 0x0a, 0x09, 0x44, 0x79, - 0x6e, 0x61, 0x74, 0x72, 0x61, 0x63, 0x65, 0x10, 0xe5, 0x05, 0x12, 0x11, 0x0a, 0x0c, 0x4d, 0x6f, - 0x6c, 0x6c, 0x69, 0x65, 0x41, 0x50, 0x49, 0x4b, 0x65, 0x79, 0x10, 0xe6, 0x05, 0x12, 0x16, 0x0a, - 0x11, 0x4d, 0x6f, 0x6c, 0x6c, 0x69, 0x65, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x54, 0x6f, 0x6b, - 0x65, 0x6e, 0x10, 0xe7, 0x05, 0x12, 0x10, 0x0a, 0x0b, 0x42, 0x61, 0x73, 0x69, 0x73, 0x54, 0x68, - 0x65, 0x6f, 0x72, 0x79, 0x10, 0xe8, 0x05, 0x12, 0x0d, 0x0a, 0x08, 0x4e, 0x6f, 0x72, 0x64, 0x69, - 0x67, 0x65, 0x6e, 0x10, 0xe9, 0x05, 0x12, 0x1c, 0x0a, 0x17, 0x46, 0x6c, 0x61, 0x67, 0x73, 0x6d, - 0x69, 0x74, 0x68, 0x45, 0x6e, 0x76, 0x69, 0x72, 0x6f, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x4b, 0x65, - 0x79, 0x10, 0xea, 0x05, 0x12, 0x13, 0x0a, 0x0e, 0x46, 0x6c, 0x61, 0x67, 0x73, 0x6d, 0x69, 0x74, - 0x68, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x10, 0xeb, 0x05, 0x12, 0x08, 0x0a, 0x03, 0x4d, 0x75, 0x78, - 0x10, 0xec, 0x05, 0x12, 0x0b, 0x0a, 0x06, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x10, 0xed, 0x05, - 0x12, 0x0d, 0x0a, 0x08, 0x53, 0x65, 0x6e, 0x64, 0x62, 0x69, 0x72, 0x64, 0x10, 0xee, 0x05, 0x12, - 0x1c, 0x0a, 0x17, 0x53, 0x65, 0x6e, 0x64, 0x62, 0x69, 0x72, 0x64, 0x4f, 0x72, 0x67, 0x61, 0x6e, - 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x41, 0x50, 0x49, 0x10, 0xef, 0x05, 0x12, 0x0b, 0x0a, - 0x06, 0x4d, 0x69, 0x64, 0x69, 0x73, 0x65, 0x10, 0xf0, 0x05, 0x12, 0x0d, 0x0a, 0x08, 0x4d, 0x6f, - 0x63, 0x6b, 0x61, 0x72, 0x6f, 0x6f, 0x10, 0xf1, 0x05, 0x12, 0x0b, 0x0a, 0x06, 0x49, 0x6d, 0x61, - 0x67, 0x65, 0x34, 0x10, 0xf2, 0x05, 0x12, 0x0b, 0x0a, 0x06, 0x50, 0x69, 0x6e, 0x61, 0x74, 0x61, - 0x10, 0xf3, 0x05, 0x12, 0x11, 0x0a, 0x0c, 0x42, 0x72, 0x6f, 0x77, 0x73, 0x65, 0x72, 0x53, 0x74, - 0x61, 0x63, 0x6b, 0x10, 0xf4, 0x05, 0x12, 0x1c, 0x0a, 0x13, 0x43, 0x72, 0x6f, 0x73, 0x73, 0x42, - 0x72, 0x6f, 0x77, 0x73, 0x65, 0x72, 0x54, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x10, 0xf5, 0x05, - 0x1a, 0x02, 0x08, 0x01, 0x12, 0x0d, 0x0a, 0x08, 0x4c, 0x6f, 0x61, 0x64, 0x6d, 0x69, 0x6c, 0x6c, - 0x10, 0xf6, 0x05, 0x12, 0x0f, 0x0a, 0x0a, 0x54, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x42, 0x6f, - 0x74, 0x10, 0xf7, 0x05, 0x12, 0x10, 0x0a, 0x0b, 0x4b, 0x6e, 0x61, 0x70, 0x73, 0x61, 0x63, 0x6b, - 0x50, 0x72, 0x6f, 0x10, 0xf8, 0x05, 0x12, 0x09, 0x0a, 0x04, 0x51, 0x61, 0x73, 0x65, 0x10, 0xf9, - 0x05, 0x12, 0x0e, 0x0a, 0x09, 0x44, 0x61, 0x72, 0x65, 0x62, 0x6f, 0x6f, 0x73, 0x74, 0x10, 0xfa, - 0x05, 0x12, 0x0d, 0x0a, 0x08, 0x47, 0x54, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x78, 0x10, 0xfb, 0x05, - 0x12, 0x0d, 0x0a, 0x08, 0x48, 0x6f, 0x6c, 0x69, 0x73, 0x74, 0x69, 0x63, 0x10, 0xfc, 0x05, 0x12, - 0x0c, 0x0a, 0x07, 0x50, 0x61, 0x72, 0x73, 0x65, 0x72, 0x73, 0x10, 0xfd, 0x05, 0x12, 0x12, 0x0a, - 0x0d, 0x53, 0x63, 0x72, 0x75, 0x74, 0x69, 0x6e, 0x69, 0x7a, 0x65, 0x72, 0x43, 0x69, 0x10, 0xfe, - 0x05, 0x12, 0x0f, 0x0a, 0x0a, 0x53, 0x6f, 0x6e, 0x61, 0x72, 0x43, 0x6c, 0x6f, 0x75, 0x64, 0x10, - 0xff, 0x05, 0x12, 0x10, 0x0a, 0x0b, 0x41, 0x50, 0x49, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, - 0x65, 0x10, 0x80, 0x06, 0x12, 0x14, 0x0a, 0x0f, 0x43, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x73, 0x69, - 0x6f, 0x6e, 0x54, 0x6f, 0x6f, 0x6c, 0x73, 0x10, 0x81, 0x06, 0x12, 0x0f, 0x0a, 0x0a, 0x43, 0x72, - 0x61, 0x66, 0x74, 0x4d, 0x79, 0x50, 0x44, 0x46, 0x10, 0x82, 0x06, 0x12, 0x0e, 0x0a, 0x09, 0x45, - 0x78, 0x70, 0x6f, 0x72, 0x74, 0x53, 0x44, 0x4b, 0x10, 0x83, 0x06, 0x12, 0x15, 0x0a, 0x0c, 0x47, - 0x6c, 0x69, 0x74, 0x74, 0x65, 0x72, 0x6c, 0x79, 0x41, 0x50, 0x49, 0x10, 0x84, 0x06, 0x1a, 0x02, - 0x08, 0x01, 0x12, 0x0d, 0x0a, 0x08, 0x48, 0x79, 0x62, 0x69, 0x73, 0x63, 0x75, 0x73, 0x10, 0x85, - 0x06, 0x12, 0x09, 0x0a, 0x04, 0x4d, 0x69, 0x72, 0x6f, 0x10, 0x86, 0x06, 0x12, 0x0f, 0x0a, 0x0a, - 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x70, 0x61, 0x67, 0x65, 0x10, 0x87, 0x06, 0x12, 0x0e, 0x0a, - 0x09, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x70, 0x61, 0x6c, 0x10, 0x88, 0x06, 0x12, 0x0d, 0x0a, - 0x08, 0x54, 0x65, 0x6c, 0x65, 0x74, 0x79, 0x70, 0x65, 0x10, 0x89, 0x06, 0x12, 0x0d, 0x0a, 0x08, - 0x54, 0x69, 0x6d, 0x65, 0x43, 0x61, 0x6d, 0x70, 0x10, 0x8a, 0x06, 0x12, 0x0d, 0x0a, 0x08, 0x55, - 0x73, 0x65, 0x72, 0x66, 0x6c, 0x6f, 0x77, 0x10, 0x8b, 0x06, 0x12, 0x0b, 0x0a, 0x06, 0x57, 0x69, - 0x73, 0x74, 0x69, 0x61, 0x10, 0x8c, 0x06, 0x12, 0x13, 0x0a, 0x0a, 0x53, 0x70, 0x6f, 0x72, 0x74, - 0x52, 0x61, 0x64, 0x61, 0x72, 0x10, 0x8d, 0x06, 0x1a, 0x02, 0x08, 0x01, 0x12, 0x10, 0x0a, 0x0b, - 0x55, 0x70, 0x74, 0x69, 0x6d, 0x65, 0x52, 0x6f, 0x62, 0x6f, 0x74, 0x10, 0x8e, 0x06, 0x12, 0x0e, - 0x0a, 0x09, 0x43, 0x6f, 0x64, 0x65, 0x71, 0x75, 0x69, 0x72, 0x79, 0x10, 0x8f, 0x06, 0x12, 0x11, - 0x0a, 0x0c, 0x45, 0x78, 0x74, 0x72, 0x61, 0x63, 0x74, 0x6f, 0x72, 0x41, 0x50, 0x49, 0x10, 0x90, - 0x06, 0x12, 0x0d, 0x0a, 0x08, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x10, 0x91, 0x06, - 0x12, 0x0e, 0x0a, 0x09, 0x4d, 0x61, 0x67, 0x69, 0x63, 0x42, 0x65, 0x6c, 0x6c, 0x10, 0x92, 0x06, - 0x12, 0x0f, 0x0a, 0x0a, 0x53, 0x74, 0x6f, 0x72, 0x6d, 0x62, 0x6f, 0x61, 0x72, 0x64, 0x10, 0x93, - 0x06, 0x12, 0x0d, 0x0a, 0x08, 0x41, 0x70, 0x69, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x10, 0x94, 0x06, - 0x12, 0x0b, 0x0a, 0x06, 0x44, 0x69, 0x73, 0x71, 0x75, 0x73, 0x10, 0x95, 0x06, 0x12, 0x0b, 0x0a, - 0x06, 0x57, 0x6f, 0x6f, 0x70, 0x72, 0x61, 0x10, 0x96, 0x06, 0x12, 0x0e, 0x0a, 0x09, 0x50, 0x61, - 0x70, 0x65, 0x72, 0x66, 0x6f, 0x72, 0x6d, 0x10, 0x97, 0x06, 0x12, 0x0c, 0x0a, 0x07, 0x47, 0x75, - 0x6d, 0x72, 0x6f, 0x61, 0x64, 0x10, 0x98, 0x06, 0x12, 0x0f, 0x0a, 0x0a, 0x50, 0x61, 0x79, 0x64, - 0x69, 0x72, 0x74, 0x61, 0x70, 0x70, 0x10, 0x99, 0x06, 0x12, 0x0e, 0x0a, 0x09, 0x44, 0x65, 0x74, - 0x65, 0x63, 0x74, 0x69, 0x66, 0x79, 0x10, 0x9a, 0x06, 0x12, 0x0f, 0x0a, 0x0a, 0x53, 0x74, 0x61, - 0x74, 0x75, 0x73, 0x63, 0x61, 0x6b, 0x65, 0x10, 0x9b, 0x06, 0x12, 0x0f, 0x0a, 0x0a, 0x4a, 0x75, - 0x6d, 0x70, 0x73, 0x65, 0x6c, 0x6c, 0x65, 0x72, 0x10, 0x9c, 0x06, 0x12, 0x0f, 0x0a, 0x0a, 0x4c, - 0x75, 0x6e, 0x63, 0x68, 0x4d, 0x6f, 0x6e, 0x65, 0x79, 0x10, 0x9d, 0x06, 0x12, 0x0c, 0x0a, 0x07, - 0x52, 0x6f, 0x73, 0x65, 0x74, 0x74, 0x65, 0x10, 0x9e, 0x06, 0x12, 0x09, 0x0a, 0x04, 0x59, 0x65, - 0x6c, 0x70, 0x10, 0x9f, 0x06, 0x12, 0x0a, 0x0a, 0x05, 0x41, 0x74, 0x65, 0x72, 0x61, 0x10, 0xa0, - 0x06, 0x12, 0x12, 0x0a, 0x0d, 0x45, 0x63, 0x6f, 0x53, 0x74, 0x72, 0x75, 0x78, 0x75, 0x72, 0x65, - 0x49, 0x54, 0x10, 0xa1, 0x06, 0x12, 0x08, 0x0a, 0x03, 0x41, 0x68, 0x61, 0x10, 0xa2, 0x06, 0x12, - 0x0d, 0x0a, 0x08, 0x50, 0x61, 0x72, 0x73, 0x65, 0x68, 0x75, 0x62, 0x10, 0xa3, 0x06, 0x12, 0x11, - 0x0a, 0x0c, 0x50, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x43, 0x6c, 0x6f, 0x75, 0x64, 0x10, 0xa4, - 0x06, 0x12, 0x0f, 0x0a, 0x0a, 0x43, 0x6c, 0x6f, 0x75, 0x64, 0x73, 0x6d, 0x69, 0x74, 0x68, 0x10, - 0xa5, 0x06, 0x12, 0x11, 0x0a, 0x08, 0x46, 0x6c, 0x6f, 0x77, 0x64, 0x61, 0x73, 0x68, 0x10, 0xa6, - 0x06, 0x1a, 0x02, 0x08, 0x01, 0x12, 0x11, 0x0a, 0x08, 0x46, 0x6c, 0x6f, 0x77, 0x64, 0x6f, 0x63, - 0x6b, 0x10, 0xa7, 0x06, 0x1a, 0x02, 0x08, 0x01, 0x12, 0x0b, 0x0a, 0x06, 0x46, 0x69, 0x62, 0x65, - 0x72, 0x79, 0x10, 0xa8, 0x06, 0x12, 0x0d, 0x0a, 0x08, 0x54, 0x79, 0x70, 0x65, 0x74, 0x61, 0x6c, - 0x6b, 0x10, 0xa9, 0x06, 0x12, 0x0e, 0x0a, 0x09, 0x56, 0x6f, 0x6f, 0x64, 0x6f, 0x6f, 0x53, 0x4d, - 0x53, 0x10, 0xaa, 0x06, 0x12, 0x0e, 0x0a, 0x09, 0x5a, 0x75, 0x6c, 0x69, 0x70, 0x43, 0x68, 0x61, - 0x74, 0x10, 0xab, 0x06, 0x12, 0x0e, 0x0a, 0x09, 0x46, 0x6f, 0x72, 0x6d, 0x63, 0x72, 0x61, 0x66, - 0x74, 0x10, 0xac, 0x06, 0x12, 0x0c, 0x0a, 0x07, 0x49, 0x65, 0x78, 0x61, 0x70, 0x69, 0x73, 0x10, - 0xad, 0x06, 0x12, 0x0e, 0x0a, 0x09, 0x52, 0x65, 0x61, 0x63, 0x68, 0x6d, 0x61, 0x69, 0x6c, 0x10, - 0xae, 0x06, 0x12, 0x0f, 0x0a, 0x0a, 0x43, 0x68, 0x61, 0x72, 0x74, 0x6d, 0x6f, 0x67, 0x75, 0x6c, - 0x10, 0xaf, 0x06, 0x12, 0x0f, 0x0a, 0x0a, 0x41, 0x70, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x65, 0x64, - 0x64, 0x10, 0xb0, 0x06, 0x12, 0x08, 0x0a, 0x03, 0x57, 0x69, 0x74, 0x10, 0xb1, 0x06, 0x12, 0x15, - 0x0a, 0x10, 0x52, 0x65, 0x63, 0x68, 0x61, 0x72, 0x67, 0x65, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, - 0x74, 0x73, 0x10, 0xb2, 0x06, 0x12, 0x0f, 0x0a, 0x0a, 0x44, 0x69, 0x67, 0x67, 0x65, 0x72, 0x6e, - 0x61, 0x75, 0x74, 0x10, 0xb3, 0x06, 0x12, 0x10, 0x0a, 0x0b, 0x4d, 0x6f, 0x6e, 0x6b, 0x65, 0x79, - 0x4c, 0x65, 0x61, 0x72, 0x6e, 0x10, 0xb4, 0x06, 0x12, 0x0a, 0x0a, 0x05, 0x44, 0x75, 0x70, 0x6c, - 0x79, 0x10, 0xb5, 0x06, 0x12, 0x0e, 0x0a, 0x09, 0x50, 0x6f, 0x73, 0x74, 0x62, 0x61, 0x63, 0x6b, - 0x73, 0x10, 0xb6, 0x06, 0x12, 0x0d, 0x0a, 0x08, 0x43, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x32, - 0x10, 0xb7, 0x06, 0x12, 0x0c, 0x0a, 0x07, 0x5a, 0x65, 0x6e, 0x52, 0x6f, 0x77, 0x73, 0x10, 0xb8, - 0x06, 0x12, 0x10, 0x0a, 0x0b, 0x5a, 0x69, 0x70, 0x63, 0x6f, 0x64, 0x65, 0x62, 0x61, 0x73, 0x65, - 0x10, 0xb9, 0x06, 0x12, 0x0b, 0x0a, 0x06, 0x54, 0x65, 0x66, 0x74, 0x65, 0x72, 0x10, 0xba, 0x06, - 0x12, 0x0a, 0x0a, 0x05, 0x54, 0x77, 0x69, 0x73, 0x74, 0x10, 0xbb, 0x06, 0x12, 0x16, 0x0a, 0x11, - 0x42, 0x72, 0x61, 0x69, 0x6e, 0x74, 0x72, 0x65, 0x65, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, - 0x73, 0x10, 0xbc, 0x06, 0x12, 0x11, 0x0a, 0x0c, 0x43, 0x6c, 0x6f, 0x75, 0x64, 0x43, 0x6f, 0x6e, - 0x76, 0x65, 0x72, 0x74, 0x10, 0xbd, 0x06, 0x12, 0x0c, 0x0a, 0x07, 0x47, 0x72, 0x61, 0x66, 0x61, - 0x6e, 0x61, 0x10, 0xbe, 0x06, 0x12, 0x0f, 0x0a, 0x0a, 0x43, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x74, - 0x41, 0x70, 0x69, 0x10, 0xbf, 0x06, 0x12, 0x11, 0x0a, 0x0c, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x66, - 0x65, 0x72, 0x77, 0x69, 0x73, 0x65, 0x10, 0xc0, 0x06, 0x12, 0x0c, 0x0a, 0x07, 0x42, 0x75, 0x6c, - 0x6b, 0x73, 0x6d, 0x73, 0x10, 0xc1, 0x06, 0x12, 0x0c, 0x0a, 0x07, 0x44, 0x61, 0x74, 0x61, 0x62, - 0x6f, 0x78, 0x10, 0xc2, 0x06, 0x12, 0x0e, 0x0a, 0x09, 0x4f, 0x6e, 0x65, 0x73, 0x69, 0x67, 0x6e, - 0x61, 0x6c, 0x10, 0xc3, 0x06, 0x12, 0x0c, 0x0a, 0x07, 0x52, 0x65, 0x6e, 0x74, 0x6d, 0x61, 0x6e, - 0x10, 0xc4, 0x06, 0x12, 0x0c, 0x0a, 0x07, 0x50, 0x61, 0x72, 0x73, 0x65, 0x75, 0x72, 0x10, 0xc5, - 0x06, 0x12, 0x0e, 0x0a, 0x09, 0x44, 0x6f, 0x63, 0x70, 0x61, 0x72, 0x73, 0x65, 0x72, 0x10, 0xc6, - 0x06, 0x12, 0x0d, 0x0a, 0x08, 0x46, 0x6f, 0x72, 0x6d, 0x73, 0x69, 0x74, 0x65, 0x10, 0xc7, 0x06, - 0x12, 0x11, 0x0a, 0x0c, 0x54, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x74, 0x61, 0x69, 0x6c, 0x6f, 0x72, - 0x10, 0xc8, 0x06, 0x12, 0x0c, 0x0a, 0x07, 0x4c, 0x65, 0x6d, 0x6c, 0x69, 0x73, 0x74, 0x10, 0xc9, - 0x06, 0x12, 0x0c, 0x0a, 0x07, 0x50, 0x72, 0x6f, 0x64, 0x70, 0x61, 0x64, 0x10, 0xca, 0x06, 0x12, - 0x0e, 0x0a, 0x09, 0x46, 0x6f, 0x72, 0x6d, 0x73, 0x74, 0x61, 0x63, 0x6b, 0x10, 0xcb, 0x06, 0x12, - 0x10, 0x0a, 0x0b, 0x43, 0x6f, 0x64, 0x65, 0x63, 0x6c, 0x69, 0x6d, 0x61, 0x74, 0x65, 0x10, 0xcc, - 0x06, 0x12, 0x0e, 0x0a, 0x09, 0x43, 0x6f, 0x64, 0x65, 0x6d, 0x61, 0x67, 0x69, 0x63, 0x10, 0xcd, - 0x06, 0x12, 0x0a, 0x0a, 0x05, 0x56, 0x62, 0x6f, 0x75, 0x74, 0x10, 0xce, 0x06, 0x12, 0x0e, 0x0a, - 0x09, 0x4e, 0x69, 0x67, 0x68, 0x74, 0x66, 0x61, 0x6c, 0x6c, 0x10, 0xcf, 0x06, 0x12, 0x0f, 0x0a, - 0x0a, 0x46, 0x6c, 0x69, 0x67, 0x68, 0x74, 0x4c, 0x61, 0x62, 0x73, 0x10, 0xd0, 0x06, 0x12, 0x11, - 0x0a, 0x0c, 0x53, 0x70, 0x65, 0x65, 0x63, 0x68, 0x54, 0x65, 0x78, 0x74, 0x41, 0x49, 0x10, 0xd1, - 0x06, 0x12, 0x0d, 0x0a, 0x08, 0x50, 0x6f, 0x6c, 0x6c, 0x73, 0x41, 0x50, 0x49, 0x10, 0xd2, 0x06, - 0x12, 0x0b, 0x0a, 0x06, 0x53, 0x69, 0x6d, 0x46, 0x69, 0x6e, 0x10, 0xd3, 0x06, 0x12, 0x0a, 0x0a, - 0x05, 0x53, 0x63, 0x61, 0x6c, 0x72, 0x10, 0xd4, 0x06, 0x12, 0x0f, 0x0a, 0x0a, 0x4b, 0x61, 0x6e, - 0x62, 0x61, 0x6e, 0x74, 0x6f, 0x6f, 0x6c, 0x10, 0xd5, 0x06, 0x12, 0x10, 0x0a, 0x0b, 0x42, 0x72, - 0x69, 0x67, 0x68, 0x74, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x10, 0xd6, 0x06, 0x12, 0x0c, 0x0a, 0x07, - 0x48, 0x6f, 0x74, 0x77, 0x69, 0x72, 0x65, 0x10, 0xd7, 0x06, 0x12, 0x0d, 0x0a, 0x08, 0x49, 0x6e, - 0x73, 0x74, 0x61, 0x62, 0x6f, 0x74, 0x10, 0xd8, 0x06, 0x12, 0x0c, 0x0a, 0x07, 0x54, 0x69, 0x6d, - 0x65, 0x6b, 0x69, 0x74, 0x10, 0xd9, 0x06, 0x12, 0x10, 0x0a, 0x0b, 0x49, 0x6e, 0x74, 0x65, 0x72, - 0x73, 0x65, 0x6c, 0x6c, 0x65, 0x72, 0x10, 0xda, 0x06, 0x12, 0x11, 0x0a, 0x0c, 0x4d, 0x6f, 0x6a, - 0x6f, 0x68, 0x65, 0x6c, 0x70, 0x64, 0x65, 0x73, 0x6b, 0x10, 0xdb, 0x06, 0x12, 0x0f, 0x0a, 0x0a, - 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x73, 0x65, 0x6e, 0x64, 0x10, 0xdc, 0x06, 0x12, 0x10, 0x0a, - 0x0b, 0x47, 0x65, 0x74, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x10, 0xdd, 0x06, 0x12, - 0x0c, 0x0a, 0x07, 0x44, 0x79, 0x6e, 0x61, 0x64, 0x6f, 0x74, 0x10, 0xde, 0x06, 0x12, 0x0a, 0x0a, - 0x05, 0x44, 0x65, 0x6d, 0x69, 0x6f, 0x10, 0xdf, 0x06, 0x12, 0x0b, 0x0a, 0x06, 0x54, 0x6f, 0x6b, - 0x65, 0x65, 0x74, 0x10, 0xe0, 0x06, 0x12, 0x11, 0x0a, 0x0c, 0x4d, 0x79, 0x65, 0x78, 0x70, 0x65, - 0x72, 0x69, 0x6d, 0x65, 0x6e, 0x74, 0x10, 0xe1, 0x06, 0x12, 0x0e, 0x0a, 0x09, 0x43, 0x6f, 0x70, - 0x79, 0x73, 0x63, 0x61, 0x70, 0x65, 0x10, 0xe2, 0x06, 0x12, 0x0d, 0x0a, 0x08, 0x42, 0x65, 0x73, - 0x6e, 0x61, 0x70, 0x70, 0x79, 0x10, 0xe3, 0x06, 0x12, 0x0e, 0x0a, 0x09, 0x53, 0x61, 0x6c, 0x65, - 0x73, 0x6d, 0x61, 0x74, 0x65, 0x10, 0xe4, 0x06, 0x12, 0x13, 0x0a, 0x0a, 0x48, 0x65, 0x61, 0x74, - 0x6d, 0x61, 0x70, 0x61, 0x70, 0x69, 0x10, 0xe5, 0x06, 0x1a, 0x02, 0x08, 0x01, 0x12, 0x11, 0x0a, - 0x0c, 0x57, 0x65, 0x62, 0x73, 0x69, 0x74, 0x65, 0x70, 0x75, 0x6c, 0x73, 0x65, 0x10, 0xe6, 0x06, - 0x12, 0x0e, 0x0a, 0x09, 0x55, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x69, 0x66, 0x79, 0x10, 0xe7, 0x06, - 0x12, 0x0c, 0x0a, 0x07, 0x43, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x74, 0x10, 0xe8, 0x06, 0x12, 0x0d, - 0x0a, 0x08, 0x50, 0x44, 0x46, 0x6d, 0x79, 0x55, 0x52, 0x4c, 0x10, 0xe9, 0x06, 0x12, 0x10, 0x0a, - 0x0b, 0x41, 0x70, 0x69, 0x32, 0x43, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x74, 0x10, 0xea, 0x06, 0x12, - 0x0d, 0x0a, 0x08, 0x4f, 0x70, 0x73, 0x67, 0x65, 0x6e, 0x69, 0x65, 0x10, 0xeb, 0x06, 0x12, 0x0b, - 0x0a, 0x06, 0x47, 0x65, 0x6d, 0x69, 0x6e, 0x69, 0x10, 0xec, 0x06, 0x12, 0x0e, 0x0a, 0x09, 0x48, - 0x6f, 0x6e, 0x65, 0x79, 0x63, 0x6f, 0x6d, 0x62, 0x10, 0xed, 0x06, 0x12, 0x14, 0x0a, 0x0f, 0x4b, - 0x61, 0x6c, 0x74, 0x75, 0x72, 0x61, 0x41, 0x70, 0x70, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x10, 0xee, - 0x06, 0x12, 0x13, 0x0a, 0x0e, 0x4b, 0x61, 0x6c, 0x74, 0x75, 0x72, 0x61, 0x53, 0x65, 0x73, 0x73, - 0x69, 0x6f, 0x6e, 0x10, 0xef, 0x06, 0x12, 0x0a, 0x0a, 0x05, 0x42, 0x69, 0x74, 0x47, 0x6f, 0x10, - 0xf0, 0x06, 0x12, 0x0d, 0x0a, 0x08, 0x4f, 0x70, 0x74, 0x69, 0x64, 0x61, 0x73, 0x68, 0x10, 0xf1, - 0x06, 0x12, 0x0a, 0x0a, 0x05, 0x49, 0x6d, 0x67, 0x69, 0x78, 0x10, 0xf2, 0x06, 0x12, 0x10, 0x0a, - 0x0b, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x54, 0x6f, 0x54, 0x65, 0x78, 0x74, 0x10, 0xf3, 0x06, 0x12, - 0x10, 0x0a, 0x0b, 0x50, 0x61, 0x67, 0x65, 0x32, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x73, 0x10, 0xf4, - 0x06, 0x12, 0x0e, 0x0a, 0x09, 0x51, 0x75, 0x69, 0x63, 0x6b, 0x62, 0x61, 0x73, 0x65, 0x10, 0xf5, - 0x06, 0x12, 0x0d, 0x0a, 0x08, 0x52, 0x65, 0x64, 0x62, 0x6f, 0x6f, 0x74, 0x68, 0x10, 0xf6, 0x06, - 0x12, 0x0b, 0x0a, 0x06, 0x4e, 0x75, 0x62, 0x65, 0x6c, 0x61, 0x10, 0xf7, 0x06, 0x12, 0x0c, 0x0a, - 0x07, 0x49, 0x6e, 0x66, 0x6f, 0x62, 0x69, 0x70, 0x10, 0xf8, 0x06, 0x12, 0x0a, 0x0a, 0x05, 0x55, - 0x70, 0x72, 0x6f, 0x63, 0x10, 0xf9, 0x06, 0x12, 0x0f, 0x0a, 0x0a, 0x53, 0x75, 0x70, 0x70, 0x6f, - 0x72, 0x74, 0x62, 0x65, 0x65, 0x10, 0xfa, 0x06, 0x12, 0x0e, 0x0a, 0x09, 0x41, 0x66, 0x74, 0x65, - 0x72, 0x73, 0x68, 0x69, 0x70, 0x10, 0xfb, 0x06, 0x12, 0x0c, 0x0a, 0x07, 0x45, 0x64, 0x75, 0x73, - 0x69, 0x67, 0x6e, 0x10, 0xfc, 0x06, 0x12, 0x0b, 0x0a, 0x06, 0x54, 0x65, 0x61, 0x6d, 0x75, 0x70, - 0x10, 0xfd, 0x06, 0x12, 0x0c, 0x0a, 0x07, 0x57, 0x6f, 0x72, 0x6b, 0x64, 0x61, 0x79, 0x10, 0xfe, - 0x06, 0x12, 0x0c, 0x0a, 0x07, 0x4d, 0x6f, 0x6e, 0x67, 0x6f, 0x44, 0x42, 0x10, 0xff, 0x06, 0x12, - 0x08, 0x0a, 0x03, 0x4e, 0x47, 0x43, 0x10, 0x80, 0x07, 0x12, 0x13, 0x0a, 0x0e, 0x44, 0x69, 0x67, - 0x69, 0x74, 0x61, 0x6c, 0x4f, 0x63, 0x65, 0x61, 0x6e, 0x56, 0x32, 0x10, 0x81, 0x07, 0x12, 0x0e, - 0x0a, 0x09, 0x53, 0x51, 0x4c, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x10, 0x82, 0x07, 0x12, 0x08, - 0x0a, 0x03, 0x46, 0x54, 0x50, 0x10, 0x83, 0x07, 0x12, 0x0a, 0x0a, 0x05, 0x52, 0x65, 0x64, 0x69, - 0x73, 0x10, 0x84, 0x07, 0x12, 0x09, 0x0a, 0x04, 0x4c, 0x44, 0x41, 0x50, 0x10, 0x85, 0x07, 0x12, - 0x0c, 0x0a, 0x07, 0x53, 0x68, 0x6f, 0x70, 0x69, 0x66, 0x79, 0x10, 0x86, 0x07, 0x12, 0x0d, 0x0a, - 0x08, 0x52, 0x61, 0x62, 0x62, 0x69, 0x74, 0x4d, 0x51, 0x10, 0x87, 0x07, 0x12, 0x10, 0x0a, 0x0b, - 0x43, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x52, 0x65, 0x67, 0x65, 0x78, 0x10, 0x88, 0x07, 0x12, 0x0e, - 0x0a, 0x09, 0x45, 0x74, 0x68, 0x65, 0x72, 0x73, 0x63, 0x61, 0x6e, 0x10, 0x89, 0x07, 0x12, 0x0b, - 0x0a, 0x06, 0x49, 0x6e, 0x66, 0x75, 0x72, 0x61, 0x10, 0x8a, 0x07, 0x12, 0x0c, 0x0a, 0x07, 0x41, - 0x6c, 0x63, 0x68, 0x65, 0x6d, 0x79, 0x10, 0x8b, 0x07, 0x12, 0x10, 0x0a, 0x0b, 0x42, 0x6c, 0x6f, - 0x63, 0x6b, 0x4e, 0x61, 0x74, 0x69, 0x76, 0x65, 0x10, 0x8c, 0x07, 0x12, 0x0c, 0x0a, 0x07, 0x4d, - 0x6f, 0x72, 0x61, 0x6c, 0x69, 0x73, 0x10, 0x8d, 0x07, 0x12, 0x0c, 0x0a, 0x07, 0x42, 0x73, 0x63, - 0x53, 0x63, 0x61, 0x6e, 0x10, 0x8e, 0x07, 0x12, 0x16, 0x0a, 0x0d, 0x43, 0x6f, 0x69, 0x6e, 0x4d, - 0x61, 0x72, 0x6b, 0x65, 0x74, 0x43, 0x61, 0x70, 0x10, 0x8f, 0x07, 0x1a, 0x02, 0x08, 0x01, 0x12, - 0x0a, 0x0a, 0x05, 0x50, 0x65, 0x72, 0x63, 0x79, 0x10, 0x90, 0x07, 0x12, 0x11, 0x0a, 0x0c, 0x54, - 0x69, 0x6e, 0x65, 0x73, 0x57, 0x65, 0x62, 0x68, 0x6f, 0x6f, 0x6b, 0x10, 0x91, 0x07, 0x12, 0x0b, - 0x0a, 0x06, 0x50, 0x75, 0x6c, 0x75, 0x6d, 0x69, 0x10, 0x92, 0x07, 0x12, 0x12, 0x0a, 0x0d, 0x53, - 0x75, 0x70, 0x61, 0x62, 0x61, 0x73, 0x65, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x10, 0x93, 0x07, 0x12, - 0x10, 0x0a, 0x0b, 0x4e, 0x75, 0x47, 0x65, 0x74, 0x41, 0x70, 0x69, 0x4b, 0x65, 0x79, 0x10, 0x94, - 0x07, 0x12, 0x0a, 0x0a, 0x05, 0x41, 0x69, 0x76, 0x65, 0x6e, 0x10, 0x95, 0x07, 0x12, 0x0c, 0x0a, - 0x07, 0x50, 0x72, 0x65, 0x66, 0x65, 0x63, 0x74, 0x10, 0x96, 0x07, 0x12, 0x0d, 0x0a, 0x08, 0x44, - 0x6f, 0x63, 0x75, 0x73, 0x69, 0x67, 0x6e, 0x10, 0x97, 0x07, 0x12, 0x0e, 0x0a, 0x09, 0x43, 0x6f, - 0x75, 0x63, 0x68, 0x62, 0x61, 0x73, 0x65, 0x10, 0x98, 0x07, 0x12, 0x0e, 0x0a, 0x09, 0x44, 0x6f, - 0x63, 0x6b, 0x65, 0x72, 0x68, 0x75, 0x62, 0x10, 0x99, 0x07, 0x12, 0x19, 0x0a, 0x14, 0x54, 0x72, - 0x75, 0x66, 0x66, 0x6c, 0x65, 0x68, 0x6f, 0x67, 0x45, 0x6e, 0x74, 0x65, 0x72, 0x70, 0x72, 0x69, - 0x73, 0x65, 0x10, 0x9a, 0x07, 0x12, 0x10, 0x0a, 0x0b, 0x45, 0x6e, 0x76, 0x6f, 0x79, 0x41, 0x70, - 0x69, 0x4b, 0x65, 0x79, 0x10, 0x9b, 0x07, 0x12, 0x11, 0x0a, 0x0c, 0x47, 0x69, 0x74, 0x48, 0x75, - 0x62, 0x4f, 0x61, 0x75, 0x74, 0x68, 0x32, 0x10, 0x9c, 0x07, 0x12, 0x0f, 0x0a, 0x0a, 0x53, 0x61, - 0x6c, 0x65, 0x73, 0x66, 0x6f, 0x72, 0x63, 0x65, 0x10, 0x9d, 0x07, 0x12, 0x10, 0x0a, 0x0b, 0x48, - 0x75, 0x67, 0x67, 0x69, 0x6e, 0x67, 0x46, 0x61, 0x63, 0x65, 0x10, 0x9e, 0x07, 0x12, 0x0e, 0x0a, - 0x09, 0x53, 0x6e, 0x6f, 0x77, 0x66, 0x6c, 0x61, 0x6b, 0x65, 0x10, 0x9f, 0x07, 0x12, 0x10, 0x0a, - 0x0b, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x67, 0x72, 0x61, 0x70, 0x68, 0x10, 0xa0, 0x07, 0x12, - 0x0e, 0x0a, 0x09, 0x54, 0x61, 0x69, 0x6c, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x10, 0xa1, 0x07, 0x12, - 0x10, 0x0a, 0x0b, 0x57, 0x65, 0x62, 0x33, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x10, 0xa2, - 0x07, 0x12, 0x11, 0x0a, 0x0c, 0x41, 0x7a, 0x75, 0x72, 0x65, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, - 0x65, 0x10, 0xa3, 0x07, 0x12, 0x12, 0x0a, 0x0d, 0x50, 0x6c, 0x61, 0x6e, 0x65, 0x74, 0x53, 0x63, - 0x61, 0x6c, 0x65, 0x44, 0x62, 0x10, 0xa4, 0x07, 0x12, 0x0e, 0x0a, 0x09, 0x41, 0x6e, 0x74, 0x68, - 0x72, 0x6f, 0x70, 0x69, 0x63, 0x10, 0xa5, 0x07, 0x12, 0x09, 0x0a, 0x04, 0x52, 0x61, 0x6d, 0x70, - 0x10, 0xa6, 0x07, 0x12, 0x0c, 0x0a, 0x07, 0x4b, 0x6c, 0x61, 0x76, 0x69, 0x79, 0x6f, 0x10, 0xa7, - 0x07, 0x12, 0x14, 0x0a, 0x0f, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x67, 0x72, 0x61, 0x70, 0x68, - 0x43, 0x6f, 0x64, 0x79, 0x10, 0xa8, 0x07, 0x12, 0x0e, 0x0a, 0x09, 0x56, 0x6f, 0x69, 0x63, 0x65, - 0x66, 0x6c, 0x6f, 0x77, 0x10, 0xa9, 0x07, 0x12, 0x0c, 0x0a, 0x07, 0x50, 0x72, 0x69, 0x76, 0x61, - 0x63, 0x79, 0x10, 0xaa, 0x07, 0x12, 0x0b, 0x0a, 0x06, 0x49, 0x50, 0x49, 0x6e, 0x66, 0x6f, 0x10, - 0xab, 0x07, 0x12, 0x10, 0x0a, 0x0b, 0x49, 0x70, 0x32, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x10, 0xac, 0x07, 0x12, 0x0e, 0x0a, 0x09, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6d, 0x6f, 0x6a, - 0x6f, 0x10, 0xad, 0x07, 0x12, 0x0e, 0x0a, 0x09, 0x50, 0x6f, 0x72, 0x74, 0x61, 0x69, 0x6e, 0x65, - 0x72, 0x10, 0xae, 0x07, 0x12, 0x13, 0x0a, 0x0e, 0x50, 0x6f, 0x72, 0x74, 0x61, 0x69, 0x6e, 0x65, - 0x72, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x10, 0xaf, 0x07, 0x12, 0x0b, 0x0a, 0x06, 0x4c, 0x6f, 0x67, - 0x67, 0x6c, 0x79, 0x10, 0xb0, 0x07, 0x12, 0x0c, 0x0a, 0x07, 0x4f, 0x70, 0x65, 0x6e, 0x56, 0x70, - 0x6e, 0x10, 0xb1, 0x07, 0x12, 0x1e, 0x0a, 0x19, 0x56, 0x61, 0x67, 0x72, 0x61, 0x6e, 0x74, 0x43, - 0x6c, 0x6f, 0x75, 0x64, 0x50, 0x65, 0x72, 0x73, 0x6f, 0x6e, 0x61, 0x6c, 0x54, 0x6f, 0x6b, 0x65, - 0x6e, 0x10, 0xb2, 0x07, 0x12, 0x10, 0x0a, 0x0b, 0x42, 0x65, 0x74, 0x74, 0x65, 0x72, 0x53, 0x74, - 0x61, 0x63, 0x6b, 0x10, 0xb3, 0x07, 0x12, 0x0d, 0x0a, 0x08, 0x5a, 0x65, 0x72, 0x6f, 0x54, 0x69, - 0x65, 0x72, 0x10, 0xb4, 0x07, 0x12, 0x0e, 0x0a, 0x09, 0x41, 0x70, 0x70, 0x4f, 0x70, 0x74, 0x69, - 0x63, 0x73, 0x10, 0xb5, 0x07, 0x12, 0x0d, 0x0a, 0x08, 0x4d, 0x65, 0x74, 0x61, 0x62, 0x61, 0x73, - 0x65, 0x10, 0xb6, 0x07, 0x12, 0x11, 0x0a, 0x0c, 0x43, 0x6f, 0x69, 0x6e, 0x62, 0x61, 0x73, 0x65, - 0x57, 0x61, 0x61, 0x53, 0x10, 0xb7, 0x07, 0x12, 0x11, 0x0a, 0x0c, 0x4c, 0x65, 0x6d, 0x6f, 0x6e, - 0x53, 0x71, 0x75, 0x65, 0x65, 0x7a, 0x79, 0x10, 0xb8, 0x07, 0x12, 0x0d, 0x0a, 0x08, 0x42, 0x75, - 0x64, 0x69, 0x62, 0x61, 0x73, 0x65, 0x10, 0xb9, 0x07, 0x12, 0x0f, 0x0a, 0x0a, 0x44, 0x65, 0x6e, - 0x6f, 0x44, 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x10, 0xba, 0x07, 0x12, 0x0b, 0x0a, 0x06, 0x53, 0x74, - 0x72, 0x69, 0x70, 0x6f, 0x10, 0xbb, 0x07, 0x12, 0x0c, 0x0a, 0x07, 0x52, 0x65, 0x70, 0x6c, 0x79, - 0x49, 0x4f, 0x10, 0xbc, 0x07, 0x12, 0x0f, 0x0a, 0x0a, 0x41, 0x7a, 0x75, 0x72, 0x65, 0x42, 0x61, - 0x74, 0x63, 0x68, 0x10, 0xbd, 0x07, 0x12, 0x1b, 0x0a, 0x16, 0x41, 0x7a, 0x75, 0x72, 0x65, 0x43, - 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, - 0x10, 0xbe, 0x07, 0x12, 0x12, 0x0a, 0x0d, 0x41, 0x57, 0x53, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, - 0x6e, 0x4b, 0x65, 0x79, 0x10, 0xbf, 0x07, 0x12, 0x09, 0x0a, 0x04, 0x43, 0x6f, 0x64, 0x61, 0x10, - 0xc0, 0x07, 0x12, 0x0b, 0x0a, 0x06, 0x4c, 0x6f, 0x67, 0x7a, 0x49, 0x4f, 0x10, 0xc1, 0x07, 0x12, - 0x0f, 0x0a, 0x0a, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x62, 0x72, 0x69, 0x74, 0x65, 0x10, 0xc2, 0x07, - 0x12, 0x1a, 0x0a, 0x15, 0x47, 0x72, 0x61, 0x66, 0x61, 0x6e, 0x61, 0x53, 0x65, 0x72, 0x76, 0x69, - 0x63, 0x65, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x10, 0xc3, 0x07, 0x12, 0x13, 0x0a, 0x0e, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x46, 0x69, 0x6e, 0x61, 0x6e, 0x63, 0x65, 0x10, 0xc4, - 0x07, 0x12, 0x0d, 0x0a, 0x08, 0x4f, 0x76, 0x65, 0x72, 0x6c, 0x6f, 0x6f, 0x70, 0x10, 0xc5, 0x07, - 0x12, 0x0a, 0x0a, 0x05, 0x4e, 0x67, 0x72, 0x6f, 0x6b, 0x10, 0xc6, 0x07, 0x12, 0x0e, 0x0a, 0x09, - 0x52, 0x65, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x65, 0x10, 0xc7, 0x07, 0x12, 0x0d, 0x0a, 0x08, - 0x50, 0x6f, 0x73, 0x74, 0x67, 0x72, 0x65, 0x73, 0x10, 0xc8, 0x07, 0x12, 0x2a, 0x0a, 0x25, 0x41, - 0x7a, 0x75, 0x72, 0x65, 0x41, 0x63, 0x74, 0x69, 0x76, 0x65, 0x44, 0x69, 0x72, 0x65, 0x63, 0x74, - 0x6f, 0x72, 0x79, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x65, - 0x63, 0x72, 0x65, 0x74, 0x10, 0xc9, 0x07, 0x12, 0x20, 0x0a, 0x1b, 0x41, 0x7a, 0x75, 0x72, 0x65, - 0x43, 0x61, 0x63, 0x68, 0x65, 0x46, 0x6f, 0x72, 0x52, 0x65, 0x64, 0x69, 0x73, 0x41, 0x63, 0x63, - 0x65, 0x73, 0x73, 0x4b, 0x65, 0x79, 0x10, 0xca, 0x07, 0x12, 0x21, 0x0a, 0x1c, 0x41, 0x7a, 0x75, - 0x72, 0x65, 0x43, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x44, 0x42, 0x4b, 0x65, 0x79, 0x49, 0x64, 0x65, - 0x6e, 0x74, 0x69, 0x66, 0x69, 0x61, 0x62, 0x6c, 0x65, 0x10, 0xcb, 0x07, 0x12, 0x23, 0x0a, 0x1e, - 0x41, 0x7a, 0x75, 0x72, 0x65, 0x44, 0x65, 0x76, 0x6f, 0x70, 0x73, 0x50, 0x65, 0x72, 0x73, 0x6f, - 0x6e, 0x61, 0x6c, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x10, 0xcc, - 0x07, 0x12, 0x15, 0x0a, 0x10, 0x41, 0x7a, 0x75, 0x72, 0x65, 0x46, 0x75, 0x6e, 0x63, 0x74, 0x69, - 0x6f, 0x6e, 0x4b, 0x65, 0x79, 0x10, 0xcd, 0x07, 0x12, 0x2c, 0x0a, 0x27, 0x41, 0x7a, 0x75, 0x72, - 0x65, 0x4d, 0x4c, 0x57, 0x65, 0x62, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x43, 0x6c, 0x61, - 0x73, 0x73, 0x69, 0x63, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x61, 0x62, 0x6c, 0x65, - 0x4b, 0x65, 0x79, 0x10, 0xce, 0x07, 0x12, 0x12, 0x0a, 0x0d, 0x41, 0x7a, 0x75, 0x72, 0x65, 0x53, - 0x61, 0x73, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x10, 0xcf, 0x07, 0x12, 0x18, 0x0a, 0x13, 0x41, 0x7a, - 0x75, 0x72, 0x65, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x41, 0x64, 0x6d, 0x69, 0x6e, 0x4b, 0x65, - 0x79, 0x10, 0xd0, 0x07, 0x12, 0x18, 0x0a, 0x13, 0x41, 0x7a, 0x75, 0x72, 0x65, 0x53, 0x65, 0x61, - 0x72, 0x63, 0x68, 0x51, 0x75, 0x65, 0x72, 0x79, 0x4b, 0x65, 0x79, 0x10, 0xd1, 0x07, 0x12, 0x1f, - 0x0a, 0x1a, 0x41, 0x7a, 0x75, 0x72, 0x65, 0x4d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, - 0x74, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x10, 0xd2, 0x07, 0x12, - 0x0d, 0x0a, 0x08, 0x41, 0x7a, 0x75, 0x72, 0x65, 0x53, 0x51, 0x4c, 0x10, 0xd3, 0x07, 0x12, 0x0a, - 0x0a, 0x05, 0x46, 0x6c, 0x79, 0x49, 0x4f, 0x10, 0xd4, 0x07, 0x12, 0x0e, 0x0a, 0x09, 0x42, 0x75, - 0x69, 0x6c, 0x74, 0x57, 0x69, 0x74, 0x68, 0x10, 0xd5, 0x07, 0x12, 0x0f, 0x0a, 0x0a, 0x4a, 0x75, - 0x70, 0x69, 0x74, 0x65, 0x72, 0x4f, 0x6e, 0x65, 0x10, 0xd6, 0x07, 0x12, 0x25, 0x0a, 0x20, 0x47, - 0x43, 0x50, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x44, 0x65, 0x66, - 0x61, 0x75, 0x6c, 0x74, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x73, 0x10, - 0xd7, 0x07, 0x12, 0x08, 0x0a, 0x03, 0x57, 0x69, 0x7a, 0x10, 0xd8, 0x07, 0x12, 0x0c, 0x0a, 0x07, - 0x50, 0x61, 0x67, 0x61, 0x72, 0x6d, 0x65, 0x10, 0xd9, 0x07, 0x12, 0x0c, 0x0a, 0x07, 0x4f, 0x6e, - 0x66, 0x6c, 0x65, 0x65, 0x74, 0x10, 0xda, 0x07, 0x12, 0x0c, 0x0a, 0x07, 0x49, 0x6e, 0x74, 0x72, - 0x61, 0x34, 0x32, 0x10, 0xdb, 0x07, 0x12, 0x09, 0x0a, 0x04, 0x47, 0x72, 0x6f, 0x71, 0x10, 0xdc, - 0x07, 0x12, 0x17, 0x0a, 0x12, 0x54, 0x77, 0x69, 0x74, 0x74, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x73, - 0x75, 0x6d, 0x65, 0x72, 0x6b, 0x65, 0x79, 0x10, 0xdd, 0x07, 0x12, 0x0b, 0x0a, 0x06, 0x45, 0x72, - 0x61, 0x73, 0x65, 0x72, 0x10, 0xde, 0x07, 0x12, 0x0e, 0x0a, 0x09, 0x4c, 0x61, 0x72, 0x6b, 0x53, - 0x75, 0x69, 0x74, 0x65, 0x10, 0xdf, 0x07, 0x12, 0x14, 0x0a, 0x0f, 0x4c, 0x61, 0x72, 0x6b, 0x53, - 0x75, 0x69, 0x74, 0x65, 0x41, 0x70, 0x69, 0x4b, 0x65, 0x79, 0x10, 0xe0, 0x07, 0x12, 0x0e, 0x0a, - 0x09, 0x45, 0x6e, 0x64, 0x6f, 0x72, 0x4c, 0x61, 0x62, 0x73, 0x10, 0xe1, 0x07, 0x12, 0x0f, 0x0a, - 0x0a, 0x45, 0x6c, 0x65, 0x76, 0x65, 0x6e, 0x4c, 0x61, 0x62, 0x73, 0x10, 0xe2, 0x07, 0x12, 0x0d, - 0x0a, 0x08, 0x4e, 0x65, 0x74, 0x73, 0x75, 0x69, 0x74, 0x65, 0x10, 0xe3, 0x07, 0x12, 0x14, 0x0a, - 0x0f, 0x52, 0x6f, 0x62, 0x69, 0x6e, 0x68, 0x6f, 0x6f, 0x64, 0x43, 0x72, 0x79, 0x70, 0x74, 0x6f, - 0x10, 0xe4, 0x07, 0x12, 0x0a, 0x0a, 0x05, 0x4e, 0x56, 0x41, 0x50, 0x49, 0x10, 0xe5, 0x07, 0x12, - 0x09, 0x0a, 0x04, 0x50, 0x79, 0x50, 0x49, 0x10, 0xe6, 0x07, 0x12, 0x0f, 0x0a, 0x0a, 0x52, 0x61, - 0x69, 0x6c, 0x77, 0x61, 0x79, 0x41, 0x70, 0x70, 0x10, 0xe7, 0x07, 0x12, 0x0b, 0x0a, 0x06, 0x4d, - 0x65, 0x72, 0x61, 0x6b, 0x69, 0x10, 0xe8, 0x07, 0x12, 0x15, 0x0a, 0x10, 0x53, 0x61, 0x6c, 0x61, - 0x64, 0x43, 0x6c, 0x6f, 0x75, 0x64, 0x41, 0x70, 0x69, 0x4b, 0x65, 0x79, 0x10, 0xe9, 0x07, 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, + 0x10, 0x04, 0x2a, 0x93, 0x80, 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, + 0x0a, 0x0a, 0x06, 0x43, 0x69, 0x72, 0x63, 0x6c, 0x65, 0x10, 0x04, 0x12, 0x0c, 0x0a, 0x08, 0x43, + 0x6f, 0x69, 0x6e, 0x62, 0x61, 0x73, 0x65, 0x10, 0x05, 0x12, 0x07, 0x0a, 0x03, 0x47, 0x43, 0x50, + 0x10, 0x06, 0x12, 0x0b, 0x0a, 0x07, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x69, 0x63, 0x10, 0x07, 0x12, + 0x0a, 0x0a, 0x06, 0x47, 0x69, 0x74, 0x68, 0x75, 0x62, 0x10, 0x08, 0x12, 0x0a, 0x0a, 0x06, 0x47, + 0x69, 0x74, 0x6c, 0x61, 0x62, 0x10, 0x09, 0x12, 0x08, 0x0a, 0x04, 0x4a, 0x44, 0x42, 0x43, 0x10, + 0x0a, 0x12, 0x0c, 0x0a, 0x08, 0x52, 0x61, 0x7a, 0x6f, 0x72, 0x50, 0x61, 0x79, 0x10, 0x0b, 0x12, + 0x0c, 0x0a, 0x08, 0x53, 0x65, 0x6e, 0x64, 0x47, 0x72, 0x69, 0x64, 0x10, 0x0c, 0x12, 0x09, 0x0a, + 0x05, 0x53, 0x6c, 0x61, 0x63, 0x6b, 0x10, 0x0d, 0x12, 0x0a, 0x0a, 0x06, 0x53, 0x71, 0x75, 0x61, + 0x72, 0x65, 0x10, 0x0e, 0x12, 0x0e, 0x0a, 0x0a, 0x50, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x4b, + 0x65, 0x79, 0x10, 0x0f, 0x12, 0x0a, 0x0a, 0x06, 0x53, 0x74, 0x72, 0x69, 0x70, 0x65, 0x10, 0x10, + 0x12, 0x07, 0x0a, 0x03, 0x55, 0x52, 0x49, 0x10, 0x11, 0x12, 0x0b, 0x0a, 0x07, 0x44, 0x72, 0x6f, + 0x70, 0x62, 0x6f, 0x78, 0x10, 0x12, 0x12, 0x0a, 0x0a, 0x06, 0x48, 0x65, 0x72, 0x6f, 0x6b, 0x75, + 0x10, 0x13, 0x12, 0x0d, 0x0a, 0x09, 0x4d, 0x61, 0x69, 0x6c, 0x63, 0x68, 0x69, 0x6d, 0x70, 0x10, + 0x14, 0x12, 0x08, 0x0a, 0x04, 0x4f, 0x6b, 0x74, 0x61, 0x10, 0x15, 0x12, 0x0c, 0x0a, 0x08, 0x4f, + 0x6e, 0x65, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x10, 0x16, 0x12, 0x12, 0x0a, 0x0e, 0x50, 0x69, 0x76, + 0x6f, 0x74, 0x61, 0x6c, 0x54, 0x72, 0x61, 0x63, 0x6b, 0x65, 0x72, 0x10, 0x17, 0x12, 0x0d, 0x0a, + 0x09, 0x53, 0x71, 0x75, 0x61, 0x72, 0x65, 0x41, 0x70, 0x70, 0x10, 0x19, 0x12, 0x0a, 0x0a, 0x06, + 0x54, 0x77, 0x69, 0x6c, 0x69, 0x6f, 0x10, 0x1a, 0x12, 0x08, 0x0a, 0x04, 0x54, 0x65, 0x73, 0x74, + 0x10, 0x1b, 0x12, 0x0c, 0x0a, 0x08, 0x54, 0x72, 0x61, 0x76, 0x69, 0x73, 0x43, 0x49, 0x10, 0x1d, + 0x12, 0x10, 0x0a, 0x0c, 0x53, 0x6c, 0x61, 0x63, 0x6b, 0x57, 0x65, 0x62, 0x68, 0x6f, 0x6f, 0x6b, + 0x10, 0x1e, 0x12, 0x0f, 0x0a, 0x0b, 0x50, 0x61, 0x79, 0x70, 0x61, 0x6c, 0x4f, 0x61, 0x75, 0x74, + 0x68, 0x10, 0x1f, 0x12, 0x13, 0x0a, 0x0f, 0x50, 0x61, 0x67, 0x65, 0x72, 0x44, 0x75, 0x74, 0x79, + 0x41, 0x70, 0x69, 0x4b, 0x65, 0x79, 0x10, 0x20, 0x12, 0x0c, 0x0a, 0x08, 0x46, 0x69, 0x72, 0x65, + 0x62, 0x61, 0x73, 0x65, 0x10, 0x21, 0x12, 0x0b, 0x0a, 0x07, 0x4d, 0x61, 0x69, 0x6c, 0x67, 0x75, + 0x6e, 0x10, 0x22, 0x12, 0x0b, 0x0a, 0x07, 0x48, 0x75, 0x62, 0x53, 0x70, 0x6f, 0x74, 0x10, 0x23, + 0x12, 0x0d, 0x0a, 0x09, 0x47, 0x69, 0x74, 0x48, 0x75, 0x62, 0x41, 0x70, 0x70, 0x10, 0x24, 0x12, + 0x0c, 0x0a, 0x08, 0x43, 0x69, 0x72, 0x63, 0x6c, 0x65, 0x43, 0x49, 0x10, 0x25, 0x12, 0x0c, 0x0a, + 0x08, 0x57, 0x70, 0x45, 0x6e, 0x67, 0x69, 0x6e, 0x65, 0x10, 0x26, 0x12, 0x10, 0x0a, 0x0c, 0x44, + 0x61, 0x74, 0x61, 0x64, 0x6f, 0x67, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x10, 0x27, 0x12, 0x11, 0x0a, + 0x0d, 0x46, 0x61, 0x63, 0x65, 0x62, 0x6f, 0x6f, 0x6b, 0x4f, 0x41, 0x75, 0x74, 0x68, 0x10, 0x28, + 0x12, 0x1c, 0x0a, 0x18, 0x41, 0x73, 0x61, 0x6e, 0x61, 0x50, 0x65, 0x72, 0x73, 0x6f, 0x6e, 0x61, + 0x6c, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x10, 0x29, 0x12, 0x13, + 0x0a, 0x0f, 0x41, 0x6d, 0x70, 0x6c, 0x69, 0x74, 0x75, 0x64, 0x65, 0x41, 0x70, 0x69, 0x4b, 0x65, + 0x79, 0x10, 0x2a, 0x12, 0x14, 0x0a, 0x10, 0x42, 0x69, 0x74, 0x4c, 0x79, 0x41, 0x63, 0x63, 0x65, + 0x73, 0x73, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x10, 0x2b, 0x12, 0x12, 0x0a, 0x0e, 0x43, 0x61, 0x6c, + 0x65, 0x6e, 0x64, 0x6c, 0x79, 0x41, 0x70, 0x69, 0x4b, 0x65, 0x79, 0x10, 0x2c, 0x12, 0x11, 0x0a, + 0x0d, 0x5a, 0x61, 0x70, 0x69, 0x65, 0x72, 0x57, 0x65, 0x62, 0x68, 0x6f, 0x6f, 0x6b, 0x10, 0x2d, + 0x12, 0x11, 0x0a, 0x0d, 0x59, 0x6f, 0x75, 0x74, 0x75, 0x62, 0x65, 0x41, 0x70, 0x69, 0x4b, 0x65, + 0x79, 0x10, 0x2e, 0x12, 0x14, 0x0a, 0x10, 0x53, 0x61, 0x6c, 0x65, 0x73, 0x66, 0x6f, 0x72, 0x63, + 0x65, 0x4f, 0x61, 0x75, 0x74, 0x68, 0x32, 0x10, 0x2f, 0x12, 0x14, 0x0a, 0x10, 0x54, 0x77, 0x69, + 0x74, 0x74, 0x65, 0x72, 0x41, 0x70, 0x69, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x10, 0x30, 0x12, + 0x0c, 0x0a, 0x08, 0x4e, 0x70, 0x6d, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x10, 0x31, 0x12, 0x1a, 0x0a, + 0x16, 0x4e, 0x65, 0x77, 0x52, 0x65, 0x6c, 0x69, 0x63, 0x50, 0x65, 0x72, 0x73, 0x6f, 0x6e, 0x61, + 0x6c, 0x41, 0x70, 0x69, 0x4b, 0x65, 0x79, 0x10, 0x32, 0x12, 0x12, 0x0a, 0x0e, 0x41, 0x69, 0x72, + 0x74, 0x61, 0x62, 0x6c, 0x65, 0x41, 0x70, 0x69, 0x4b, 0x65, 0x79, 0x10, 0x33, 0x12, 0x0f, 0x0a, + 0x0b, 0x41, 0x6b, 0x61, 0x6d, 0x61, 0x69, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x10, 0x34, 0x12, 0x0d, + 0x0a, 0x09, 0x41, 0x6d, 0x61, 0x7a, 0x6f, 0x6e, 0x4d, 0x57, 0x53, 0x10, 0x35, 0x12, 0x0e, 0x0a, + 0x0a, 0x4b, 0x75, 0x62, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x10, 0x36, 0x12, 0x0e, 0x0a, + 0x0a, 0x41, 0x75, 0x74, 0x68, 0x30, 0x6f, 0x61, 0x75, 0x74, 0x68, 0x10, 0x37, 0x12, 0x0c, 0x0a, + 0x08, 0x42, 0x69, 0x74, 0x66, 0x69, 0x6e, 0x65, 0x78, 0x10, 0x38, 0x12, 0x0c, 0x0a, 0x08, 0x43, + 0x6c, 0x61, 0x72, 0x69, 0x66, 0x61, 0x69, 0x10, 0x39, 0x12, 0x1a, 0x0a, 0x16, 0x43, 0x6c, 0x6f, + 0x75, 0x64, 0x66, 0x6c, 0x61, 0x72, 0x65, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x41, 0x70, 0x69, + 0x4b, 0x65, 0x79, 0x10, 0x3a, 0x12, 0x13, 0x0a, 0x0f, 0x43, 0x6c, 0x6f, 0x75, 0x64, 0x66, 0x6c, + 0x61, 0x72, 0x65, 0x43, 0x61, 0x4b, 0x65, 0x79, 0x10, 0x3b, 0x12, 0x0d, 0x0a, 0x09, 0x43, 0x6f, + 0x6e, 0x66, 0x6c, 0x75, 0x65, 0x6e, 0x74, 0x10, 0x3c, 0x12, 0x16, 0x0a, 0x12, 0x43, 0x6f, 0x6e, + 0x74, 0x65, 0x6e, 0x74, 0x66, 0x75, 0x6c, 0x44, 0x65, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x79, 0x10, + 0x3d, 0x12, 0x13, 0x0a, 0x0f, 0x44, 0x61, 0x74, 0x61, 0x62, 0x72, 0x69, 0x63, 0x6b, 0x73, 0x54, + 0x6f, 0x6b, 0x65, 0x6e, 0x10, 0x3e, 0x12, 0x16, 0x0a, 0x12, 0x44, 0x69, 0x67, 0x69, 0x74, 0x61, + 0x6c, 0x4f, 0x63, 0x65, 0x61, 0x6e, 0x53, 0x70, 0x61, 0x63, 0x65, 0x73, 0x10, 0x3f, 0x12, 0x15, + 0x0a, 0x11, 0x44, 0x69, 0x67, 0x69, 0x74, 0x61, 0x6c, 0x4f, 0x63, 0x65, 0x61, 0x6e, 0x54, 0x6f, + 0x6b, 0x65, 0x6e, 0x10, 0x40, 0x12, 0x13, 0x0a, 0x0f, 0x44, 0x69, 0x73, 0x63, 0x6f, 0x72, 0x64, + 0x42, 0x6f, 0x74, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x10, 0x41, 0x12, 0x12, 0x0a, 0x0e, 0x44, 0x69, + 0x73, 0x63, 0x6f, 0x72, 0x64, 0x57, 0x65, 0x62, 0x68, 0x6f, 0x6f, 0x6b, 0x10, 0x42, 0x12, 0x12, + 0x0a, 0x0a, 0x45, 0x74, 0x73, 0x79, 0x41, 0x70, 0x69, 0x4b, 0x65, 0x79, 0x10, 0x43, 0x1a, 0x02, + 0x08, 0x01, 0x12, 0x17, 0x0a, 0x13, 0x46, 0x61, 0x73, 0x74, 0x6c, 0x79, 0x50, 0x65, 0x72, 0x73, + 0x6f, 0x6e, 0x61, 0x6c, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x10, 0x44, 0x12, 0x10, 0x0a, 0x0c, 0x47, + 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x4f, 0x61, 0x75, 0x74, 0x68, 0x32, 0x10, 0x45, 0x12, 0x0d, 0x0a, + 0x09, 0x52, 0x65, 0x43, 0x41, 0x50, 0x54, 0x43, 0x48, 0x41, 0x10, 0x46, 0x12, 0x10, 0x0a, 0x0c, + 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x41, 0x70, 0x69, 0x4b, 0x65, 0x79, 0x10, 0x47, 0x12, 0x0a, + 0x0a, 0x06, 0x48, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x10, 0x48, 0x12, 0x13, 0x0a, 0x0f, 0x49, 0x62, + 0x6d, 0x43, 0x6c, 0x6f, 0x75, 0x64, 0x55, 0x73, 0x65, 0x72, 0x4b, 0x65, 0x79, 0x10, 0x49, 0x12, + 0x0b, 0x0a, 0x07, 0x4e, 0x65, 0x74, 0x6c, 0x69, 0x66, 0x79, 0x10, 0x4a, 0x12, 0x0a, 0x0a, 0x06, + 0x56, 0x6f, 0x6e, 0x61, 0x67, 0x65, 0x10, 0x4b, 0x12, 0x10, 0x0a, 0x0c, 0x45, 0x71, 0x75, 0x69, + 0x6e, 0x69, 0x78, 0x4f, 0x61, 0x75, 0x74, 0x68, 0x10, 0x4c, 0x12, 0x0c, 0x0a, 0x08, 0x50, 0x61, + 0x79, 0x73, 0x74, 0x61, 0x63, 0x6b, 0x10, 0x4d, 0x12, 0x0e, 0x0a, 0x0a, 0x50, 0x6c, 0x61, 0x69, + 0x64, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x10, 0x4e, 0x12, 0x0c, 0x0a, 0x08, 0x50, 0x6c, 0x61, 0x69, + 0x64, 0x4b, 0x65, 0x79, 0x10, 0x4f, 0x12, 0x09, 0x0a, 0x05, 0x50, 0x6c, 0x69, 0x76, 0x6f, 0x10, + 0x50, 0x12, 0x0c, 0x0a, 0x08, 0x50, 0x6f, 0x73, 0x74, 0x6d, 0x61, 0x72, 0x6b, 0x10, 0x51, 0x12, + 0x14, 0x0a, 0x10, 0x50, 0x75, 0x62, 0x4e, 0x75, 0x62, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, + 0x4b, 0x65, 0x79, 0x10, 0x52, 0x12, 0x19, 0x0a, 0x15, 0x50, 0x75, 0x62, 0x4e, 0x75, 0x62, 0x53, + 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x4b, 0x65, 0x79, 0x10, 0x53, + 0x12, 0x14, 0x0a, 0x10, 0x50, 0x75, 0x73, 0x68, 0x65, 0x72, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, + 0x6c, 0x4b, 0x65, 0x79, 0x10, 0x54, 0x12, 0x0f, 0x0a, 0x0b, 0x53, 0x63, 0x61, 0x6c, 0x65, 0x77, + 0x61, 0x79, 0x4b, 0x65, 0x79, 0x10, 0x55, 0x12, 0x10, 0x0a, 0x0c, 0x53, 0x65, 0x6e, 0x64, 0x69, + 0x6e, 0x42, 0x6c, 0x75, 0x65, 0x56, 0x32, 0x10, 0x56, 0x12, 0x0f, 0x0a, 0x0b, 0x53, 0x65, 0x6e, + 0x74, 0x72, 0x79, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x10, 0x57, 0x12, 0x0d, 0x0a, 0x09, 0x53, 0x68, + 0x6f, 0x64, 0x61, 0x6e, 0x4b, 0x65, 0x79, 0x10, 0x58, 0x12, 0x0b, 0x0a, 0x07, 0x53, 0x6e, 0x79, + 0x6b, 0x4b, 0x65, 0x79, 0x10, 0x59, 0x12, 0x0e, 0x0a, 0x0a, 0x53, 0x70, 0x6f, 0x74, 0x69, 0x66, + 0x79, 0x4b, 0x65, 0x79, 0x10, 0x5a, 0x12, 0x14, 0x0a, 0x10, 0x54, 0x65, 0x6c, 0x65, 0x67, 0x72, + 0x61, 0x6d, 0x42, 0x6f, 0x74, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x10, 0x5b, 0x12, 0x13, 0x0a, 0x0f, + 0x54, 0x65, 0x6e, 0x63, 0x65, 0x6e, 0x74, 0x43, 0x6c, 0x6f, 0x75, 0x64, 0x4b, 0x65, 0x79, 0x10, + 0x5c, 0x12, 0x1f, 0x0a, 0x1b, 0x54, 0x65, 0x72, 0x72, 0x61, 0x66, 0x6f, 0x72, 0x6d, 0x43, 0x6c, + 0x6f, 0x75, 0x64, 0x50, 0x65, 0x72, 0x73, 0x6f, 0x6e, 0x61, 0x6c, 0x54, 0x6f, 0x6b, 0x65, 0x6e, + 0x10, 0x5d, 0x12, 0x10, 0x0a, 0x0c, 0x54, 0x72, 0x65, 0x6c, 0x6c, 0x6f, 0x41, 0x70, 0x69, 0x4b, + 0x65, 0x79, 0x10, 0x5e, 0x12, 0x0e, 0x0a, 0x0a, 0x5a, 0x65, 0x6e, 0x64, 0x65, 0x73, 0x6b, 0x41, + 0x70, 0x69, 0x10, 0x5f, 0x12, 0x12, 0x0a, 0x0e, 0x4d, 0x61, 0x78, 0x4d, 0x69, 0x6e, 0x64, 0x4c, + 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x10, 0x60, 0x12, 0x1a, 0x0a, 0x16, 0x41, 0x69, 0x72, 0x74, + 0x61, 0x62, 0x6c, 0x65, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x41, 0x70, 0x69, 0x4b, + 0x65, 0x79, 0x10, 0x61, 0x12, 0x0e, 0x0a, 0x0a, 0x41, 0x73, 0x61, 0x6e, 0x61, 0x4f, 0x61, 0x75, + 0x74, 0x68, 0x10, 0x62, 0x12, 0x0c, 0x0a, 0x08, 0x52, 0x61, 0x70, 0x69, 0x64, 0x41, 0x70, 0x69, + 0x10, 0x63, 0x12, 0x16, 0x0a, 0x12, 0x43, 0x6c, 0x6f, 0x75, 0x64, 0x66, 0x6c, 0x61, 0x72, 0x65, + 0x41, 0x70, 0x69, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x10, 0x64, 0x12, 0x09, 0x0a, 0x05, 0x57, 0x65, + 0x62, 0x65, 0x78, 0x10, 0x65, 0x12, 0x1a, 0x0a, 0x16, 0x46, 0x69, 0x72, 0x65, 0x62, 0x61, 0x73, + 0x65, 0x43, 0x6c, 0x6f, 0x75, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x69, 0x6e, 0x67, 0x10, + 0x66, 0x12, 0x21, 0x0a, 0x1d, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x66, 0x75, 0x6c, 0x50, + 0x65, 0x72, 0x73, 0x6f, 0x6e, 0x61, 0x6c, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x54, 0x6f, 0x6b, + 0x65, 0x6e, 0x10, 0x67, 0x12, 0x0a, 0x0a, 0x06, 0x4d, 0x61, 0x70, 0x42, 0x6f, 0x78, 0x10, 0x68, + 0x12, 0x14, 0x0a, 0x10, 0x4d, 0x61, 0x69, 0x6c, 0x4a, 0x65, 0x74, 0x42, 0x61, 0x73, 0x69, 0x63, + 0x41, 0x75, 0x74, 0x68, 0x10, 0x69, 0x12, 0x0e, 0x0a, 0x0a, 0x4d, 0x61, 0x69, 0x6c, 0x4a, 0x65, + 0x74, 0x53, 0x4d, 0x53, 0x10, 0x6a, 0x12, 0x11, 0x0a, 0x0d, 0x48, 0x75, 0x62, 0x53, 0x70, 0x6f, + 0x74, 0x41, 0x70, 0x69, 0x4b, 0x65, 0x79, 0x10, 0x6b, 0x12, 0x10, 0x0a, 0x0c, 0x48, 0x75, 0x62, + 0x53, 0x70, 0x6f, 0x74, 0x4f, 0x61, 0x75, 0x74, 0x68, 0x10, 0x6c, 0x12, 0x0b, 0x0a, 0x07, 0x53, + 0x73, 0x6c, 0x4d, 0x61, 0x74, 0x65, 0x10, 0x6d, 0x12, 0x1b, 0x0a, 0x17, 0x41, 0x75, 0x74, 0x68, + 0x30, 0x4d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x41, 0x70, 0x69, 0x54, 0x6f, + 0x6b, 0x65, 0x6e, 0x10, 0x6e, 0x12, 0x0f, 0x0a, 0x0b, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x42, 0x69, 0x72, 0x64, 0x10, 0x6f, 0x12, 0x10, 0x0a, 0x0c, 0x45, 0x6c, 0x61, 0x73, 0x74, 0x69, + 0x63, 0x45, 0x6d, 0x61, 0x69, 0x6c, 0x10, 0x70, 0x12, 0x1c, 0x0a, 0x18, 0x46, 0x69, 0x67, 0x6d, + 0x61, 0x50, 0x65, 0x72, 0x73, 0x6f, 0x6e, 0x61, 0x6c, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x54, + 0x6f, 0x6b, 0x65, 0x6e, 0x10, 0x71, 0x12, 0x19, 0x0a, 0x15, 0x4d, 0x69, 0x63, 0x72, 0x6f, 0x73, + 0x6f, 0x66, 0x74, 0x54, 0x65, 0x61, 0x6d, 0x73, 0x57, 0x65, 0x62, 0x68, 0x6f, 0x6f, 0x6b, 0x10, + 0x72, 0x12, 0x0d, 0x0a, 0x09, 0x47, 0x69, 0x74, 0x48, 0x75, 0x62, 0x4f, 0x6c, 0x64, 0x10, 0x73, + 0x12, 0x0f, 0x0a, 0x0b, 0x56, 0x75, 0x6c, 0x74, 0x72, 0x41, 0x70, 0x69, 0x4b, 0x65, 0x79, 0x10, + 0x74, 0x12, 0x0c, 0x0a, 0x08, 0x50, 0x65, 0x70, 0x69, 0x70, 0x6f, 0x73, 0x74, 0x10, 0x75, 0x12, + 0x0b, 0x0a, 0x07, 0x50, 0x6f, 0x73, 0x74, 0x6d, 0x61, 0x6e, 0x10, 0x76, 0x12, 0x11, 0x0a, 0x0d, + 0x43, 0x6c, 0x6f, 0x75, 0x64, 0x73, 0x69, 0x67, 0x68, 0x74, 0x4b, 0x65, 0x79, 0x10, 0x77, 0x12, + 0x0d, 0x0a, 0x09, 0x4a, 0x69, 0x72, 0x61, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x10, 0x78, 0x12, 0x0f, + 0x0a, 0x0b, 0x4e, 0x65, 0x78, 0x6d, 0x6f, 0x41, 0x70, 0x69, 0x4b, 0x65, 0x79, 0x10, 0x79, 0x12, + 0x11, 0x0a, 0x0d, 0x53, 0x65, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x41, 0x70, 0x69, 0x4b, 0x65, 0x79, + 0x10, 0x7a, 0x12, 0x10, 0x0a, 0x0c, 0x53, 0x75, 0x6d, 0x6f, 0x4c, 0x6f, 0x67, 0x69, 0x63, 0x4b, + 0x65, 0x79, 0x10, 0x7b, 0x12, 0x14, 0x0a, 0x10, 0x50, 0x75, 0x73, 0x68, 0x42, 0x75, 0x6c, 0x6c, + 0x65, 0x74, 0x41, 0x70, 0x69, 0x4b, 0x65, 0x79, 0x10, 0x7c, 0x12, 0x16, 0x0a, 0x12, 0x41, 0x69, + 0x72, 0x62, 0x72, 0x61, 0x6b, 0x65, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x4b, 0x65, 0x79, + 0x10, 0x7d, 0x12, 0x13, 0x0a, 0x0f, 0x41, 0x69, 0x72, 0x62, 0x72, 0x61, 0x6b, 0x65, 0x55, 0x73, + 0x65, 0x72, 0x4b, 0x65, 0x79, 0x10, 0x7e, 0x12, 0x17, 0x0a, 0x13, 0x50, 0x65, 0x6e, 0x64, 0x6f, + 0x49, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4b, 0x65, 0x79, 0x10, 0x7f, + 0x12, 0x1f, 0x0a, 0x1a, 0x53, 0x70, 0x6c, 0x75, 0x6e, 0x6b, 0x4f, 0x62, 0x65, 0x72, 0x73, 0x65, + 0x72, 0x76, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x10, 0x80, + 0x01, 0x12, 0x12, 0x0a, 0x0d, 0x4c, 0x6f, 0x6b, 0x61, 0x6c, 0x69, 0x73, 0x65, 0x54, 0x6f, 0x6b, + 0x65, 0x6e, 0x10, 0x81, 0x01, 0x12, 0x11, 0x0a, 0x0c, 0x43, 0x61, 0x6c, 0x65, 0x6e, 0x64, 0x61, + 0x72, 0x69, 0x66, 0x69, 0x63, 0x10, 0x82, 0x01, 0x12, 0x0e, 0x0a, 0x09, 0x4a, 0x75, 0x6d, 0x70, + 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x10, 0x83, 0x01, 0x12, 0x0c, 0x0a, 0x07, 0x49, 0x70, 0x53, 0x74, + 0x61, 0x63, 0x6b, 0x10, 0x85, 0x01, 0x12, 0x0b, 0x0a, 0x06, 0x4e, 0x6f, 0x74, 0x69, 0x6f, 0x6e, + 0x10, 0x86, 0x01, 0x12, 0x0c, 0x0a, 0x07, 0x44, 0x72, 0x6f, 0x6e, 0x65, 0x43, 0x49, 0x10, 0x87, + 0x01, 0x12, 0x0c, 0x0a, 0x07, 0x41, 0x64, 0x6f, 0x62, 0x65, 0x49, 0x4f, 0x10, 0x88, 0x01, 0x12, + 0x0f, 0x0a, 0x0a, 0x54, 0x77, 0x65, 0x6c, 0x76, 0x65, 0x44, 0x61, 0x74, 0x61, 0x10, 0x89, 0x01, + 0x12, 0x0e, 0x0a, 0x09, 0x44, 0x37, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x10, 0x8a, 0x01, + 0x12, 0x10, 0x0a, 0x0b, 0x53, 0x63, 0x72, 0x61, 0x70, 0x69, 0x6e, 0x67, 0x42, 0x65, 0x65, 0x10, + 0x8b, 0x01, 0x12, 0x0b, 0x0a, 0x06, 0x4b, 0x65, 0x65, 0x6e, 0x49, 0x4f, 0x10, 0x8c, 0x01, 0x12, + 0x0d, 0x0a, 0x08, 0x57, 0x61, 0x6b, 0x61, 0x74, 0x69, 0x6d, 0x65, 0x10, 0x8d, 0x01, 0x12, 0x0e, + 0x0a, 0x09, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x6b, 0x69, 0x74, 0x65, 0x10, 0x8e, 0x01, 0x12, 0x0d, + 0x0a, 0x08, 0x56, 0x65, 0x72, 0x69, 0x6d, 0x61, 0x69, 0x6c, 0x10, 0x8f, 0x01, 0x12, 0x0f, 0x0a, + 0x0a, 0x5a, 0x65, 0x72, 0x6f, 0x62, 0x6f, 0x75, 0x6e, 0x63, 0x65, 0x10, 0x90, 0x01, 0x12, 0x11, + 0x0a, 0x0c, 0x4d, 0x61, 0x69, 0x6c, 0x62, 0x6f, 0x78, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x10, 0x91, + 0x01, 0x12, 0x0f, 0x0a, 0x0a, 0x46, 0x61, 0x73, 0x74, 0x73, 0x70, 0x72, 0x69, 0x6e, 0x67, 0x10, + 0x92, 0x01, 0x12, 0x0b, 0x0a, 0x06, 0x50, 0x61, 0x64, 0x64, 0x6c, 0x65, 0x10, 0x93, 0x01, 0x12, + 0x0b, 0x0a, 0x06, 0x53, 0x65, 0x6c, 0x6c, 0x66, 0x79, 0x10, 0x94, 0x01, 0x12, 0x0c, 0x0a, 0x07, + 0x46, 0x69, 0x78, 0x65, 0x72, 0x49, 0x4f, 0x10, 0x95, 0x01, 0x12, 0x0e, 0x0a, 0x09, 0x42, 0x75, + 0x74, 0x74, 0x65, 0x72, 0x43, 0x4d, 0x53, 0x10, 0x96, 0x01, 0x12, 0x0b, 0x0a, 0x06, 0x54, 0x61, + 0x78, 0x6a, 0x61, 0x72, 0x10, 0x97, 0x01, 0x12, 0x0c, 0x0a, 0x07, 0x41, 0x76, 0x61, 0x6c, 0x61, + 0x72, 0x61, 0x10, 0x98, 0x01, 0x12, 0x0e, 0x0a, 0x09, 0x48, 0x65, 0x6c, 0x70, 0x73, 0x63, 0x6f, + 0x75, 0x74, 0x10, 0x99, 0x01, 0x12, 0x10, 0x0a, 0x0b, 0x45, 0x6c, 0x61, 0x73, 0x74, 0x69, 0x63, + 0x50, 0x61, 0x74, 0x68, 0x10, 0x9a, 0x01, 0x12, 0x0b, 0x0a, 0x06, 0x5a, 0x65, 0x70, 0x6c, 0x69, + 0x6e, 0x10, 0x9b, 0x01, 0x12, 0x0d, 0x0a, 0x08, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x63, 0x6f, 0x6d, + 0x10, 0x9c, 0x01, 0x12, 0x0d, 0x0a, 0x08, 0x4d, 0x61, 0x69, 0x6c, 0x6d, 0x6f, 0x64, 0x6f, 0x10, + 0x9d, 0x01, 0x12, 0x0c, 0x0a, 0x07, 0x43, 0x61, 0x6e, 0x6e, 0x79, 0x49, 0x6f, 0x10, 0x9e, 0x01, + 0x12, 0x0e, 0x0a, 0x09, 0x50, 0x69, 0x70, 0x65, 0x64, 0x72, 0x69, 0x76, 0x65, 0x10, 0x9f, 0x01, + 0x12, 0x0b, 0x0a, 0x06, 0x56, 0x65, 0x72, 0x63, 0x65, 0x6c, 0x10, 0xa0, 0x01, 0x12, 0x0f, 0x0a, + 0x0a, 0x50, 0x6f, 0x73, 0x74, 0x68, 0x6f, 0x67, 0x41, 0x70, 0x70, 0x10, 0xa1, 0x01, 0x12, 0x11, + 0x0a, 0x0c, 0x53, 0x69, 0x6e, 0x63, 0x68, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x10, 0xa2, + 0x01, 0x12, 0x0d, 0x0a, 0x08, 0x41, 0x79, 0x72, 0x73, 0x68, 0x61, 0x72, 0x65, 0x10, 0xa3, 0x01, + 0x12, 0x0f, 0x0a, 0x0a, 0x48, 0x65, 0x6c, 0x70, 0x43, 0x72, 0x75, 0x6e, 0x63, 0x68, 0x10, 0xa4, + 0x01, 0x12, 0x0e, 0x0a, 0x09, 0x4c, 0x69, 0x76, 0x65, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x10, 0xa5, + 0x01, 0x12, 0x0b, 0x0a, 0x06, 0x42, 0x65, 0x61, 0x6d, 0x65, 0x72, 0x10, 0xa6, 0x01, 0x12, 0x11, + 0x0a, 0x0c, 0x57, 0x65, 0x43, 0x68, 0x61, 0x74, 0x41, 0x70, 0x70, 0x4b, 0x65, 0x79, 0x10, 0xa7, + 0x01, 0x12, 0x12, 0x0a, 0x0d, 0x4c, 0x69, 0x6e, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x69, + 0x6e, 0x67, 0x10, 0xa8, 0x01, 0x12, 0x14, 0x0a, 0x0f, 0x55, 0x62, 0x65, 0x72, 0x53, 0x65, 0x72, + 0x76, 0x65, 0x72, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x10, 0xa9, 0x01, 0x12, 0x14, 0x0a, 0x0f, 0x41, + 0x6c, 0x67, 0x6f, 0x6c, 0x69, 0x61, 0x41, 0x64, 0x6d, 0x69, 0x6e, 0x4b, 0x65, 0x79, 0x10, 0xaa, + 0x01, 0x12, 0x10, 0x0a, 0x0b, 0x46, 0x75, 0x6c, 0x6c, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, + 0x10, 0xab, 0x01, 0x12, 0x0d, 0x0a, 0x08, 0x4d, 0x61, 0x6e, 0x64, 0x72, 0x69, 0x6c, 0x6c, 0x10, + 0xac, 0x01, 0x12, 0x10, 0x0a, 0x0b, 0x46, 0x6c, 0x75, 0x74, 0x74, 0x65, 0x72, 0x77, 0x61, 0x76, + 0x65, 0x10, 0xad, 0x01, 0x12, 0x1c, 0x0a, 0x17, 0x4d, 0x61, 0x74, 0x74, 0x65, 0x72, 0x6d, 0x6f, + 0x73, 0x74, 0x50, 0x65, 0x72, 0x73, 0x6f, 0x6e, 0x61, 0x6c, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x10, + 0xae, 0x01, 0x12, 0x0d, 0x0a, 0x08, 0x43, 0x6c, 0x6f, 0x75, 0x64, 0x61, 0x6e, 0x74, 0x10, 0xaf, + 0x01, 0x12, 0x0f, 0x0a, 0x0a, 0x4c, 0x69, 0x6e, 0x65, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x10, + 0xb0, 0x01, 0x12, 0x0e, 0x0a, 0x09, 0x4c, 0x69, 0x6e, 0x65, 0x61, 0x72, 0x41, 0x50, 0x49, 0x10, + 0xb1, 0x01, 0x12, 0x0c, 0x0a, 0x07, 0x55, 0x62, 0x69, 0x64, 0x6f, 0x74, 0x73, 0x10, 0xb2, 0x01, + 0x12, 0x0d, 0x0a, 0x08, 0x41, 0x6e, 0x79, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x10, 0xb3, 0x01, 0x12, + 0x0b, 0x0a, 0x06, 0x44, 0x77, 0x6f, 0x6c, 0x6c, 0x61, 0x10, 0xb4, 0x01, 0x12, 0x1b, 0x0a, 0x16, + 0x41, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x6f, 0x72, 0x79, 0x41, 0x63, 0x63, 0x65, 0x73, + 0x73, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x10, 0xb5, 0x01, 0x12, 0x0a, 0x0a, 0x05, 0x53, 0x75, 0x72, + 0x67, 0x65, 0x10, 0xb6, 0x01, 0x12, 0x0e, 0x0a, 0x09, 0x53, 0x70, 0x61, 0x72, 0x6b, 0x70, 0x6f, + 0x73, 0x74, 0x10, 0xb7, 0x01, 0x12, 0x0f, 0x0a, 0x0a, 0x47, 0x6f, 0x43, 0x61, 0x72, 0x64, 0x6c, + 0x65, 0x73, 0x73, 0x10, 0xb8, 0x01, 0x12, 0x0b, 0x0a, 0x06, 0x43, 0x6f, 0x64, 0x61, 0x63, 0x79, + 0x10, 0xb9, 0x01, 0x12, 0x0b, 0x0a, 0x06, 0x4b, 0x72, 0x61, 0x6b, 0x65, 0x6e, 0x10, 0xba, 0x01, + 0x12, 0x0d, 0x0a, 0x08, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x6f, 0x75, 0x74, 0x10, 0xbb, 0x01, 0x12, + 0x0b, 0x0a, 0x06, 0x4b, 0x61, 0x69, 0x72, 0x6f, 0x73, 0x10, 0xbc, 0x01, 0x12, 0x11, 0x0a, 0x0c, + 0x43, 0x6c, 0x6f, 0x63, 0x6b, 0x77, 0x6f, 0x72, 0x6b, 0x53, 0x4d, 0x53, 0x10, 0xbd, 0x01, 0x12, + 0x0e, 0x0a, 0x09, 0x41, 0x74, 0x6c, 0x61, 0x73, 0x73, 0x69, 0x61, 0x6e, 0x10, 0xbe, 0x01, 0x12, + 0x11, 0x0a, 0x0c, 0x4c, 0x61, 0x75, 0x6e, 0x63, 0x68, 0x44, 0x61, 0x72, 0x6b, 0x6c, 0x79, 0x10, + 0xbf, 0x01, 0x12, 0x0e, 0x0a, 0x09, 0x43, 0x6f, 0x76, 0x65, 0x72, 0x61, 0x6c, 0x6c, 0x73, 0x10, + 0xc0, 0x01, 0x12, 0x0b, 0x0a, 0x06, 0x4c, 0x69, 0x6e, 0x6f, 0x64, 0x65, 0x10, 0xc1, 0x01, 0x12, + 0x0a, 0x0a, 0x05, 0x57, 0x65, 0x50, 0x61, 0x79, 0x10, 0xc2, 0x01, 0x12, 0x10, 0x0a, 0x0b, 0x50, + 0x6c, 0x61, 0x6e, 0x65, 0x74, 0x53, 0x63, 0x61, 0x6c, 0x65, 0x10, 0xc3, 0x01, 0x12, 0x0c, 0x0a, + 0x07, 0x44, 0x6f, 0x70, 0x70, 0x6c, 0x65, 0x72, 0x10, 0xc4, 0x01, 0x12, 0x0a, 0x0a, 0x05, 0x41, + 0x67, 0x6f, 0x72, 0x61, 0x10, 0xc5, 0x01, 0x12, 0x0c, 0x0a, 0x07, 0x53, 0x61, 0x6d, 0x73, 0x61, + 0x72, 0x61, 0x10, 0xc6, 0x01, 0x12, 0x0c, 0x0a, 0x07, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x49, 0x4f, + 0x10, 0xc7, 0x01, 0x12, 0x0d, 0x0a, 0x08, 0x52, 0x75, 0x62, 0x79, 0x47, 0x65, 0x6d, 0x73, 0x10, + 0xc8, 0x01, 0x12, 0x0b, 0x0a, 0x06, 0x4f, 0x70, 0x65, 0x6e, 0x41, 0x49, 0x10, 0xc9, 0x01, 0x12, + 0x12, 0x0a, 0x0d, 0x53, 0x75, 0x72, 0x76, 0x65, 0x79, 0x53, 0x70, 0x61, 0x72, 0x72, 0x6f, 0x77, + 0x10, 0xca, 0x01, 0x12, 0x0c, 0x0a, 0x07, 0x53, 0x69, 0x6d, 0x76, 0x6f, 0x6c, 0x79, 0x10, 0xcb, + 0x01, 0x12, 0x0e, 0x0a, 0x09, 0x53, 0x75, 0x72, 0x76, 0x69, 0x63, 0x61, 0x74, 0x65, 0x10, 0xcc, + 0x01, 0x12, 0x0d, 0x0a, 0x08, 0x4f, 0x6d, 0x6e, 0x69, 0x73, 0x65, 0x6e, 0x64, 0x10, 0xcd, 0x01, + 0x12, 0x0d, 0x0a, 0x08, 0x47, 0x72, 0x6f, 0x6f, 0x76, 0x65, 0x68, 0x71, 0x10, 0xce, 0x01, 0x12, + 0x0c, 0x0a, 0x07, 0x4e, 0x65, 0x77, 0x73, 0x61, 0x70, 0x69, 0x10, 0xcf, 0x01, 0x12, 0x0c, 0x0a, + 0x07, 0x43, 0x68, 0x61, 0x74, 0x62, 0x6f, 0x74, 0x10, 0xd0, 0x01, 0x12, 0x11, 0x0a, 0x0c, 0x43, + 0x6c, 0x69, 0x63, 0x6b, 0x53, 0x65, 0x6e, 0x64, 0x73, 0x6d, 0x73, 0x10, 0xd1, 0x01, 0x12, 0x0c, + 0x0a, 0x07, 0x47, 0x65, 0x74, 0x67, 0x69, 0x73, 0x74, 0x10, 0xd2, 0x01, 0x12, 0x0f, 0x0a, 0x0a, + 0x43, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x65, 0x72, 0x49, 0x4f, 0x10, 0xd3, 0x01, 0x12, 0x0c, 0x0a, + 0x07, 0x41, 0x70, 0x69, 0x44, 0x65, 0x63, 0x6b, 0x10, 0xd4, 0x01, 0x12, 0x0c, 0x0a, 0x07, 0x4e, + 0x66, 0x74, 0x70, 0x6f, 0x72, 0x74, 0x10, 0xd5, 0x01, 0x12, 0x0b, 0x0a, 0x06, 0x43, 0x6f, 0x70, + 0x70, 0x65, 0x72, 0x10, 0xd6, 0x01, 0x12, 0x0a, 0x0a, 0x05, 0x43, 0x6c, 0x6f, 0x73, 0x65, 0x10, + 0xd7, 0x01, 0x12, 0x11, 0x0a, 0x0c, 0x4d, 0x79, 0x66, 0x72, 0x65, 0x73, 0x68, 0x77, 0x6f, 0x72, + 0x6b, 0x73, 0x10, 0xd8, 0x01, 0x12, 0x0f, 0x0a, 0x0a, 0x53, 0x61, 0x6c, 0x65, 0x73, 0x66, 0x6c, + 0x61, 0x72, 0x65, 0x10, 0xd9, 0x01, 0x12, 0x0c, 0x0a, 0x07, 0x57, 0x65, 0x62, 0x66, 0x6c, 0x6f, + 0x77, 0x10, 0xda, 0x01, 0x12, 0x09, 0x0a, 0x04, 0x44, 0x75, 0x64, 0x61, 0x10, 0xdb, 0x01, 0x12, + 0x09, 0x0a, 0x04, 0x59, 0x65, 0x78, 0x74, 0x10, 0xdc, 0x01, 0x12, 0x11, 0x0a, 0x0c, 0x43, 0x6f, + 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x53, 0x74, 0x61, 0x63, 0x6b, 0x10, 0xdd, 0x01, 0x12, 0x0e, 0x0a, + 0x09, 0x53, 0x74, 0x6f, 0x72, 0x79, 0x62, 0x6c, 0x6f, 0x6b, 0x10, 0xde, 0x01, 0x12, 0x0d, 0x0a, + 0x08, 0x47, 0x72, 0x61, 0x70, 0x68, 0x43, 0x4d, 0x53, 0x10, 0xdf, 0x01, 0x12, 0x10, 0x0a, 0x0b, + 0x43, 0x68, 0x65, 0x63, 0x6b, 0x6d, 0x61, 0x72, 0x6b, 0x65, 0x74, 0x10, 0xe0, 0x01, 0x12, 0x0f, + 0x0a, 0x0a, 0x43, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x74, 0x6b, 0x69, 0x74, 0x10, 0xe1, 0x01, 0x12, + 0x11, 0x0a, 0x0c, 0x43, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x65, 0x72, 0x47, 0x75, 0x72, 0x75, 0x10, + 0xe2, 0x01, 0x12, 0x0c, 0x0a, 0x07, 0x4b, 0x61, 0x6c, 0x65, 0x79, 0x72, 0x61, 0x10, 0xe3, 0x01, + 0x12, 0x0f, 0x0a, 0x0a, 0x4d, 0x61, 0x69, 0x6c, 0x65, 0x72, 0x6c, 0x69, 0x74, 0x65, 0x10, 0xe4, + 0x01, 0x12, 0x0d, 0x0a, 0x08, 0x51, 0x75, 0x61, 0x6c, 0x61, 0x72, 0x6f, 0x6f, 0x10, 0xe5, 0x01, + 0x12, 0x19, 0x0a, 0x14, 0x53, 0x61, 0x74, 0x69, 0x73, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x50, 0x72, + 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x6b, 0x65, 0x79, 0x10, 0xe6, 0x01, 0x12, 0x17, 0x0a, 0x12, 0x53, + 0x61, 0x74, 0x69, 0x73, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x57, 0x72, 0x69, 0x74, 0x65, 0x6b, 0x65, + 0x79, 0x10, 0xe7, 0x01, 0x12, 0x0e, 0x0a, 0x09, 0x53, 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x61, + 0x74, 0x10, 0xe8, 0x01, 0x12, 0x13, 0x0a, 0x0e, 0x53, 0x75, 0x72, 0x76, 0x65, 0x79, 0x41, 0x6e, + 0x79, 0x70, 0x6c, 0x61, 0x63, 0x65, 0x10, 0xe9, 0x01, 0x12, 0x0e, 0x0a, 0x09, 0x53, 0x75, 0x72, + 0x76, 0x65, 0x79, 0x42, 0x6f, 0x74, 0x10, 0xea, 0x01, 0x12, 0x0e, 0x0a, 0x09, 0x57, 0x65, 0x62, + 0x65, 0x6e, 0x67, 0x61, 0x67, 0x65, 0x10, 0xeb, 0x01, 0x12, 0x12, 0x0a, 0x0d, 0x5a, 0x6f, 0x6e, + 0x6b, 0x61, 0x46, 0x65, 0x65, 0x64, 0x62, 0x61, 0x63, 0x6b, 0x10, 0xec, 0x01, 0x12, 0x0e, 0x0a, + 0x09, 0x44, 0x65, 0x6c, 0x69, 0x67, 0x68, 0x74, 0x65, 0x64, 0x10, 0xed, 0x01, 0x12, 0x0c, 0x0a, + 0x07, 0x46, 0x65, 0x65, 0x64, 0x69, 0x65, 0x72, 0x10, 0xee, 0x01, 0x12, 0x0d, 0x0a, 0x08, 0x41, + 0x62, 0x62, 0x79, 0x73, 0x61, 0x6c, 0x65, 0x10, 0xef, 0x01, 0x12, 0x0d, 0x0a, 0x08, 0x4d, 0x61, + 0x67, 0x6e, 0x65, 0x74, 0x69, 0x63, 0x10, 0xf0, 0x01, 0x12, 0x10, 0x0a, 0x07, 0x4e, 0x79, 0x74, + 0x69, 0x6d, 0x65, 0x73, 0x10, 0xf1, 0x01, 0x1a, 0x02, 0x08, 0x01, 0x12, 0x0c, 0x0a, 0x07, 0x50, + 0x6f, 0x6c, 0x79, 0x67, 0x6f, 0x6e, 0x10, 0xf2, 0x01, 0x12, 0x0c, 0x0a, 0x07, 0x50, 0x6f, 0x77, + 0x72, 0x62, 0x6f, 0x74, 0x10, 0xf3, 0x01, 0x12, 0x13, 0x0a, 0x0a, 0x50, 0x72, 0x6f, 0x73, 0x70, + 0x65, 0x63, 0x74, 0x49, 0x4f, 0x10, 0xf4, 0x01, 0x1a, 0x02, 0x08, 0x01, 0x12, 0x0d, 0x0a, 0x08, + 0x53, 0x6b, 0x72, 0x61, 0x70, 0x70, 0x69, 0x6f, 0x10, 0xf5, 0x01, 0x12, 0x0b, 0x0a, 0x06, 0x4d, + 0x6f, 0x6e, 0x64, 0x61, 0x79, 0x10, 0xf6, 0x01, 0x12, 0x10, 0x0a, 0x0b, 0x53, 0x6d, 0x61, 0x72, + 0x74, 0x73, 0x68, 0x65, 0x65, 0x74, 0x73, 0x10, 0xf7, 0x01, 0x12, 0x0a, 0x0a, 0x05, 0x57, 0x72, + 0x69, 0x6b, 0x65, 0x10, 0xf8, 0x01, 0x12, 0x0a, 0x0a, 0x05, 0x46, 0x6c, 0x6f, 0x61, 0x74, 0x10, + 0xf9, 0x01, 0x12, 0x0d, 0x0a, 0x08, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x6b, 0x69, 0x74, 0x10, 0xfa, + 0x01, 0x12, 0x13, 0x0a, 0x0a, 0x49, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x6f, 0x6d, 0x61, 0x74, 0x10, + 0xfb, 0x01, 0x1a, 0x02, 0x08, 0x01, 0x12, 0x0f, 0x0a, 0x0a, 0x53, 0x61, 0x6c, 0x65, 0x73, 0x62, + 0x6c, 0x69, 0x6e, 0x6b, 0x10, 0xfc, 0x01, 0x12, 0x0a, 0x0a, 0x05, 0x42, 0x6f, 0x72, 0x65, 0x64, + 0x10, 0xfd, 0x01, 0x12, 0x0c, 0x0a, 0x07, 0x43, 0x61, 0x6d, 0x70, 0x61, 0x79, 0x6e, 0x10, 0xfe, + 0x01, 0x12, 0x0e, 0x0a, 0x09, 0x43, 0x6c, 0x69, 0x6e, 0x63, 0x68, 0x70, 0x61, 0x64, 0x10, 0xff, + 0x01, 0x12, 0x0f, 0x0a, 0x0a, 0x43, 0x6f, 0x6d, 0x70, 0x61, 0x6e, 0x79, 0x48, 0x75, 0x62, 0x10, + 0x80, 0x02, 0x12, 0x0d, 0x0a, 0x08, 0x44, 0x65, 0x62, 0x6f, 0x75, 0x6e, 0x63, 0x65, 0x10, 0x81, + 0x02, 0x12, 0x0d, 0x0a, 0x08, 0x44, 0x79, 0x73, 0x70, 0x61, 0x74, 0x63, 0x68, 0x10, 0x82, 0x02, + 0x12, 0x10, 0x0a, 0x0b, 0x47, 0x75, 0x61, 0x72, 0x64, 0x69, 0x61, 0x6e, 0x61, 0x70, 0x69, 0x10, + 0x83, 0x02, 0x12, 0x0c, 0x0a, 0x07, 0x48, 0x61, 0x72, 0x76, 0x65, 0x73, 0x74, 0x10, 0x84, 0x02, + 0x12, 0x0c, 0x0a, 0x07, 0x4d, 0x6f, 0x6f, 0x73, 0x65, 0x6e, 0x64, 0x10, 0x85, 0x02, 0x12, 0x10, + 0x0a, 0x0b, 0x4f, 0x70, 0x65, 0x6e, 0x57, 0x65, 0x61, 0x74, 0x68, 0x65, 0x72, 0x10, 0x86, 0x02, + 0x12, 0x0d, 0x0a, 0x08, 0x53, 0x69, 0x74, 0x65, 0x6c, 0x65, 0x61, 0x66, 0x10, 0x87, 0x02, 0x12, + 0x10, 0x0a, 0x0b, 0x53, 0x71, 0x75, 0x61, 0x72, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x10, 0x88, + 0x02, 0x12, 0x0c, 0x0a, 0x07, 0x46, 0x6c, 0x6f, 0x77, 0x46, 0x6c, 0x75, 0x10, 0x89, 0x02, 0x12, + 0x0b, 0x0a, 0x06, 0x4e, 0x69, 0x6d, 0x62, 0x6c, 0x65, 0x10, 0x8a, 0x02, 0x12, 0x14, 0x0a, 0x0f, + 0x4c, 0x65, 0x73, 0x73, 0x41, 0x6e, 0x6e, 0x6f, 0x79, 0x69, 0x6e, 0x67, 0x43, 0x52, 0x4d, 0x10, + 0x8b, 0x02, 0x12, 0x0c, 0x0a, 0x07, 0x4e, 0x65, 0x74, 0x68, 0x75, 0x6e, 0x74, 0x10, 0x8c, 0x02, + 0x12, 0x0c, 0x0a, 0x07, 0x41, 0x70, 0x70, 0x74, 0x69, 0x76, 0x6f, 0x10, 0x8d, 0x02, 0x12, 0x0f, + 0x0a, 0x0a, 0x43, 0x61, 0x70, 0x73, 0x75, 0x6c, 0x65, 0x43, 0x52, 0x4d, 0x10, 0x8e, 0x02, 0x12, + 0x0e, 0x0a, 0x09, 0x49, 0x6e, 0x73, 0x69, 0x67, 0x68, 0x74, 0x6c, 0x79, 0x10, 0x8f, 0x02, 0x12, + 0x0a, 0x0a, 0x05, 0x4b, 0x79, 0x6c, 0x61, 0x73, 0x10, 0x90, 0x02, 0x12, 0x0f, 0x0a, 0x0a, 0x4f, + 0x6e, 0x65, 0x70, 0x61, 0x67, 0x65, 0x43, 0x52, 0x4d, 0x10, 0x91, 0x02, 0x12, 0x09, 0x0a, 0x04, + 0x55, 0x73, 0x65, 0x72, 0x10, 0x92, 0x02, 0x12, 0x10, 0x0a, 0x0b, 0x50, 0x72, 0x6f, 0x73, 0x70, + 0x65, 0x63, 0x74, 0x43, 0x52, 0x4d, 0x10, 0x93, 0x02, 0x12, 0x18, 0x0a, 0x13, 0x52, 0x65, 0x61, + 0x6c, 0x6c, 0x79, 0x53, 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x73, + 0x10, 0x94, 0x02, 0x12, 0x0c, 0x0a, 0x07, 0x41, 0x69, 0x72, 0x73, 0x68, 0x69, 0x70, 0x10, 0x95, + 0x02, 0x12, 0x0a, 0x0a, 0x05, 0x41, 0x72, 0x74, 0x73, 0x79, 0x10, 0x96, 0x02, 0x12, 0x0b, 0x0a, + 0x06, 0x59, 0x61, 0x6e, 0x64, 0x65, 0x78, 0x10, 0x97, 0x02, 0x12, 0x0d, 0x0a, 0x08, 0x43, 0x6c, + 0x6f, 0x63, 0x6b, 0x69, 0x66, 0x79, 0x10, 0x98, 0x02, 0x12, 0x0d, 0x0a, 0x08, 0x44, 0x6e, 0x73, + 0x63, 0x68, 0x65, 0x63, 0x6b, 0x10, 0x99, 0x02, 0x12, 0x10, 0x0a, 0x0b, 0x45, 0x61, 0x73, 0x79, + 0x49, 0x6e, 0x73, 0x69, 0x67, 0x68, 0x74, 0x10, 0x9a, 0x02, 0x12, 0x0e, 0x0a, 0x09, 0x45, 0x74, + 0x68, 0x70, 0x6c, 0x6f, 0x72, 0x65, 0x72, 0x10, 0x9b, 0x02, 0x12, 0x0d, 0x0a, 0x08, 0x45, 0x76, + 0x65, 0x72, 0x68, 0x6f, 0x75, 0x72, 0x10, 0x9c, 0x02, 0x12, 0x0c, 0x0a, 0x07, 0x46, 0x75, 0x6c, + 0x63, 0x72, 0x75, 0x6d, 0x10, 0x9d, 0x02, 0x12, 0x0d, 0x0a, 0x08, 0x47, 0x65, 0x6f, 0x49, 0x70, + 0x69, 0x66, 0x69, 0x10, 0x9e, 0x02, 0x12, 0x0c, 0x0a, 0x07, 0x4a, 0x6f, 0x74, 0x66, 0x6f, 0x72, + 0x6d, 0x10, 0x9f, 0x02, 0x12, 0x0c, 0x0a, 0x07, 0x52, 0x65, 0x66, 0x69, 0x6e, 0x65, 0x72, 0x10, + 0xa0, 0x02, 0x12, 0x10, 0x0a, 0x0b, 0x54, 0x69, 0x6d, 0x65, 0x7a, 0x6f, 0x6e, 0x65, 0x61, 0x70, + 0x69, 0x10, 0xa1, 0x02, 0x12, 0x0f, 0x0a, 0x0a, 0x54, 0x6f, 0x67, 0x67, 0x6c, 0x54, 0x72, 0x61, + 0x63, 0x6b, 0x10, 0xa2, 0x02, 0x12, 0x0b, 0x0a, 0x06, 0x56, 0x70, 0x6e, 0x61, 0x70, 0x69, 0x10, + 0xa3, 0x02, 0x12, 0x0e, 0x0a, 0x09, 0x57, 0x6f, 0x72, 0x6b, 0x73, 0x74, 0x61, 0x63, 0x6b, 0x10, + 0xa4, 0x02, 0x12, 0x0b, 0x0a, 0x06, 0x41, 0x70, 0x6f, 0x6c, 0x6c, 0x6f, 0x10, 0xa5, 0x02, 0x12, + 0x0d, 0x0a, 0x08, 0x45, 0x76, 0x65, 0x72, 0x73, 0x69, 0x67, 0x6e, 0x10, 0xa6, 0x02, 0x12, 0x09, + 0x0a, 0x04, 0x4a, 0x75, 0x72, 0x6f, 0x10, 0xa7, 0x02, 0x12, 0x0d, 0x0a, 0x08, 0x4b, 0x61, 0x72, + 0x6d, 0x61, 0x43, 0x52, 0x4d, 0x10, 0xa8, 0x02, 0x12, 0x0c, 0x0a, 0x07, 0x4d, 0x65, 0x74, 0x72, + 0x69, 0x6c, 0x6f, 0x10, 0xa9, 0x02, 0x12, 0x0d, 0x0a, 0x08, 0x50, 0x61, 0x6e, 0x64, 0x61, 0x64, + 0x6f, 0x63, 0x10, 0xaa, 0x02, 0x12, 0x0e, 0x0a, 0x09, 0x52, 0x65, 0x76, 0x61, 0x6d, 0x70, 0x43, + 0x52, 0x4d, 0x10, 0xab, 0x02, 0x12, 0x10, 0x0a, 0x0b, 0x53, 0x61, 0x6c, 0x65, 0x73, 0x63, 0x6f, + 0x6f, 0x6b, 0x69, 0x65, 0x10, 0xac, 0x02, 0x12, 0x0d, 0x0a, 0x08, 0x41, 0x6c, 0x63, 0x6f, 0x6e, + 0x6f, 0x73, 0x74, 0x10, 0xad, 0x02, 0x12, 0x0c, 0x0a, 0x07, 0x42, 0x6c, 0x6f, 0x67, 0x67, 0x65, + 0x72, 0x10, 0xae, 0x02, 0x12, 0x10, 0x0a, 0x0b, 0x41, 0x63, 0x63, 0x75, 0x77, 0x65, 0x61, 0x74, + 0x68, 0x65, 0x72, 0x10, 0xaf, 0x02, 0x12, 0x13, 0x0a, 0x0a, 0x4f, 0x70, 0x65, 0x6e, 0x67, 0x72, + 0x61, 0x70, 0x68, 0x72, 0x10, 0xb0, 0x02, 0x1a, 0x02, 0x08, 0x01, 0x12, 0x09, 0x0a, 0x04, 0x52, + 0x61, 0x77, 0x67, 0x10, 0xb1, 0x02, 0x12, 0x0e, 0x0a, 0x09, 0x52, 0x69, 0x6f, 0x74, 0x67, 0x61, + 0x6d, 0x65, 0x73, 0x10, 0xb2, 0x02, 0x12, 0x0d, 0x0a, 0x08, 0x52, 0x6f, 0x6e, 0x69, 0x6e, 0x41, + 0x70, 0x70, 0x10, 0xb3, 0x02, 0x12, 0x0f, 0x0a, 0x0a, 0x53, 0x74, 0x6f, 0x72, 0x6d, 0x67, 0x6c, + 0x61, 0x73, 0x73, 0x10, 0xb4, 0x02, 0x12, 0x0b, 0x0a, 0x06, 0x54, 0x6f, 0x6d, 0x74, 0x6f, 0x6d, + 0x10, 0xb5, 0x02, 0x12, 0x0b, 0x0a, 0x06, 0x54, 0x77, 0x69, 0x74, 0x63, 0x68, 0x10, 0xb6, 0x02, + 0x12, 0x0b, 0x0a, 0x06, 0x44, 0x6f, 0x63, 0x75, 0x6d, 0x6f, 0x10, 0xb7, 0x02, 0x12, 0x0e, 0x0a, + 0x09, 0x43, 0x6c, 0x6f, 0x75, 0x64, 0x77, 0x61, 0x79, 0x73, 0x10, 0xb8, 0x02, 0x12, 0x0f, 0x0a, + 0x0a, 0x56, 0x65, 0x65, 0x76, 0x61, 0x76, 0x61, 0x75, 0x6c, 0x74, 0x10, 0xb9, 0x02, 0x12, 0x10, + 0x0a, 0x0b, 0x4b, 0x69, 0x74, 0x65, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x10, 0xba, 0x02, + 0x12, 0x17, 0x0a, 0x12, 0x53, 0x68, 0x6f, 0x70, 0x65, 0x65, 0x4f, 0x70, 0x65, 0x6e, 0x50, 0x6c, + 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x10, 0xbb, 0x02, 0x12, 0x0f, 0x0a, 0x0a, 0x54, 0x65, 0x61, + 0x6d, 0x56, 0x69, 0x65, 0x77, 0x65, 0x72, 0x10, 0xbc, 0x02, 0x12, 0x0b, 0x0a, 0x06, 0x42, 0x75, + 0x6c, 0x62, 0x75, 0x6c, 0x10, 0xbd, 0x02, 0x12, 0x16, 0x0a, 0x11, 0x43, 0x65, 0x6e, 0x74, 0x72, + 0x61, 0x6c, 0x53, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x52, 0x4d, 0x10, 0xbe, 0x02, 0x12, + 0x0d, 0x0a, 0x08, 0x54, 0x65, 0x61, 0x6d, 0x67, 0x61, 0x74, 0x65, 0x10, 0xbf, 0x02, 0x12, 0x0c, + 0x0a, 0x07, 0x41, 0x78, 0x6f, 0x6e, 0x61, 0x75, 0x74, 0x10, 0xc0, 0x02, 0x12, 0x0b, 0x0a, 0x06, + 0x54, 0x79, 0x6e, 0x74, 0x65, 0x63, 0x10, 0xc1, 0x02, 0x12, 0x0c, 0x0a, 0x07, 0x41, 0x70, 0x70, + 0x63, 0x75, 0x65, 0x73, 0x10, 0xc2, 0x02, 0x12, 0x0e, 0x0a, 0x09, 0x41, 0x75, 0x74, 0x6f, 0x6b, + 0x6c, 0x6f, 0x73, 0x65, 0x10, 0xc3, 0x02, 0x12, 0x0e, 0x0a, 0x09, 0x43, 0x6c, 0x6f, 0x75, 0x64, + 0x70, 0x6c, 0x61, 0x6e, 0x10, 0xc4, 0x02, 0x12, 0x0e, 0x0a, 0x09, 0x44, 0x6f, 0x74, 0x6d, 0x61, + 0x69, 0x6c, 0x65, 0x72, 0x10, 0xc5, 0x02, 0x12, 0x0d, 0x0a, 0x08, 0x47, 0x65, 0x74, 0x45, 0x6d, + 0x61, 0x69, 0x6c, 0x10, 0xc6, 0x02, 0x12, 0x0e, 0x0a, 0x09, 0x47, 0x65, 0x74, 0x45, 0x6d, 0x61, + 0x69, 0x6c, 0x73, 0x10, 0xc7, 0x02, 0x12, 0x0c, 0x0a, 0x07, 0x4b, 0x6f, 0x6e, 0x74, 0x65, 0x6e, + 0x74, 0x10, 0xc8, 0x02, 0x12, 0x0f, 0x0a, 0x0a, 0x4c, 0x65, 0x61, 0x64, 0x66, 0x65, 0x65, 0x64, + 0x65, 0x72, 0x10, 0xc9, 0x02, 0x12, 0x0a, 0x0a, 0x05, 0x52, 0x61, 0x76, 0x65, 0x6e, 0x10, 0xca, + 0x02, 0x12, 0x10, 0x0a, 0x0b, 0x52, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x52, 0x65, 0x61, 0x63, 0x68, + 0x10, 0xcb, 0x02, 0x12, 0x0b, 0x0a, 0x06, 0x55, 0x70, 0x6c, 0x65, 0x61, 0x64, 0x10, 0xcc, 0x02, + 0x12, 0x0f, 0x0a, 0x0a, 0x42, 0x72, 0x61, 0x6e, 0x64, 0x66, 0x65, 0x74, 0x63, 0x68, 0x10, 0xcd, + 0x02, 0x12, 0x0d, 0x0a, 0x08, 0x43, 0x6c, 0x65, 0x61, 0x72, 0x62, 0x69, 0x74, 0x10, 0xce, 0x02, + 0x12, 0x0c, 0x0a, 0x07, 0x43, 0x72, 0x6f, 0x77, 0x64, 0x69, 0x6e, 0x10, 0xcf, 0x02, 0x12, 0x0d, + 0x0a, 0x08, 0x4d, 0x61, 0x70, 0x71, 0x75, 0x65, 0x73, 0x74, 0x10, 0xd0, 0x02, 0x12, 0x0f, 0x0a, + 0x0a, 0x4e, 0x6f, 0x74, 0x69, 0x63, 0x65, 0x61, 0x62, 0x6c, 0x65, 0x10, 0xd1, 0x02, 0x12, 0x0b, + 0x0a, 0x06, 0x4f, 0x6e, 0x62, 0x75, 0x6b, 0x61, 0x10, 0xd2, 0x02, 0x12, 0x0c, 0x0a, 0x07, 0x54, + 0x6f, 0x64, 0x6f, 0x69, 0x73, 0x74, 0x10, 0xd3, 0x02, 0x12, 0x0f, 0x0a, 0x0a, 0x53, 0x74, 0x6f, + 0x72, 0x79, 0x63, 0x68, 0x69, 0x65, 0x66, 0x10, 0xd4, 0x02, 0x12, 0x0d, 0x0a, 0x08, 0x4c, 0x69, + 0x6e, 0x6b, 0x65, 0x64, 0x49, 0x6e, 0x10, 0xd5, 0x02, 0x12, 0x0c, 0x0a, 0x07, 0x59, 0x6f, 0x75, + 0x53, 0x69, 0x67, 0x6e, 0x10, 0xd6, 0x02, 0x12, 0x0b, 0x0a, 0x06, 0x44, 0x6f, 0x63, 0x6b, 0x65, + 0x72, 0x10, 0xd7, 0x02, 0x12, 0x0d, 0x0a, 0x08, 0x54, 0x65, 0x6c, 0x65, 0x73, 0x69, 0x67, 0x6e, + 0x10, 0xd8, 0x02, 0x12, 0x10, 0x0a, 0x0b, 0x53, 0x70, 0x6f, 0x6f, 0x6e, 0x61, 0x63, 0x75, 0x6c, + 0x61, 0x72, 0x10, 0xd9, 0x02, 0x12, 0x11, 0x0a, 0x0c, 0x41, 0x65, 0x72, 0x69, 0x73, 0x77, 0x65, + 0x61, 0x74, 0x68, 0x65, 0x72, 0x10, 0xda, 0x02, 0x12, 0x11, 0x0a, 0x0c, 0x41, 0x6c, 0x70, 0x68, + 0x61, 0x76, 0x61, 0x6e, 0x74, 0x61, 0x67, 0x65, 0x10, 0xdb, 0x02, 0x12, 0x0a, 0x0a, 0x05, 0x49, + 0x6d, 0x67, 0x75, 0x72, 0x10, 0xdc, 0x02, 0x12, 0x0b, 0x0a, 0x06, 0x49, 0x6d, 0x61, 0x67, 0x67, + 0x61, 0x10, 0xdd, 0x02, 0x12, 0x0b, 0x0a, 0x06, 0x53, 0x4d, 0x53, 0x41, 0x70, 0x69, 0x10, 0xde, + 0x02, 0x12, 0x11, 0x0a, 0x0c, 0x44, 0x69, 0x73, 0x74, 0x72, 0x69, 0x62, 0x75, 0x73, 0x69, 0x6f, + 0x6e, 0x10, 0xdf, 0x02, 0x12, 0x12, 0x0a, 0x09, 0x42, 0x6c, 0x61, 0x62, 0x6c, 0x61, 0x62, 0x75, + 0x73, 0x10, 0xe0, 0x02, 0x1a, 0x02, 0x08, 0x01, 0x12, 0x0d, 0x0a, 0x08, 0x57, 0x6f, 0x72, 0x64, + 0x73, 0x41, 0x70, 0x69, 0x10, 0xe1, 0x02, 0x12, 0x12, 0x0a, 0x0d, 0x43, 0x75, 0x72, 0x72, 0x65, + 0x6e, 0x63, 0x79, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x10, 0xe2, 0x02, 0x12, 0x0d, 0x0a, 0x08, 0x48, + 0x74, 0x6d, 0x6c, 0x32, 0x50, 0x64, 0x66, 0x10, 0xe3, 0x02, 0x12, 0x12, 0x0a, 0x0d, 0x49, 0x50, + 0x47, 0x65, 0x6f, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x10, 0xe4, 0x02, 0x12, 0x0b, + 0x0a, 0x06, 0x4f, 0x77, 0x6c, 0x62, 0x6f, 0x74, 0x10, 0xe5, 0x02, 0x12, 0x11, 0x0a, 0x0c, 0x43, + 0x6c, 0x6f, 0x75, 0x64, 0x6d, 0x65, 0x72, 0x73, 0x69, 0x76, 0x65, 0x10, 0xe6, 0x02, 0x12, 0x0d, + 0x0a, 0x08, 0x44, 0x79, 0x6e, 0x61, 0x6c, 0x69, 0x73, 0x74, 0x10, 0xe7, 0x02, 0x12, 0x14, 0x0a, + 0x0f, 0x45, 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x52, 0x61, 0x74, 0x65, 0x41, 0x50, 0x49, + 0x10, 0xe8, 0x02, 0x12, 0x0f, 0x0a, 0x0a, 0x48, 0x6f, 0x6c, 0x69, 0x64, 0x61, 0x79, 0x41, 0x50, + 0x49, 0x10, 0xe9, 0x02, 0x12, 0x0a, 0x0a, 0x05, 0x49, 0x70, 0x61, 0x70, 0x69, 0x10, 0xea, 0x02, + 0x12, 0x10, 0x0a, 0x0b, 0x4d, 0x61, 0x72, 0x6b, 0x65, 0x74, 0x73, 0x74, 0x61, 0x63, 0x6b, 0x10, + 0xeb, 0x02, 0x12, 0x10, 0x0a, 0x0b, 0x4e, 0x75, 0x74, 0x72, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x69, + 0x78, 0x10, 0xec, 0x02, 0x12, 0x0a, 0x0a, 0x05, 0x53, 0x77, 0x65, 0x6c, 0x6c, 0x10, 0xed, 0x02, + 0x12, 0x19, 0x0a, 0x14, 0x43, 0x6c, 0x69, 0x63, 0x6b, 0x75, 0x70, 0x50, 0x65, 0x72, 0x73, 0x6f, + 0x6e, 0x61, 0x6c, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x10, 0xee, 0x02, 0x12, 0x0e, 0x0a, 0x05, 0x4e, + 0x69, 0x74, 0x72, 0x6f, 0x10, 0xef, 0x02, 0x1a, 0x02, 0x08, 0x01, 0x12, 0x08, 0x0a, 0x03, 0x52, + 0x65, 0x76, 0x10, 0xf0, 0x02, 0x12, 0x0d, 0x0a, 0x08, 0x52, 0x75, 0x6e, 0x52, 0x75, 0x6e, 0x49, + 0x74, 0x10, 0xf1, 0x02, 0x12, 0x0d, 0x0a, 0x08, 0x54, 0x79, 0x70, 0x65, 0x66, 0x6f, 0x72, 0x6d, + 0x10, 0xf2, 0x02, 0x12, 0x0d, 0x0a, 0x08, 0x4d, 0x69, 0x78, 0x70, 0x61, 0x6e, 0x65, 0x6c, 0x10, + 0xf3, 0x02, 0x12, 0x0c, 0x0a, 0x07, 0x54, 0x72, 0x61, 0x64, 0x69, 0x65, 0x72, 0x10, 0xf4, 0x02, + 0x12, 0x0d, 0x0a, 0x08, 0x56, 0x65, 0x72, 0x69, 0x66, 0x69, 0x65, 0x72, 0x10, 0xf5, 0x02, 0x12, + 0x0d, 0x0a, 0x08, 0x56, 0x6f, 0x75, 0x63, 0x68, 0x65, 0x72, 0x79, 0x10, 0xf6, 0x02, 0x12, 0x0b, + 0x0a, 0x06, 0x41, 0x6c, 0x65, 0x67, 0x72, 0x61, 0x10, 0xf7, 0x02, 0x12, 0x09, 0x0a, 0x04, 0x41, + 0x75, 0x64, 0x64, 0x10, 0xf8, 0x02, 0x12, 0x10, 0x0a, 0x0b, 0x42, 0x61, 0x72, 0x65, 0x6d, 0x65, + 0x74, 0x72, 0x69, 0x63, 0x73, 0x10, 0xf9, 0x02, 0x12, 0x0c, 0x0a, 0x07, 0x43, 0x6f, 0x69, 0x6e, + 0x6c, 0x69, 0x62, 0x10, 0xfa, 0x02, 0x12, 0x15, 0x0a, 0x10, 0x45, 0x78, 0x63, 0x68, 0x61, 0x6e, + 0x67, 0x65, 0x52, 0x61, 0x74, 0x65, 0x73, 0x41, 0x50, 0x49, 0x10, 0xfb, 0x02, 0x12, 0x12, 0x0a, + 0x0d, 0x43, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x53, 0x63, 0x6f, 0x6f, 0x70, 0x10, 0xfc, + 0x02, 0x12, 0x0d, 0x0a, 0x08, 0x46, 0x58, 0x4d, 0x61, 0x72, 0x6b, 0x65, 0x74, 0x10, 0xfd, 0x02, + 0x12, 0x12, 0x0a, 0x0d, 0x43, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x43, 0x6c, 0x6f, 0x75, + 0x64, 0x10, 0xfe, 0x02, 0x12, 0x0e, 0x0a, 0x09, 0x47, 0x65, 0x74, 0x47, 0x65, 0x6f, 0x41, 0x50, + 0x49, 0x10, 0xff, 0x02, 0x12, 0x0d, 0x0a, 0x08, 0x41, 0x62, 0x73, 0x74, 0x72, 0x61, 0x63, 0x74, + 0x10, 0x80, 0x03, 0x12, 0x0d, 0x0a, 0x08, 0x42, 0x69, 0x6c, 0x6c, 0x6f, 0x6d, 0x61, 0x74, 0x10, + 0x81, 0x03, 0x12, 0x0b, 0x0a, 0x06, 0x44, 0x6f, 0x76, 0x69, 0x63, 0x6f, 0x10, 0x82, 0x03, 0x12, + 0x0b, 0x0a, 0x06, 0x42, 0x69, 0x74, 0x62, 0x61, 0x72, 0x10, 0x83, 0x03, 0x12, 0x0c, 0x0a, 0x07, + 0x42, 0x75, 0x67, 0x73, 0x6e, 0x61, 0x67, 0x10, 0x84, 0x03, 0x12, 0x0f, 0x0a, 0x0a, 0x41, 0x73, + 0x73, 0x65, 0x6d, 0x62, 0x6c, 0x79, 0x41, 0x49, 0x10, 0x85, 0x03, 0x12, 0x0f, 0x0a, 0x0a, 0x41, + 0x64, 0x61, 0x66, 0x72, 0x75, 0x69, 0x74, 0x49, 0x4f, 0x10, 0x86, 0x03, 0x12, 0x0a, 0x0a, 0x05, + 0x41, 0x70, 0x69, 0x66, 0x79, 0x10, 0x87, 0x03, 0x12, 0x0e, 0x0a, 0x09, 0x43, 0x6f, 0x69, 0x6e, + 0x47, 0x65, 0x63, 0x6b, 0x6f, 0x10, 0x88, 0x03, 0x12, 0x12, 0x0a, 0x0d, 0x43, 0x72, 0x79, 0x70, + 0x74, 0x6f, 0x43, 0x6f, 0x6d, 0x70, 0x61, 0x72, 0x65, 0x10, 0x89, 0x03, 0x12, 0x0e, 0x0a, 0x09, + 0x46, 0x75, 0x6c, 0x6c, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x10, 0x8a, 0x03, 0x12, 0x0e, 0x0a, 0x09, + 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x53, 0x69, 0x67, 0x6e, 0x10, 0x8b, 0x03, 0x12, 0x0d, 0x0a, 0x08, + 0x4c, 0x6f, 0x79, 0x76, 0x65, 0x72, 0x73, 0x65, 0x10, 0x8c, 0x03, 0x12, 0x0c, 0x0a, 0x07, 0x4e, + 0x65, 0x74, 0x43, 0x6f, 0x72, 0x65, 0x10, 0x8d, 0x03, 0x12, 0x0e, 0x0a, 0x09, 0x53, 0x61, 0x75, + 0x63, 0x65, 0x4c, 0x61, 0x62, 0x73, 0x10, 0x8e, 0x03, 0x12, 0x0f, 0x0a, 0x0a, 0x41, 0x6c, 0x69, + 0x65, 0x6e, 0x56, 0x61, 0x75, 0x6c, 0x74, 0x10, 0x8f, 0x03, 0x12, 0x0d, 0x0a, 0x08, 0x41, 0x70, + 0x69, 0x66, 0x6c, 0x61, 0x73, 0x68, 0x10, 0x91, 0x03, 0x12, 0x0e, 0x0a, 0x09, 0x43, 0x6f, 0x69, + 0x6e, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x10, 0x92, 0x03, 0x12, 0x10, 0x0a, 0x0b, 0x43, 0x75, 0x72, + 0x72, 0x65, 0x6e, 0x74, 0x73, 0x41, 0x50, 0x49, 0x10, 0x93, 0x03, 0x12, 0x0c, 0x0a, 0x07, 0x44, + 0x61, 0x74, 0x61, 0x47, 0x6f, 0x76, 0x10, 0x94, 0x03, 0x12, 0x0b, 0x0a, 0x06, 0x45, 0x6e, 0x69, + 0x67, 0x6d, 0x61, 0x10, 0x95, 0x03, 0x12, 0x1a, 0x0a, 0x15, 0x46, 0x69, 0x6e, 0x61, 0x6e, 0x63, + 0x69, 0x61, 0x6c, 0x4d, 0x6f, 0x64, 0x65, 0x6c, 0x69, 0x6e, 0x67, 0x50, 0x72, 0x65, 0x70, 0x10, + 0x96, 0x03, 0x12, 0x0d, 0x0a, 0x08, 0x47, 0x65, 0x6f, 0x63, 0x6f, 0x64, 0x69, 0x6f, 0x10, 0x97, + 0x03, 0x12, 0x0c, 0x0a, 0x07, 0x48, 0x65, 0x72, 0x65, 0x41, 0x50, 0x49, 0x10, 0x98, 0x03, 0x12, + 0x13, 0x0a, 0x0a, 0x4d, 0x61, 0x63, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x10, 0x99, 0x03, + 0x1a, 0x02, 0x08, 0x01, 0x12, 0x0c, 0x0a, 0x07, 0x4f, 0x4f, 0x50, 0x53, 0x70, 0x61, 0x6d, 0x10, + 0x9a, 0x03, 0x12, 0x10, 0x0a, 0x0b, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x73, 0x49, + 0x4f, 0x10, 0x9b, 0x03, 0x12, 0x0f, 0x0a, 0x0a, 0x53, 0x63, 0x72, 0x61, 0x70, 0x65, 0x72, 0x41, + 0x50, 0x49, 0x10, 0x9c, 0x03, 0x12, 0x13, 0x0a, 0x0e, 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, + 0x79, 0x54, 0x72, 0x61, 0x69, 0x6c, 0x73, 0x10, 0x9d, 0x03, 0x12, 0x0f, 0x0a, 0x0a, 0x54, 0x6f, + 0x6d, 0x6f, 0x72, 0x72, 0x6f, 0x77, 0x49, 0x4f, 0x10, 0x9e, 0x03, 0x12, 0x13, 0x0a, 0x0e, 0x57, + 0x6f, 0x72, 0x6c, 0x64, 0x43, 0x6f, 0x69, 0x6e, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x10, 0x9f, 0x03, + 0x12, 0x11, 0x0a, 0x0c, 0x46, 0x61, 0x63, 0x65, 0x50, 0x6c, 0x75, 0x73, 0x50, 0x6c, 0x75, 0x73, + 0x10, 0xa0, 0x03, 0x12, 0x0e, 0x0a, 0x09, 0x56, 0x6f, 0x69, 0x63, 0x65, 0x67, 0x61, 0x69, 0x6e, + 0x10, 0xa1, 0x03, 0x12, 0x0d, 0x0a, 0x08, 0x44, 0x65, 0x65, 0x70, 0x67, 0x72, 0x61, 0x6d, 0x10, + 0xa2, 0x03, 0x12, 0x13, 0x0a, 0x0e, 0x56, 0x69, 0x73, 0x75, 0x61, 0x6c, 0x43, 0x72, 0x6f, 0x73, + 0x73, 0x69, 0x6e, 0x67, 0x10, 0xa3, 0x03, 0x12, 0x0c, 0x0a, 0x07, 0x46, 0x69, 0x6e, 0x6e, 0x68, + 0x75, 0x62, 0x10, 0xa4, 0x03, 0x12, 0x0b, 0x0a, 0x06, 0x54, 0x69, 0x69, 0x6e, 0x67, 0x6f, 0x10, + 0xa5, 0x03, 0x12, 0x10, 0x0a, 0x0b, 0x52, 0x69, 0x6e, 0x67, 0x43, 0x65, 0x6e, 0x74, 0x72, 0x61, + 0x6c, 0x10, 0xa6, 0x03, 0x12, 0x0b, 0x0a, 0x06, 0x46, 0x69, 0x6e, 0x61, 0x67, 0x65, 0x10, 0xa7, + 0x03, 0x12, 0x0b, 0x0a, 0x06, 0x45, 0x64, 0x61, 0x6d, 0x61, 0x6d, 0x10, 0xa8, 0x03, 0x12, 0x10, + 0x0a, 0x0b, 0x48, 0x79, 0x70, 0x65, 0x41, 0x75, 0x64, 0x69, 0x74, 0x6f, 0x72, 0x10, 0xa9, 0x03, + 0x12, 0x0a, 0x0a, 0x05, 0x47, 0x65, 0x6e, 0x67, 0x6f, 0x10, 0xaa, 0x03, 0x12, 0x0a, 0x0a, 0x05, + 0x46, 0x72, 0x6f, 0x6e, 0x74, 0x10, 0xab, 0x03, 0x12, 0x0e, 0x0a, 0x09, 0x46, 0x6c, 0x65, 0x65, + 0x74, 0x62, 0x61, 0x73, 0x65, 0x10, 0xac, 0x03, 0x12, 0x0b, 0x0a, 0x06, 0x42, 0x75, 0x62, 0x62, + 0x6c, 0x65, 0x10, 0xad, 0x03, 0x12, 0x0f, 0x0a, 0x0a, 0x42, 0x61, 0x6e, 0x6e, 0x65, 0x72, 0x62, + 0x65, 0x61, 0x72, 0x10, 0xae, 0x03, 0x12, 0x0b, 0x0a, 0x06, 0x41, 0x64, 0x7a, 0x75, 0x6e, 0x61, + 0x10, 0xaf, 0x03, 0x12, 0x13, 0x0a, 0x0e, 0x42, 0x69, 0x74, 0x63, 0x6f, 0x69, 0x6e, 0x41, 0x76, + 0x65, 0x72, 0x61, 0x67, 0x65, 0x10, 0xb0, 0x03, 0x12, 0x0f, 0x0a, 0x0a, 0x43, 0x6f, 0x6d, 0x6d, + 0x65, 0x72, 0x63, 0x65, 0x4a, 0x53, 0x10, 0xb1, 0x03, 0x12, 0x13, 0x0a, 0x0e, 0x44, 0x65, 0x74, + 0x65, 0x63, 0x74, 0x4c, 0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65, 0x10, 0xb2, 0x03, 0x12, 0x11, + 0x0a, 0x08, 0x46, 0x61, 0x6b, 0x65, 0x4a, 0x53, 0x4f, 0x4e, 0x10, 0xb3, 0x03, 0x1a, 0x02, 0x08, + 0x01, 0x12, 0x10, 0x0a, 0x0b, 0x47, 0x72, 0x61, 0x70, 0x68, 0x68, 0x6f, 0x70, 0x70, 0x65, 0x72, + 0x10, 0xb4, 0x03, 0x12, 0x0d, 0x0a, 0x08, 0x4c, 0x65, 0x78, 0x69, 0x67, 0x72, 0x61, 0x6d, 0x10, + 0xb5, 0x03, 0x12, 0x10, 0x0a, 0x0b, 0x4c, 0x69, 0x6e, 0x6b, 0x50, 0x72, 0x65, 0x76, 0x69, 0x65, + 0x77, 0x10, 0xb6, 0x03, 0x12, 0x0e, 0x0a, 0x09, 0x4e, 0x75, 0x6d, 0x76, 0x65, 0x72, 0x69, 0x66, + 0x79, 0x10, 0xb7, 0x03, 0x12, 0x0f, 0x0a, 0x0a, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x43, 0x72, 0x61, + 0x77, 0x6c, 0x10, 0xb8, 0x03, 0x12, 0x0f, 0x0a, 0x0a, 0x5a, 0x69, 0x70, 0x43, 0x6f, 0x64, 0x65, + 0x41, 0x50, 0x49, 0x10, 0xb9, 0x03, 0x12, 0x0e, 0x0a, 0x09, 0x43, 0x6f, 0x6d, 0x65, 0x74, 0x63, + 0x68, 0x61, 0x74, 0x10, 0xba, 0x03, 0x12, 0x0b, 0x0a, 0x06, 0x4b, 0x65, 0x79, 0x67, 0x65, 0x6e, + 0x10, 0xbb, 0x03, 0x12, 0x0d, 0x0a, 0x08, 0x4d, 0x69, 0x78, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x10, + 0xbc, 0x03, 0x12, 0x0c, 0x0a, 0x07, 0x54, 0x61, 0x74, 0x75, 0x6d, 0x49, 0x4f, 0x10, 0xbd, 0x03, + 0x12, 0x0c, 0x0a, 0x07, 0x54, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x10, 0xbe, 0x03, 0x12, 0x0f, + 0x0a, 0x06, 0x4c, 0x61, 0x73, 0x74, 0x66, 0x6d, 0x10, 0xbf, 0x03, 0x1a, 0x02, 0x08, 0x01, 0x12, + 0x0d, 0x0a, 0x08, 0x42, 0x72, 0x6f, 0x77, 0x73, 0x68, 0x6f, 0x74, 0x10, 0xc0, 0x03, 0x12, 0x0c, + 0x0a, 0x07, 0x4a, 0x53, 0x4f, 0x4e, 0x62, 0x69, 0x6e, 0x10, 0xc1, 0x03, 0x12, 0x0f, 0x0a, 0x0a, + 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x51, 0x10, 0xc2, 0x03, 0x12, 0x12, 0x0a, + 0x0d, 0x53, 0x63, 0x72, 0x65, 0x65, 0x6e, 0x73, 0x68, 0x6f, 0x74, 0x41, 0x50, 0x49, 0x10, 0xc3, + 0x03, 0x12, 0x11, 0x0a, 0x0c, 0x57, 0x65, 0x61, 0x74, 0x68, 0x65, 0x72, 0x53, 0x74, 0x61, 0x63, + 0x6b, 0x10, 0xc4, 0x03, 0x12, 0x0c, 0x0a, 0x07, 0x41, 0x6d, 0x61, 0x64, 0x65, 0x75, 0x73, 0x10, + 0xc5, 0x03, 0x12, 0x0f, 0x0a, 0x0a, 0x46, 0x6f, 0x75, 0x72, 0x53, 0x71, 0x75, 0x61, 0x72, 0x65, + 0x10, 0xc6, 0x03, 0x12, 0x0b, 0x0a, 0x06, 0x46, 0x6c, 0x69, 0x63, 0x6b, 0x72, 0x10, 0xc7, 0x03, + 0x12, 0x0e, 0x0a, 0x09, 0x43, 0x6c, 0x69, 0x63, 0x6b, 0x48, 0x65, 0x6c, 0x70, 0x10, 0xc8, 0x03, + 0x12, 0x0a, 0x0a, 0x05, 0x41, 0x6d, 0x62, 0x65, 0x65, 0x10, 0xc9, 0x03, 0x12, 0x0d, 0x0a, 0x08, + 0x41, 0x70, 0x69, 0x32, 0x43, 0x61, 0x72, 0x74, 0x10, 0xca, 0x03, 0x12, 0x0f, 0x0a, 0x0a, 0x48, + 0x79, 0x70, 0x65, 0x72, 0x74, 0x72, 0x61, 0x63, 0x6b, 0x10, 0xcb, 0x03, 0x12, 0x0e, 0x0a, 0x09, + 0x4b, 0x61, 0x6b, 0x61, 0x6f, 0x54, 0x61, 0x6c, 0x6b, 0x10, 0xcc, 0x03, 0x12, 0x0c, 0x0a, 0x07, + 0x52, 0x69, 0x74, 0x65, 0x4b, 0x69, 0x74, 0x10, 0xcd, 0x03, 0x12, 0x11, 0x0a, 0x0c, 0x53, 0x68, + 0x75, 0x74, 0x74, 0x65, 0x72, 0x73, 0x74, 0x6f, 0x63, 0x6b, 0x10, 0xce, 0x03, 0x12, 0x12, 0x0a, + 0x09, 0x54, 0x65, 0x78, 0x74, 0x32, 0x44, 0x61, 0x74, 0x61, 0x10, 0xcf, 0x03, 0x1a, 0x02, 0x08, + 0x01, 0x12, 0x13, 0x0a, 0x0e, 0x59, 0x6f, 0x75, 0x4e, 0x65, 0x65, 0x64, 0x41, 0x42, 0x75, 0x64, + 0x67, 0x65, 0x74, 0x10, 0xd0, 0x03, 0x12, 0x0c, 0x0a, 0x07, 0x43, 0x72, 0x69, 0x63, 0x6b, 0x65, + 0x74, 0x10, 0xd1, 0x03, 0x12, 0x0e, 0x0a, 0x09, 0x46, 0x69, 0x6c, 0x65, 0x73, 0x74, 0x61, 0x63, + 0x6b, 0x10, 0xd2, 0x03, 0x12, 0x0a, 0x0a, 0x05, 0x47, 0x79, 0x61, 0x7a, 0x6f, 0x10, 0xd3, 0x03, + 0x12, 0x0e, 0x0a, 0x09, 0x4d, 0x61, 0x76, 0x65, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x10, 0xd4, 0x03, + 0x12, 0x0b, 0x0a, 0x06, 0x53, 0x68, 0x65, 0x65, 0x74, 0x79, 0x10, 0xd5, 0x03, 0x12, 0x0f, 0x0a, + 0x0a, 0x53, 0x70, 0x6f, 0x72, 0x74, 0x73, 0x6d, 0x6f, 0x6e, 0x6b, 0x10, 0xd6, 0x03, 0x12, 0x0e, + 0x0a, 0x09, 0x53, 0x74, 0x6f, 0x63, 0x6b, 0x64, 0x61, 0x74, 0x61, 0x10, 0xd7, 0x03, 0x12, 0x0d, + 0x0a, 0x08, 0x55, 0x6e, 0x73, 0x70, 0x6c, 0x61, 0x73, 0x68, 0x10, 0xd8, 0x03, 0x12, 0x0e, 0x0a, + 0x09, 0x41, 0x6c, 0x6c, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x73, 0x10, 0xd9, 0x03, 0x12, 0x11, 0x0a, + 0x0c, 0x43, 0x61, 0x6c, 0x6f, 0x72, 0x69, 0x65, 0x4e, 0x69, 0x6e, 0x6a, 0x61, 0x10, 0xda, 0x03, + 0x12, 0x0e, 0x0a, 0x09, 0x57, 0x61, 0x6c, 0x6b, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x10, 0xdb, 0x03, + 0x12, 0x0b, 0x0a, 0x06, 0x53, 0x74, 0x72, 0x61, 0x76, 0x61, 0x10, 0xdc, 0x03, 0x12, 0x0b, 0x0a, + 0x06, 0x43, 0x69, 0x63, 0x65, 0x72, 0x6f, 0x10, 0xdd, 0x03, 0x12, 0x0e, 0x0a, 0x09, 0x49, 0x50, + 0x51, 0x75, 0x61, 0x6c, 0x69, 0x74, 0x79, 0x10, 0xde, 0x03, 0x12, 0x11, 0x0a, 0x0c, 0x50, 0x61, + 0x72, 0x61, 0x6c, 0x6c, 0x65, 0x6c, 0x44, 0x6f, 0x74, 0x73, 0x10, 0xdf, 0x03, 0x12, 0x0c, 0x0a, + 0x07, 0x52, 0x6f, 0x61, 0x72, 0x69, 0x6e, 0x67, 0x10, 0xe0, 0x03, 0x12, 0x0c, 0x0a, 0x07, 0x4d, + 0x61, 0x69, 0x6c, 0x73, 0x61, 0x63, 0x10, 0xe1, 0x03, 0x12, 0x0a, 0x0a, 0x05, 0x57, 0x68, 0x6f, + 0x78, 0x79, 0x10, 0xe2, 0x03, 0x12, 0x11, 0x0a, 0x0c, 0x57, 0x6f, 0x72, 0x6c, 0x64, 0x57, 0x65, + 0x61, 0x74, 0x68, 0x65, 0x72, 0x10, 0xe3, 0x03, 0x12, 0x0e, 0x0a, 0x09, 0x41, 0x70, 0x69, 0x46, + 0x6f, 0x6e, 0x69, 0x63, 0x61, 0x10, 0xe4, 0x03, 0x12, 0x0b, 0x0a, 0x06, 0x41, 0x79, 0x6c, 0x69, + 0x65, 0x6e, 0x10, 0xe5, 0x03, 0x12, 0x0c, 0x0a, 0x07, 0x47, 0x65, 0x6f, 0x63, 0x6f, 0x64, 0x65, + 0x10, 0xe6, 0x03, 0x12, 0x0f, 0x0a, 0x0a, 0x49, 0x63, 0x6f, 0x6e, 0x46, 0x69, 0x6e, 0x64, 0x65, + 0x72, 0x10, 0xe7, 0x03, 0x12, 0x0e, 0x0a, 0x05, 0x49, 0x70, 0x69, 0x66, 0x79, 0x10, 0xe8, 0x03, + 0x1a, 0x02, 0x08, 0x01, 0x12, 0x12, 0x0a, 0x0d, 0x4c, 0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65, + 0x4c, 0x61, 0x79, 0x65, 0x72, 0x10, 0xe9, 0x03, 0x12, 0x08, 0x0a, 0x03, 0x4c, 0x6f, 0x62, 0x10, + 0xea, 0x03, 0x12, 0x12, 0x0a, 0x09, 0x4f, 0x6e, 0x57, 0x61, 0x74, 0x65, 0x72, 0x49, 0x4f, 0x10, + 0xeb, 0x03, 0x1a, 0x02, 0x08, 0x01, 0x12, 0x0d, 0x0a, 0x08, 0x50, 0x61, 0x73, 0x74, 0x65, 0x62, + 0x69, 0x6e, 0x10, 0xec, 0x03, 0x12, 0x0d, 0x0a, 0x08, 0x50, 0x64, 0x66, 0x4c, 0x61, 0x79, 0x65, + 0x72, 0x10, 0xed, 0x03, 0x12, 0x0c, 0x0a, 0x07, 0x50, 0x69, 0x78, 0x61, 0x62, 0x61, 0x79, 0x10, + 0xee, 0x03, 0x12, 0x0b, 0x0a, 0x06, 0x52, 0x65, 0x61, 0x64, 0x4d, 0x65, 0x10, 0xef, 0x03, 0x12, + 0x0d, 0x0a, 0x08, 0x56, 0x61, 0x74, 0x4c, 0x61, 0x79, 0x65, 0x72, 0x10, 0xf0, 0x03, 0x12, 0x0f, + 0x0a, 0x0a, 0x56, 0x69, 0x72, 0x75, 0x73, 0x54, 0x6f, 0x74, 0x61, 0x6c, 0x10, 0xf1, 0x03, 0x12, + 0x0e, 0x0a, 0x09, 0x41, 0x69, 0x72, 0x56, 0x69, 0x73, 0x75, 0x61, 0x6c, 0x10, 0xf2, 0x03, 0x12, + 0x13, 0x0a, 0x0e, 0x43, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x66, 0x72, 0x65, 0x61, 0x6b, + 0x73, 0x10, 0xf3, 0x03, 0x12, 0x0b, 0x0a, 0x06, 0x44, 0x75, 0x66, 0x66, 0x65, 0x6c, 0x10, 0xf4, + 0x03, 0x12, 0x0b, 0x0a, 0x06, 0x46, 0x6c, 0x61, 0x74, 0x49, 0x4f, 0x10, 0xf5, 0x03, 0x12, 0x08, + 0x0a, 0x03, 0x4d, 0x33, 0x6f, 0x10, 0xf6, 0x03, 0x12, 0x0b, 0x0a, 0x06, 0x4d, 0x65, 0x73, 0x69, + 0x62, 0x6f, 0x10, 0xf7, 0x03, 0x12, 0x0b, 0x0a, 0x06, 0x4f, 0x70, 0x65, 0x6e, 0x75, 0x76, 0x10, + 0xf8, 0x03, 0x12, 0x0d, 0x0a, 0x08, 0x53, 0x6e, 0x69, 0x70, 0x63, 0x61, 0x72, 0x74, 0x10, 0xf9, + 0x03, 0x12, 0x0d, 0x0a, 0x08, 0x42, 0x65, 0x73, 0x74, 0x74, 0x69, 0x6d, 0x65, 0x10, 0xfa, 0x03, + 0x12, 0x10, 0x0a, 0x0b, 0x48, 0x61, 0x70, 0x70, 0x79, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x10, + 0xfb, 0x03, 0x12, 0x0d, 0x0a, 0x08, 0x48, 0x75, 0x6d, 0x61, 0x6e, 0x69, 0x74, 0x79, 0x10, 0xfc, + 0x03, 0x12, 0x0b, 0x0a, 0x06, 0x49, 0x6d, 0x70, 0x61, 0x6c, 0x61, 0x10, 0xfd, 0x03, 0x12, 0x10, + 0x0a, 0x0b, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x72, 0x61, 0x64, 0x69, 0x75, 0x73, 0x10, 0xfe, 0x03, + 0x12, 0x0e, 0x0a, 0x09, 0x41, 0x75, 0x74, 0x6f, 0x50, 0x69, 0x6c, 0x6f, 0x74, 0x10, 0xff, 0x03, + 0x12, 0x0b, 0x0a, 0x06, 0x42, 0x69, 0x74, 0x6d, 0x65, 0x78, 0x10, 0x80, 0x04, 0x12, 0x0d, 0x0a, + 0x08, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x44, 0x6f, 0x63, 0x10, 0x81, 0x04, 0x12, 0x0c, 0x0a, 0x07, + 0x4d, 0x65, 0x73, 0x73, 0x61, 0x72, 0x69, 0x10, 0x82, 0x04, 0x12, 0x0d, 0x0a, 0x08, 0x50, 0x64, + 0x66, 0x53, 0x68, 0x69, 0x66, 0x74, 0x10, 0x83, 0x04, 0x12, 0x0d, 0x0a, 0x08, 0x50, 0x6f, 0x6c, + 0x6f, 0x6e, 0x69, 0x65, 0x78, 0x10, 0x84, 0x04, 0x12, 0x19, 0x0a, 0x14, 0x52, 0x65, 0x73, 0x74, + 0x70, 0x61, 0x63, 0x6b, 0x48, 0x74, 0x6d, 0x6c, 0x54, 0x6f, 0x50, 0x64, 0x66, 0x41, 0x50, 0x49, + 0x10, 0x85, 0x04, 0x12, 0x1a, 0x0a, 0x15, 0x52, 0x65, 0x73, 0x74, 0x70, 0x61, 0x63, 0x6b, 0x53, + 0x63, 0x72, 0x65, 0x65, 0x6e, 0x73, 0x68, 0x6f, 0x74, 0x41, 0x50, 0x49, 0x10, 0x86, 0x04, 0x12, + 0x16, 0x0a, 0x11, 0x53, 0x68, 0x75, 0x74, 0x74, 0x65, 0x72, 0x73, 0x74, 0x6f, 0x63, 0x6b, 0x4f, + 0x41, 0x75, 0x74, 0x68, 0x10, 0x87, 0x04, 0x12, 0x10, 0x0a, 0x0b, 0x53, 0x6b, 0x79, 0x42, 0x69, + 0x6f, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x10, 0x88, 0x04, 0x12, 0x0e, 0x0a, 0x09, 0x41, 0x62, 0x75, + 0x73, 0x65, 0x49, 0x50, 0x44, 0x42, 0x10, 0x89, 0x04, 0x12, 0x10, 0x0a, 0x0b, 0x41, 0x6c, 0x65, + 0x74, 0x68, 0x65, 0x69, 0x61, 0x41, 0x70, 0x69, 0x10, 0x8a, 0x04, 0x12, 0x0c, 0x0a, 0x07, 0x42, + 0x6c, 0x69, 0x74, 0x41, 0x70, 0x70, 0x10, 0x8b, 0x04, 0x12, 0x0b, 0x0a, 0x06, 0x43, 0x65, 0x6e, + 0x73, 0x79, 0x73, 0x10, 0x8c, 0x04, 0x12, 0x0d, 0x0a, 0x08, 0x43, 0x6c, 0x6f, 0x76, 0x65, 0x72, + 0x6c, 0x79, 0x10, 0x8d, 0x04, 0x12, 0x11, 0x0a, 0x0c, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x72, 0x79, + 0x4c, 0x61, 0x79, 0x65, 0x72, 0x10, 0x8e, 0x04, 0x12, 0x0b, 0x0a, 0x06, 0x46, 0x69, 0x6c, 0x65, + 0x49, 0x4f, 0x10, 0x8f, 0x04, 0x12, 0x0e, 0x0a, 0x09, 0x46, 0x6c, 0x69, 0x67, 0x68, 0x74, 0x41, + 0x70, 0x69, 0x10, 0x90, 0x04, 0x12, 0x0d, 0x0a, 0x08, 0x47, 0x65, 0x6f, 0x61, 0x70, 0x69, 0x66, + 0x79, 0x10, 0x91, 0x04, 0x12, 0x0d, 0x0a, 0x08, 0x49, 0x50, 0x69, 0x6e, 0x66, 0x6f, 0x44, 0x42, + 0x10, 0x92, 0x04, 0x12, 0x0f, 0x0a, 0x0a, 0x4d, 0x65, 0x64, 0x69, 0x61, 0x53, 0x74, 0x61, 0x63, + 0x6b, 0x10, 0x93, 0x04, 0x12, 0x13, 0x0a, 0x0e, 0x4e, 0x61, 0x73, 0x64, 0x61, 0x71, 0x44, 0x61, + 0x74, 0x61, 0x4c, 0x69, 0x6e, 0x6b, 0x10, 0x94, 0x04, 0x12, 0x11, 0x0a, 0x0c, 0x4f, 0x70, 0x65, + 0x6e, 0x43, 0x61, 0x67, 0x65, 0x44, 0x61, 0x74, 0x61, 0x10, 0x95, 0x04, 0x12, 0x0d, 0x0a, 0x08, + 0x50, 0x61, 0x79, 0x6d, 0x6f, 0x6e, 0x67, 0x6f, 0x10, 0x96, 0x04, 0x12, 0x12, 0x0a, 0x0d, 0x50, + 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x63, 0x6b, 0x10, 0x97, 0x04, 0x12, + 0x0e, 0x0a, 0x09, 0x52, 0x65, 0x62, 0x72, 0x61, 0x6e, 0x64, 0x6c, 0x79, 0x10, 0x98, 0x04, 0x12, + 0x14, 0x0a, 0x0f, 0x53, 0x63, 0x72, 0x65, 0x65, 0x6e, 0x73, 0x68, 0x6f, 0x74, 0x4c, 0x61, 0x79, + 0x65, 0x72, 0x10, 0x99, 0x04, 0x12, 0x0b, 0x0a, 0x06, 0x53, 0x74, 0x79, 0x74, 0x63, 0x68, 0x10, + 0x9a, 0x04, 0x12, 0x0c, 0x0a, 0x07, 0x55, 0x6e, 0x70, 0x6c, 0x75, 0x67, 0x67, 0x10, 0x9b, 0x04, + 0x12, 0x10, 0x0a, 0x0b, 0x55, 0x50, 0x43, 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x10, + 0x9c, 0x04, 0x12, 0x0e, 0x0a, 0x09, 0x55, 0x73, 0x65, 0x72, 0x53, 0x74, 0x61, 0x63, 0x6b, 0x10, + 0x9d, 0x04, 0x12, 0x0e, 0x0a, 0x09, 0x47, 0x65, 0x6f, 0x63, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x10, + 0x9e, 0x04, 0x12, 0x10, 0x0a, 0x0b, 0x4e, 0x65, 0x77, 0x73, 0x63, 0x61, 0x74, 0x63, 0x68, 0x65, + 0x72, 0x10, 0x9f, 0x04, 0x12, 0x0e, 0x0a, 0x09, 0x4e, 0x69, 0x63, 0x65, 0x72, 0x65, 0x70, 0x6c, + 0x79, 0x10, 0xa0, 0x04, 0x12, 0x11, 0x0a, 0x0c, 0x50, 0x61, 0x72, 0x74, 0x6e, 0x65, 0x72, 0x73, + 0x74, 0x61, 0x63, 0x6b, 0x10, 0xa1, 0x04, 0x12, 0x0d, 0x0a, 0x08, 0x52, 0x6f, 0x75, 0x74, 0x65, + 0x34, 0x6d, 0x65, 0x10, 0xa2, 0x04, 0x12, 0x0e, 0x0a, 0x09, 0x53, 0x63, 0x72, 0x61, 0x70, 0x65, + 0x6f, 0x77, 0x6c, 0x10, 0xa3, 0x04, 0x12, 0x10, 0x0a, 0x0b, 0x53, 0x63, 0x72, 0x61, 0x70, 0x69, + 0x6e, 0x67, 0x44, 0x6f, 0x67, 0x10, 0xa4, 0x04, 0x12, 0x0b, 0x0a, 0x06, 0x53, 0x74, 0x72, 0x65, + 0x61, 0x6b, 0x10, 0xa5, 0x04, 0x12, 0x0e, 0x0a, 0x09, 0x56, 0x65, 0x72, 0x69, 0x70, 0x68, 0x6f, + 0x6e, 0x65, 0x10, 0xa6, 0x04, 0x12, 0x10, 0x0a, 0x0b, 0x57, 0x65, 0x62, 0x73, 0x63, 0x72, 0x61, + 0x70, 0x69, 0x6e, 0x67, 0x10, 0xa7, 0x04, 0x12, 0x0e, 0x0a, 0x09, 0x5a, 0x65, 0x6e, 0x73, 0x63, + 0x72, 0x61, 0x70, 0x65, 0x10, 0xa8, 0x04, 0x12, 0x0c, 0x0a, 0x07, 0x5a, 0x65, 0x6e, 0x73, 0x65, + 0x72, 0x70, 0x10, 0xa9, 0x04, 0x12, 0x0c, 0x0a, 0x07, 0x43, 0x6f, 0x69, 0x6e, 0x41, 0x70, 0x69, + 0x10, 0xaa, 0x04, 0x12, 0x0b, 0x0a, 0x06, 0x47, 0x69, 0x74, 0x74, 0x65, 0x72, 0x10, 0xab, 0x04, + 0x12, 0x09, 0x0a, 0x04, 0x48, 0x6f, 0x73, 0x74, 0x10, 0xac, 0x04, 0x12, 0x0d, 0x0a, 0x08, 0x49, + 0x65, 0x78, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x10, 0xad, 0x04, 0x12, 0x0d, 0x0a, 0x08, 0x52, 0x65, + 0x73, 0x74, 0x70, 0x61, 0x63, 0x6b, 0x10, 0xae, 0x04, 0x12, 0x0f, 0x0a, 0x0a, 0x53, 0x63, 0x72, + 0x61, 0x70, 0x65, 0x72, 0x42, 0x6f, 0x78, 0x10, 0xaf, 0x04, 0x12, 0x10, 0x0a, 0x0b, 0x53, 0x63, + 0x72, 0x61, 0x70, 0x69, 0x6e, 0x67, 0x41, 0x6e, 0x74, 0x10, 0xb0, 0x04, 0x12, 0x0e, 0x0a, 0x09, + 0x53, 0x65, 0x72, 0x70, 0x53, 0x74, 0x61, 0x63, 0x6b, 0x10, 0xb1, 0x04, 0x12, 0x12, 0x0a, 0x0d, + 0x53, 0x6d, 0x61, 0x72, 0x74, 0x79, 0x53, 0x74, 0x72, 0x65, 0x65, 0x74, 0x73, 0x10, 0xb2, 0x04, + 0x12, 0x11, 0x0a, 0x0c, 0x54, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x4d, 0x61, 0x73, 0x74, 0x65, 0x72, + 0x10, 0xb3, 0x04, 0x12, 0x12, 0x0a, 0x0d, 0x41, 0x76, 0x69, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, + 0x74, 0x61, 0x63, 0x6b, 0x10, 0xb4, 0x04, 0x12, 0x0d, 0x0a, 0x08, 0x42, 0x6f, 0x6d, 0x62, 0x42, + 0x6f, 0x6d, 0x62, 0x10, 0xb5, 0x04, 0x12, 0x10, 0x0a, 0x0b, 0x43, 0x6f, 0x6d, 0x6d, 0x6f, 0x64, + 0x69, 0x74, 0x69, 0x65, 0x73, 0x10, 0xb6, 0x04, 0x12, 0x0a, 0x0a, 0x05, 0x44, 0x66, 0x75, 0x73, + 0x65, 0x10, 0xb7, 0x04, 0x12, 0x0b, 0x0a, 0x06, 0x45, 0x64, 0x65, 0x6e, 0x41, 0x49, 0x10, 0xb8, + 0x04, 0x12, 0x0e, 0x0a, 0x09, 0x47, 0x6c, 0x61, 0x73, 0x73, 0x6e, 0x6f, 0x64, 0x65, 0x10, 0xb9, + 0x04, 0x12, 0x09, 0x0a, 0x04, 0x47, 0x75, 0x72, 0x75, 0x10, 0xba, 0x04, 0x12, 0x09, 0x0a, 0x04, + 0x48, 0x69, 0x76, 0x65, 0x10, 0xbb, 0x04, 0x12, 0x0c, 0x0a, 0x07, 0x48, 0x69, 0x76, 0x65, 0x61, + 0x67, 0x65, 0x10, 0xbc, 0x04, 0x12, 0x0c, 0x0a, 0x07, 0x4b, 0x69, 0x63, 0x6b, 0x62, 0x6f, 0x78, + 0x10, 0xbd, 0x04, 0x12, 0x11, 0x0a, 0x08, 0x50, 0x61, 0x73, 0x73, 0x62, 0x61, 0x73, 0x65, 0x10, + 0xbe, 0x04, 0x1a, 0x02, 0x08, 0x01, 0x12, 0x0f, 0x0a, 0x0a, 0x50, 0x6f, 0x73, 0x74, 0x61, 0x67, + 0x65, 0x41, 0x70, 0x70, 0x10, 0xbf, 0x04, 0x12, 0x0e, 0x0a, 0x09, 0x50, 0x75, 0x72, 0x65, 0x53, + 0x74, 0x61, 0x6b, 0x65, 0x10, 0xc0, 0x04, 0x12, 0x0b, 0x0a, 0x06, 0x51, 0x75, 0x62, 0x6f, 0x6c, + 0x65, 0x10, 0xc1, 0x04, 0x12, 0x14, 0x0a, 0x0f, 0x43, 0x61, 0x72, 0x62, 0x6f, 0x6e, 0x49, 0x6e, + 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, 0x10, 0xc2, 0x04, 0x12, 0x0d, 0x0a, 0x08, 0x49, 0x6e, + 0x74, 0x72, 0x69, 0x6e, 0x69, 0x6f, 0x10, 0xc3, 0x04, 0x12, 0x15, 0x0a, 0x0c, 0x51, 0x75, 0x69, + 0x63, 0x6b, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x10, 0xc4, 0x04, 0x1a, 0x02, 0x08, 0x01, + 0x12, 0x10, 0x0a, 0x0b, 0x53, 0x63, 0x72, 0x61, 0x70, 0x65, 0x53, 0x74, 0x61, 0x63, 0x6b, 0x10, + 0xc5, 0x04, 0x12, 0x19, 0x0a, 0x14, 0x54, 0x65, 0x63, 0x68, 0x6e, 0x69, 0x63, 0x61, 0x6c, 0x41, + 0x6e, 0x61, 0x6c, 0x79, 0x73, 0x69, 0x73, 0x41, 0x70, 0x69, 0x10, 0xc6, 0x04, 0x12, 0x0c, 0x0a, + 0x07, 0x55, 0x72, 0x6c, 0x73, 0x63, 0x61, 0x6e, 0x10, 0xc7, 0x04, 0x12, 0x0e, 0x0a, 0x09, 0x42, + 0x61, 0x73, 0x65, 0x41, 0x70, 0x69, 0x49, 0x4f, 0x10, 0xc8, 0x04, 0x12, 0x0c, 0x0a, 0x07, 0x44, + 0x61, 0x69, 0x6c, 0x79, 0x43, 0x4f, 0x10, 0xc9, 0x04, 0x12, 0x08, 0x0a, 0x03, 0x54, 0x4c, 0x79, + 0x10, 0xca, 0x04, 0x12, 0x0d, 0x0a, 0x08, 0x53, 0x68, 0x6f, 0x72, 0x74, 0x63, 0x75, 0x74, 0x10, + 0xcb, 0x04, 0x12, 0x0e, 0x0a, 0x09, 0x41, 0x70, 0x70, 0x66, 0x6f, 0x6c, 0x6c, 0x6f, 0x77, 0x10, + 0xcc, 0x04, 0x12, 0x0e, 0x0a, 0x09, 0x54, 0x68, 0x69, 0x6e, 0x6b, 0x69, 0x66, 0x69, 0x63, 0x10, + 0xcd, 0x04, 0x12, 0x0b, 0x0a, 0x06, 0x46, 0x65, 0x65, 0x64, 0x6c, 0x79, 0x10, 0xce, 0x04, 0x12, + 0x0f, 0x0a, 0x0a, 0x53, 0x74, 0x69, 0x74, 0x63, 0x68, 0x64, 0x61, 0x74, 0x61, 0x10, 0xcf, 0x04, + 0x12, 0x0d, 0x0a, 0x08, 0x46, 0x65, 0x74, 0x63, 0x68, 0x72, 0x73, 0x73, 0x10, 0xd0, 0x04, 0x12, + 0x11, 0x0a, 0x0c, 0x53, 0x69, 0x67, 0x6e, 0x75, 0x70, 0x67, 0x65, 0x6e, 0x69, 0x75, 0x73, 0x10, + 0xd1, 0x04, 0x12, 0x0f, 0x0a, 0x0a, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x69, 0x74, + 0x10, 0xd2, 0x04, 0x12, 0x0f, 0x0a, 0x0a, 0x4f, 0x70, 0x74, 0x69, 0x6d, 0x69, 0x7a, 0x65, 0x6c, + 0x79, 0x10, 0xd3, 0x04, 0x12, 0x0d, 0x0a, 0x08, 0x4f, 0x63, 0x72, 0x53, 0x70, 0x61, 0x63, 0x65, + 0x10, 0xd4, 0x04, 0x12, 0x0f, 0x0a, 0x0a, 0x57, 0x65, 0x61, 0x74, 0x68, 0x65, 0x72, 0x42, 0x69, + 0x74, 0x10, 0xd5, 0x04, 0x12, 0x0c, 0x0a, 0x07, 0x42, 0x75, 0x64, 0x64, 0x79, 0x4e, 0x53, 0x10, + 0xd6, 0x04, 0x12, 0x0b, 0x0a, 0x06, 0x5a, 0x69, 0x70, 0x41, 0x50, 0x49, 0x10, 0xd7, 0x04, 0x12, + 0x0d, 0x0a, 0x08, 0x5a, 0x69, 0x70, 0x42, 0x6f, 0x6f, 0x6b, 0x73, 0x10, 0xd8, 0x04, 0x12, 0x0c, + 0x0a, 0x07, 0x4f, 0x6e, 0x65, 0x64, 0x65, 0x73, 0x6b, 0x10, 0xd9, 0x04, 0x12, 0x0c, 0x0a, 0x07, + 0x42, 0x75, 0x67, 0x68, 0x65, 0x72, 0x64, 0x10, 0xda, 0x04, 0x12, 0x0f, 0x0a, 0x0a, 0x42, 0x6c, + 0x61, 0x7a, 0x65, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x10, 0xdb, 0x04, 0x12, 0x0d, 0x0a, 0x08, 0x41, + 0x75, 0x74, 0x6f, 0x64, 0x65, 0x73, 0x6b, 0x10, 0xdc, 0x04, 0x12, 0x08, 0x0a, 0x03, 0x54, 0x72, + 0x75, 0x10, 0xdd, 0x04, 0x12, 0x0c, 0x0a, 0x07, 0x55, 0x6e, 0x69, 0x66, 0x79, 0x49, 0x44, 0x10, + 0xde, 0x04, 0x12, 0x0c, 0x0a, 0x07, 0x54, 0x72, 0x69, 0x6d, 0x62, 0x6c, 0x65, 0x10, 0xdf, 0x04, + 0x12, 0x0b, 0x0a, 0x06, 0x53, 0x6d, 0x6f, 0x6f, 0x63, 0x68, 0x10, 0xe0, 0x04, 0x12, 0x0e, 0x0a, + 0x09, 0x53, 0x65, 0x6d, 0x61, 0x70, 0x68, 0x6f, 0x72, 0x65, 0x10, 0xe1, 0x04, 0x12, 0x0b, 0x0a, + 0x06, 0x54, 0x65, 0x6c, 0x6e, 0x79, 0x78, 0x10, 0xe2, 0x04, 0x12, 0x0f, 0x0a, 0x0a, 0x53, 0x69, + 0x67, 0x6e, 0x61, 0x6c, 0x77, 0x69, 0x72, 0x65, 0x10, 0xe3, 0x04, 0x12, 0x0e, 0x0a, 0x09, 0x54, + 0x65, 0x78, 0x74, 0x6d, 0x61, 0x67, 0x69, 0x63, 0x10, 0xe4, 0x04, 0x12, 0x0e, 0x0a, 0x09, 0x53, + 0x65, 0x72, 0x70, 0x68, 0x6f, 0x75, 0x73, 0x65, 0x10, 0xe5, 0x04, 0x12, 0x0b, 0x0a, 0x06, 0x50, + 0x6c, 0x61, 0x6e, 0x79, 0x6f, 0x10, 0xe6, 0x04, 0x12, 0x0f, 0x0a, 0x0a, 0x53, 0x69, 0x6d, 0x70, + 0x6c, 0x79, 0x62, 0x6f, 0x6f, 0x6b, 0x10, 0xe7, 0x04, 0x12, 0x09, 0x0a, 0x04, 0x56, 0x79, 0x74, + 0x65, 0x10, 0xe8, 0x04, 0x12, 0x0a, 0x0a, 0x05, 0x4e, 0x79, 0x6c, 0x61, 0x73, 0x10, 0xe9, 0x04, + 0x12, 0x0d, 0x0a, 0x08, 0x53, 0x71, 0x75, 0x61, 0x72, 0x65, 0x75, 0x70, 0x10, 0xea, 0x04, 0x12, + 0x0e, 0x0a, 0x09, 0x44, 0x61, 0x6e, 0x64, 0x65, 0x6c, 0x69, 0x6f, 0x6e, 0x10, 0xeb, 0x04, 0x12, + 0x11, 0x0a, 0x08, 0x44, 0x61, 0x74, 0x61, 0x46, 0x69, 0x72, 0x65, 0x10, 0xec, 0x04, 0x1a, 0x02, + 0x08, 0x01, 0x12, 0x0b, 0x0a, 0x06, 0x44, 0x65, 0x65, 0x70, 0x41, 0x49, 0x10, 0xed, 0x04, 0x12, + 0x11, 0x0a, 0x0c, 0x4d, 0x65, 0x61, 0x6e, 0x69, 0x6e, 0x67, 0x43, 0x6c, 0x6f, 0x75, 0x64, 0x10, + 0xee, 0x04, 0x12, 0x10, 0x0a, 0x0b, 0x4e, 0x65, 0x75, 0x74, 0x72, 0x69, 0x6e, 0x6f, 0x41, 0x70, + 0x69, 0x10, 0xef, 0x04, 0x12, 0x0e, 0x0a, 0x09, 0x53, 0x74, 0x6f, 0x72, 0x65, 0x63, 0x6f, 0x76, + 0x65, 0x10, 0xf0, 0x04, 0x12, 0x0c, 0x0a, 0x07, 0x53, 0x68, 0x69, 0x70, 0x64, 0x61, 0x79, 0x10, + 0xf1, 0x04, 0x12, 0x12, 0x0a, 0x09, 0x53, 0x65, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x6e, 0x74, 0x10, + 0xf2, 0x04, 0x1a, 0x02, 0x08, 0x01, 0x12, 0x18, 0x0a, 0x13, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, + 0x43, 0x68, 0x61, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x69, 0x6e, 0x67, 0x10, 0xf3, 0x04, + 0x12, 0x10, 0x0a, 0x0b, 0x54, 0x65, 0x61, 0x6d, 0x77, 0x6f, 0x72, 0x6b, 0x43, 0x52, 0x4d, 0x10, + 0xf4, 0x04, 0x12, 0x11, 0x0a, 0x0c, 0x54, 0x65, 0x61, 0x6d, 0x77, 0x6f, 0x72, 0x6b, 0x44, 0x65, + 0x73, 0x6b, 0x10, 0xf5, 0x04, 0x12, 0x13, 0x0a, 0x0e, 0x54, 0x65, 0x61, 0x6d, 0x77, 0x6f, 0x72, + 0x6b, 0x53, 0x70, 0x61, 0x63, 0x65, 0x73, 0x10, 0xf6, 0x04, 0x12, 0x0f, 0x0a, 0x0a, 0x54, 0x68, + 0x65, 0x4f, 0x64, 0x64, 0x73, 0x41, 0x70, 0x69, 0x10, 0xf7, 0x04, 0x12, 0x0b, 0x0a, 0x06, 0x41, + 0x70, 0x61, 0x63, 0x74, 0x61, 0x10, 0xf8, 0x04, 0x12, 0x0f, 0x0a, 0x0a, 0x47, 0x65, 0x74, 0x53, + 0x61, 0x6e, 0x64, 0x62, 0x6f, 0x78, 0x10, 0xf9, 0x04, 0x12, 0x0e, 0x0a, 0x05, 0x48, 0x61, 0x70, + 0x70, 0x69, 0x10, 0xfa, 0x04, 0x1a, 0x02, 0x08, 0x01, 0x12, 0x0a, 0x0a, 0x05, 0x4f, 0x61, 0x6e, + 0x64, 0x61, 0x10, 0xfb, 0x04, 0x12, 0x0e, 0x0a, 0x09, 0x46, 0x61, 0x73, 0x74, 0x46, 0x6f, 0x72, + 0x65, 0x78, 0x10, 0xfc, 0x04, 0x12, 0x0d, 0x0a, 0x08, 0x41, 0x50, 0x49, 0x4d, 0x61, 0x74, 0x69, + 0x63, 0x10, 0xfd, 0x04, 0x12, 0x0f, 0x0a, 0x0a, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x45, + 0x79, 0x65, 0x10, 0xfe, 0x04, 0x12, 0x15, 0x0a, 0x10, 0x45, 0x61, 0x67, 0x6c, 0x65, 0x45, 0x79, + 0x65, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x10, 0xff, 0x04, 0x12, 0x11, 0x0a, 0x0c, + 0x54, 0x68, 0x6f, 0x75, 0x73, 0x61, 0x6e, 0x64, 0x45, 0x79, 0x65, 0x73, 0x10, 0x80, 0x05, 0x12, + 0x0e, 0x0a, 0x09, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x50, 0x44, 0x46, 0x10, 0x81, 0x05, 0x12, + 0x10, 0x0a, 0x0b, 0x46, 0x6c, 0x69, 0x67, 0x68, 0x74, 0x73, 0x74, 0x61, 0x74, 0x73, 0x10, 0x82, + 0x05, 0x12, 0x0b, 0x0a, 0x06, 0x43, 0x68, 0x65, 0x63, 0x49, 0x4f, 0x10, 0x83, 0x05, 0x12, 0x0d, + 0x0a, 0x08, 0x4d, 0x61, 0x6e, 0x69, 0x66, 0x65, 0x73, 0x74, 0x10, 0x84, 0x05, 0x12, 0x0f, 0x0a, + 0x0a, 0x41, 0x70, 0x69, 0x53, 0x63, 0x69, 0x65, 0x6e, 0x63, 0x65, 0x10, 0x85, 0x05, 0x12, 0x0f, + 0x0a, 0x0a, 0x41, 0x70, 0x70, 0x53, 0x79, 0x6e, 0x65, 0x72, 0x67, 0x79, 0x10, 0x86, 0x05, 0x12, + 0x0b, 0x0a, 0x06, 0x43, 0x61, 0x66, 0x6c, 0x6f, 0x75, 0x10, 0x87, 0x05, 0x12, 0x0b, 0x0a, 0x06, + 0x43, 0x61, 0x73, 0x70, 0x69, 0x6f, 0x10, 0x88, 0x05, 0x12, 0x0e, 0x0a, 0x09, 0x43, 0x68, 0x65, + 0x63, 0x6b, 0x6c, 0x79, 0x48, 0x51, 0x10, 0x89, 0x05, 0x12, 0x12, 0x0a, 0x0d, 0x43, 0x6c, 0x6f, + 0x75, 0x64, 0x45, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x10, 0x8a, 0x05, 0x12, 0x0c, 0x0a, + 0x07, 0x44, 0x72, 0x6f, 0x6e, 0x61, 0x48, 0x51, 0x10, 0x8b, 0x05, 0x12, 0x0c, 0x0a, 0x07, 0x45, + 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x78, 0x10, 0x8c, 0x05, 0x12, 0x09, 0x0a, 0x04, 0x46, 0x6d, 0x66, + 0x77, 0x10, 0x8d, 0x05, 0x12, 0x0c, 0x0a, 0x07, 0x47, 0x6f, 0x6f, 0x64, 0x44, 0x61, 0x79, 0x10, + 0x8e, 0x05, 0x12, 0x09, 0x0a, 0x04, 0x4c, 0x75, 0x6e, 0x6f, 0x10, 0x8f, 0x05, 0x12, 0x10, 0x0a, + 0x0b, 0x4d, 0x65, 0x69, 0x73, 0x74, 0x65, 0x72, 0x74, 0x61, 0x73, 0x6b, 0x10, 0x90, 0x05, 0x12, + 0x10, 0x0a, 0x0b, 0x4d, 0x69, 0x6e, 0x64, 0x6d, 0x65, 0x69, 0x73, 0x74, 0x65, 0x72, 0x10, 0x91, + 0x05, 0x12, 0x13, 0x0a, 0x0e, 0x50, 0x65, 0x6f, 0x70, 0x6c, 0x65, 0x44, 0x61, 0x74, 0x61, 0x4c, + 0x61, 0x62, 0x73, 0x10, 0x92, 0x05, 0x12, 0x14, 0x0a, 0x0b, 0x53, 0x63, 0x72, 0x61, 0x70, 0x65, + 0x72, 0x53, 0x69, 0x74, 0x65, 0x10, 0x93, 0x05, 0x1a, 0x02, 0x08, 0x01, 0x12, 0x0d, 0x0a, 0x08, + 0x53, 0x63, 0x72, 0x61, 0x70, 0x66, 0x6c, 0x79, 0x10, 0x94, 0x05, 0x12, 0x10, 0x0a, 0x0b, 0x53, + 0x69, 0x6d, 0x70, 0x6c, 0x79, 0x4e, 0x6f, 0x74, 0x65, 0x64, 0x10, 0x95, 0x05, 0x12, 0x12, 0x0a, + 0x0d, 0x54, 0x72, 0x61, 0x76, 0x65, 0x6c, 0x50, 0x61, 0x79, 0x6f, 0x75, 0x74, 0x73, 0x10, 0x96, + 0x05, 0x12, 0x0f, 0x0a, 0x0a, 0x57, 0x65, 0x62, 0x53, 0x63, 0x72, 0x61, 0x70, 0x65, 0x72, 0x10, + 0x97, 0x05, 0x12, 0x0c, 0x0a, 0x07, 0x43, 0x6f, 0x6e, 0x76, 0x69, 0x65, 0x72, 0x10, 0x98, 0x05, + 0x12, 0x0c, 0x0a, 0x07, 0x43, 0x6f, 0x75, 0x72, 0x69, 0x65, 0x72, 0x10, 0x99, 0x05, 0x12, 0x0a, + 0x0a, 0x05, 0x44, 0x69, 0x74, 0x74, 0x6f, 0x10, 0x9a, 0x05, 0x12, 0x0a, 0x0a, 0x05, 0x46, 0x69, + 0x6e, 0x64, 0x6c, 0x10, 0x9b, 0x05, 0x12, 0x0d, 0x0a, 0x08, 0x4c, 0x65, 0x6e, 0x64, 0x66, 0x6c, + 0x6f, 0x77, 0x10, 0x9c, 0x05, 0x12, 0x0f, 0x0a, 0x0a, 0x4d, 0x6f, 0x64, 0x65, 0x72, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x10, 0x9d, 0x05, 0x12, 0x11, 0x0a, 0x0c, 0x4f, 0x70, 0x65, 0x6e, 0x64, 0x61, + 0x74, 0x61, 0x73, 0x6f, 0x66, 0x74, 0x10, 0x9e, 0x05, 0x12, 0x0a, 0x0a, 0x05, 0x50, 0x6f, 0x64, + 0x69, 0x6f, 0x10, 0x9f, 0x05, 0x12, 0x0c, 0x0a, 0x07, 0x52, 0x6f, 0x63, 0x6b, 0x73, 0x65, 0x74, + 0x10, 0xa0, 0x05, 0x12, 0x0a, 0x0a, 0x05, 0x52, 0x6f, 0x77, 0x6e, 0x64, 0x10, 0xa1, 0x05, 0x12, + 0x0e, 0x0a, 0x09, 0x53, 0x68, 0x6f, 0x74, 0x73, 0x74, 0x61, 0x63, 0x6b, 0x10, 0xa2, 0x05, 0x12, + 0x0d, 0x0a, 0x08, 0x53, 0x77, 0x69, 0x66, 0x74, 0x79, 0x70, 0x65, 0x10, 0xa3, 0x05, 0x12, 0x0c, + 0x0a, 0x07, 0x54, 0x77, 0x69, 0x74, 0x74, 0x65, 0x72, 0x10, 0xa4, 0x05, 0x12, 0x0a, 0x0a, 0x05, + 0x48, 0x6f, 0x6e, 0x65, 0x79, 0x10, 0xa5, 0x05, 0x12, 0x0e, 0x0a, 0x09, 0x46, 0x72, 0x65, 0x73, + 0x68, 0x64, 0x65, 0x73, 0x6b, 0x10, 0xa6, 0x05, 0x12, 0x0b, 0x0a, 0x06, 0x55, 0x70, 0x77, 0x61, + 0x76, 0x65, 0x10, 0xa7, 0x05, 0x12, 0x0d, 0x0a, 0x08, 0x46, 0x6f, 0x75, 0x6e, 0x74, 0x61, 0x69, + 0x6e, 0x10, 0xa8, 0x05, 0x12, 0x0f, 0x0a, 0x0a, 0x46, 0x72, 0x65, 0x73, 0x68, 0x62, 0x6f, 0x6f, + 0x6b, 0x73, 0x10, 0xa9, 0x05, 0x12, 0x09, 0x0a, 0x04, 0x4d, 0x69, 0x74, 0x65, 0x10, 0xaa, 0x05, + 0x12, 0x0b, 0x0a, 0x06, 0x44, 0x65, 0x70, 0x75, 0x74, 0x79, 0x10, 0xab, 0x05, 0x12, 0x0c, 0x0a, + 0x07, 0x42, 0x65, 0x65, 0x62, 0x6f, 0x6c, 0x65, 0x10, 0xac, 0x05, 0x12, 0x0e, 0x0a, 0x09, 0x43, + 0x61, 0x73, 0x68, 0x62, 0x6f, 0x61, 0x72, 0x64, 0x10, 0xad, 0x05, 0x12, 0x0b, 0x0a, 0x06, 0x4b, + 0x61, 0x6e, 0x62, 0x61, 0x6e, 0x10, 0xae, 0x05, 0x12, 0x0e, 0x0a, 0x09, 0x57, 0x6f, 0x72, 0x6b, + 0x73, 0x6e, 0x61, 0x70, 0x73, 0x10, 0xaf, 0x05, 0x12, 0x10, 0x0a, 0x0b, 0x4d, 0x79, 0x49, 0x6e, + 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x73, 0x10, 0xb0, 0x05, 0x12, 0x11, 0x0a, 0x0c, 0x49, 0x6e, + 0x76, 0x6f, 0x69, 0x63, 0x65, 0x4f, 0x63, 0x65, 0x61, 0x6e, 0x10, 0xb1, 0x05, 0x12, 0x0f, 0x0a, + 0x0a, 0x53, 0x68, 0x65, 0x72, 0x70, 0x61, 0x64, 0x65, 0x73, 0x6b, 0x10, 0xb2, 0x05, 0x12, 0x0f, + 0x0a, 0x0a, 0x4d, 0x72, 0x74, 0x69, 0x63, 0x6b, 0x74, 0x6f, 0x63, 0x6b, 0x10, 0xb3, 0x05, 0x12, + 0x0d, 0x0a, 0x08, 0x43, 0x68, 0x61, 0x74, 0x66, 0x75, 0x6c, 0x65, 0x10, 0xb4, 0x05, 0x12, 0x11, + 0x0a, 0x0c, 0x41, 0x65, 0x72, 0x6f, 0x77, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x10, 0xb5, + 0x05, 0x12, 0x11, 0x0a, 0x0c, 0x45, 0x6d, 0x61, 0x69, 0x6c, 0x6f, 0x63, 0x74, 0x6f, 0x70, 0x75, + 0x73, 0x10, 0xb6, 0x05, 0x12, 0x11, 0x0a, 0x08, 0x46, 0x75, 0x73, 0x65, 0x62, 0x69, 0x6c, 0x6c, + 0x10, 0xb7, 0x05, 0x1a, 0x02, 0x08, 0x01, 0x12, 0x0f, 0x0a, 0x0a, 0x47, 0x65, 0x63, 0x6b, 0x6f, + 0x62, 0x6f, 0x61, 0x72, 0x64, 0x10, 0xb8, 0x05, 0x12, 0x0e, 0x0a, 0x09, 0x47, 0x6f, 0x73, 0x71, + 0x75, 0x61, 0x72, 0x65, 0x64, 0x10, 0xb9, 0x05, 0x12, 0x0e, 0x0a, 0x09, 0x4d, 0x6f, 0x6f, 0x6e, + 0x63, 0x6c, 0x65, 0x72, 0x6b, 0x10, 0xba, 0x05, 0x12, 0x0d, 0x0a, 0x08, 0x50, 0x61, 0x79, 0x6d, + 0x6f, 0x61, 0x70, 0x70, 0x10, 0xbb, 0x05, 0x12, 0x0b, 0x0a, 0x06, 0x4d, 0x69, 0x78, 0x6d, 0x61, + 0x78, 0x10, 0xbc, 0x05, 0x12, 0x0e, 0x0a, 0x09, 0x50, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x73, + 0x74, 0x10, 0xbd, 0x05, 0x12, 0x10, 0x0a, 0x0b, 0x52, 0x65, 0x70, 0x61, 0x69, 0x72, 0x73, 0x68, + 0x6f, 0x70, 0x72, 0x10, 0xbe, 0x05, 0x12, 0x0d, 0x0a, 0x08, 0x47, 0x6f, 0x73, 0x68, 0x69, 0x70, + 0x70, 0x6f, 0x10, 0xbf, 0x05, 0x12, 0x0b, 0x0a, 0x06, 0x53, 0x69, 0x67, 0x6f, 0x70, 0x74, 0x10, + 0xc0, 0x05, 0x12, 0x0d, 0x0a, 0x08, 0x53, 0x75, 0x67, 0x65, 0x73, 0x74, 0x65, 0x72, 0x10, 0xc1, + 0x05, 0x12, 0x0c, 0x0a, 0x07, 0x56, 0x69, 0x65, 0x77, 0x6e, 0x65, 0x6f, 0x10, 0xc2, 0x05, 0x12, + 0x0e, 0x0a, 0x09, 0x42, 0x6f, 0x6f, 0x73, 0x74, 0x4e, 0x6f, 0x74, 0x65, 0x10, 0xc3, 0x05, 0x12, + 0x10, 0x0a, 0x0b, 0x43, 0x61, 0x70, 0x74, 0x61, 0x69, 0x6e, 0x44, 0x61, 0x74, 0x61, 0x10, 0xc4, + 0x05, 0x12, 0x0e, 0x0a, 0x09, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x76, 0x69, 0x73, 0x74, 0x10, 0xc5, + 0x05, 0x12, 0x0c, 0x0a, 0x07, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x67, 0x6f, 0x10, 0xc6, 0x05, 0x12, + 0x0a, 0x0a, 0x05, 0x43, 0x6c, 0x6f, 0x7a, 0x65, 0x10, 0xc7, 0x05, 0x12, 0x0b, 0x0a, 0x06, 0x46, + 0x6f, 0x72, 0x6d, 0x49, 0x4f, 0x10, 0xc8, 0x05, 0x12, 0x0f, 0x0a, 0x0a, 0x46, 0x6f, 0x72, 0x6d, + 0x42, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x10, 0xc9, 0x05, 0x12, 0x0d, 0x0a, 0x08, 0x47, 0x6f, 0x43, + 0x61, 0x6e, 0x76, 0x61, 0x73, 0x10, 0xca, 0x05, 0x12, 0x0c, 0x0a, 0x07, 0x4d, 0x61, 0x64, 0x4b, + 0x75, 0x64, 0x75, 0x10, 0xcb, 0x05, 0x12, 0x0f, 0x0a, 0x0a, 0x4e, 0x6f, 0x7a, 0x62, 0x65, 0x54, + 0x65, 0x61, 0x6d, 0x73, 0x10, 0xcc, 0x05, 0x12, 0x0b, 0x0a, 0x06, 0x50, 0x61, 0x70, 0x79, 0x72, + 0x73, 0x10, 0xcd, 0x05, 0x12, 0x12, 0x0a, 0x0d, 0x53, 0x75, 0x70, 0x65, 0x72, 0x4e, 0x6f, 0x74, + 0x65, 0x73, 0x41, 0x50, 0x49, 0x10, 0xce, 0x05, 0x12, 0x0c, 0x0a, 0x07, 0x54, 0x61, 0x6c, 0x6c, + 0x79, 0x66, 0x79, 0x10, 0xcf, 0x05, 0x12, 0x0e, 0x0a, 0x09, 0x5a, 0x65, 0x6e, 0x6b, 0x69, 0x74, + 0x41, 0x50, 0x49, 0x10, 0xd0, 0x05, 0x12, 0x0f, 0x0a, 0x0a, 0x43, 0x6c, 0x6f, 0x75, 0x64, 0x49, + 0x6d, 0x61, 0x67, 0x65, 0x10, 0xd1, 0x05, 0x12, 0x0f, 0x0a, 0x0a, 0x55, 0x70, 0x6c, 0x6f, 0x61, + 0x64, 0x43, 0x61, 0x72, 0x65, 0x10, 0xd2, 0x05, 0x12, 0x0d, 0x0a, 0x08, 0x42, 0x6f, 0x72, 0x67, + 0x62, 0x61, 0x73, 0x65, 0x10, 0xd3, 0x05, 0x12, 0x0e, 0x0a, 0x09, 0x50, 0x69, 0x70, 0x65, 0x64, + 0x72, 0x65, 0x61, 0x6d, 0x10, 0xd4, 0x05, 0x12, 0x09, 0x0a, 0x04, 0x53, 0x69, 0x72, 0x76, 0x10, + 0xd5, 0x05, 0x12, 0x0c, 0x0a, 0x07, 0x44, 0x69, 0x66, 0x66, 0x62, 0x6f, 0x74, 0x10, 0xd6, 0x05, + 0x12, 0x10, 0x0a, 0x0b, 0x45, 0x69, 0x67, 0x68, 0x74, 0x78, 0x45, 0x69, 0x67, 0x68, 0x74, 0x10, + 0xd7, 0x05, 0x12, 0x0c, 0x0a, 0x07, 0x53, 0x65, 0x6e, 0x64, 0x6f, 0x73, 0x6f, 0x10, 0xd8, 0x05, + 0x12, 0x11, 0x0a, 0x0c, 0x50, 0x72, 0x69, 0x6e, 0x74, 0x66, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, + 0x10, 0xd9, 0x05, 0x12, 0x0e, 0x0a, 0x09, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, + 0x10, 0xda, 0x05, 0x12, 0x0f, 0x0a, 0x0a, 0x50, 0x61, 0x6e, 0x64, 0x61, 0x53, 0x63, 0x6f, 0x72, + 0x65, 0x10, 0xdb, 0x05, 0x12, 0x0a, 0x0a, 0x05, 0x50, 0x61, 0x79, 0x6d, 0x6f, 0x10, 0xdc, 0x05, + 0x12, 0x1d, 0x0a, 0x18, 0x41, 0x76, 0x61, 0x7a, 0x61, 0x50, 0x65, 0x72, 0x73, 0x6f, 0x6e, 0x61, + 0x6c, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x10, 0xdd, 0x05, 0x12, + 0x14, 0x0a, 0x0f, 0x50, 0x6c, 0x61, 0x6e, 0x76, 0x69, 0x65, 0x77, 0x4c, 0x65, 0x61, 0x6e, 0x4b, + 0x69, 0x74, 0x10, 0xde, 0x05, 0x12, 0x0e, 0x0a, 0x09, 0x4c, 0x69, 0x76, 0x65, 0x73, 0x74, 0x6f, + 0x72, 0x6d, 0x10, 0xdf, 0x05, 0x12, 0x0b, 0x0a, 0x06, 0x4b, 0x75, 0x43, 0x6f, 0x69, 0x6e, 0x10, + 0xe0, 0x05, 0x12, 0x0c, 0x0a, 0x07, 0x4d, 0x65, 0x74, 0x61, 0x41, 0x50, 0x49, 0x10, 0xe1, 0x05, + 0x12, 0x0d, 0x0a, 0x08, 0x4e, 0x69, 0x63, 0x65, 0x48, 0x61, 0x73, 0x68, 0x10, 0xe2, 0x05, 0x12, + 0x0a, 0x0a, 0x05, 0x43, 0x65, 0x78, 0x49, 0x4f, 0x10, 0xe3, 0x05, 0x12, 0x0e, 0x0a, 0x09, 0x4b, + 0x6c, 0x69, 0x70, 0x66, 0x6f, 0x6c, 0x69, 0x6f, 0x10, 0xe4, 0x05, 0x12, 0x0e, 0x0a, 0x09, 0x44, + 0x79, 0x6e, 0x61, 0x74, 0x72, 0x61, 0x63, 0x65, 0x10, 0xe5, 0x05, 0x12, 0x11, 0x0a, 0x0c, 0x4d, + 0x6f, 0x6c, 0x6c, 0x69, 0x65, 0x41, 0x50, 0x49, 0x4b, 0x65, 0x79, 0x10, 0xe6, 0x05, 0x12, 0x16, + 0x0a, 0x11, 0x4d, 0x6f, 0x6c, 0x6c, 0x69, 0x65, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x54, 0x6f, + 0x6b, 0x65, 0x6e, 0x10, 0xe7, 0x05, 0x12, 0x10, 0x0a, 0x0b, 0x42, 0x61, 0x73, 0x69, 0x73, 0x54, + 0x68, 0x65, 0x6f, 0x72, 0x79, 0x10, 0xe8, 0x05, 0x12, 0x0d, 0x0a, 0x08, 0x4e, 0x6f, 0x72, 0x64, + 0x69, 0x67, 0x65, 0x6e, 0x10, 0xe9, 0x05, 0x12, 0x1c, 0x0a, 0x17, 0x46, 0x6c, 0x61, 0x67, 0x73, + 0x6d, 0x69, 0x74, 0x68, 0x45, 0x6e, 0x76, 0x69, 0x72, 0x6f, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x4b, + 0x65, 0x79, 0x10, 0xea, 0x05, 0x12, 0x13, 0x0a, 0x0e, 0x46, 0x6c, 0x61, 0x67, 0x73, 0x6d, 0x69, + 0x74, 0x68, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x10, 0xeb, 0x05, 0x12, 0x08, 0x0a, 0x03, 0x4d, 0x75, + 0x78, 0x10, 0xec, 0x05, 0x12, 0x0b, 0x0a, 0x06, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x10, 0xed, + 0x05, 0x12, 0x0d, 0x0a, 0x08, 0x53, 0x65, 0x6e, 0x64, 0x62, 0x69, 0x72, 0x64, 0x10, 0xee, 0x05, + 0x12, 0x1c, 0x0a, 0x17, 0x53, 0x65, 0x6e, 0x64, 0x62, 0x69, 0x72, 0x64, 0x4f, 0x72, 0x67, 0x61, + 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x41, 0x50, 0x49, 0x10, 0xef, 0x05, 0x12, 0x0b, + 0x0a, 0x06, 0x4d, 0x69, 0x64, 0x69, 0x73, 0x65, 0x10, 0xf0, 0x05, 0x12, 0x0d, 0x0a, 0x08, 0x4d, + 0x6f, 0x63, 0x6b, 0x61, 0x72, 0x6f, 0x6f, 0x10, 0xf1, 0x05, 0x12, 0x0b, 0x0a, 0x06, 0x49, 0x6d, + 0x61, 0x67, 0x65, 0x34, 0x10, 0xf2, 0x05, 0x12, 0x0b, 0x0a, 0x06, 0x50, 0x69, 0x6e, 0x61, 0x74, + 0x61, 0x10, 0xf3, 0x05, 0x12, 0x11, 0x0a, 0x0c, 0x42, 0x72, 0x6f, 0x77, 0x73, 0x65, 0x72, 0x53, + 0x74, 0x61, 0x63, 0x6b, 0x10, 0xf4, 0x05, 0x12, 0x1c, 0x0a, 0x13, 0x43, 0x72, 0x6f, 0x73, 0x73, + 0x42, 0x72, 0x6f, 0x77, 0x73, 0x65, 0x72, 0x54, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x10, 0xf5, + 0x05, 0x1a, 0x02, 0x08, 0x01, 0x12, 0x0d, 0x0a, 0x08, 0x4c, 0x6f, 0x61, 0x64, 0x6d, 0x69, 0x6c, + 0x6c, 0x10, 0xf6, 0x05, 0x12, 0x0f, 0x0a, 0x0a, 0x54, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x42, + 0x6f, 0x74, 0x10, 0xf7, 0x05, 0x12, 0x10, 0x0a, 0x0b, 0x4b, 0x6e, 0x61, 0x70, 0x73, 0x61, 0x63, + 0x6b, 0x50, 0x72, 0x6f, 0x10, 0xf8, 0x05, 0x12, 0x09, 0x0a, 0x04, 0x51, 0x61, 0x73, 0x65, 0x10, + 0xf9, 0x05, 0x12, 0x0e, 0x0a, 0x09, 0x44, 0x61, 0x72, 0x65, 0x62, 0x6f, 0x6f, 0x73, 0x74, 0x10, + 0xfa, 0x05, 0x12, 0x0d, 0x0a, 0x08, 0x47, 0x54, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x78, 0x10, 0xfb, + 0x05, 0x12, 0x0d, 0x0a, 0x08, 0x48, 0x6f, 0x6c, 0x69, 0x73, 0x74, 0x69, 0x63, 0x10, 0xfc, 0x05, + 0x12, 0x0c, 0x0a, 0x07, 0x50, 0x61, 0x72, 0x73, 0x65, 0x72, 0x73, 0x10, 0xfd, 0x05, 0x12, 0x12, + 0x0a, 0x0d, 0x53, 0x63, 0x72, 0x75, 0x74, 0x69, 0x6e, 0x69, 0x7a, 0x65, 0x72, 0x43, 0x69, 0x10, + 0xfe, 0x05, 0x12, 0x0f, 0x0a, 0x0a, 0x53, 0x6f, 0x6e, 0x61, 0x72, 0x43, 0x6c, 0x6f, 0x75, 0x64, + 0x10, 0xff, 0x05, 0x12, 0x10, 0x0a, 0x0b, 0x41, 0x50, 0x49, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, + 0x74, 0x65, 0x10, 0x80, 0x06, 0x12, 0x14, 0x0a, 0x0f, 0x43, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x73, + 0x69, 0x6f, 0x6e, 0x54, 0x6f, 0x6f, 0x6c, 0x73, 0x10, 0x81, 0x06, 0x12, 0x0f, 0x0a, 0x0a, 0x43, + 0x72, 0x61, 0x66, 0x74, 0x4d, 0x79, 0x50, 0x44, 0x46, 0x10, 0x82, 0x06, 0x12, 0x0e, 0x0a, 0x09, + 0x45, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x53, 0x44, 0x4b, 0x10, 0x83, 0x06, 0x12, 0x15, 0x0a, 0x0c, + 0x47, 0x6c, 0x69, 0x74, 0x74, 0x65, 0x72, 0x6c, 0x79, 0x41, 0x50, 0x49, 0x10, 0x84, 0x06, 0x1a, + 0x02, 0x08, 0x01, 0x12, 0x0d, 0x0a, 0x08, 0x48, 0x79, 0x62, 0x69, 0x73, 0x63, 0x75, 0x73, 0x10, + 0x85, 0x06, 0x12, 0x09, 0x0a, 0x04, 0x4d, 0x69, 0x72, 0x6f, 0x10, 0x86, 0x06, 0x12, 0x0f, 0x0a, + 0x0a, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x70, 0x61, 0x67, 0x65, 0x10, 0x87, 0x06, 0x12, 0x0e, + 0x0a, 0x09, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x70, 0x61, 0x6c, 0x10, 0x88, 0x06, 0x12, 0x0d, + 0x0a, 0x08, 0x54, 0x65, 0x6c, 0x65, 0x74, 0x79, 0x70, 0x65, 0x10, 0x89, 0x06, 0x12, 0x0d, 0x0a, + 0x08, 0x54, 0x69, 0x6d, 0x65, 0x43, 0x61, 0x6d, 0x70, 0x10, 0x8a, 0x06, 0x12, 0x0d, 0x0a, 0x08, + 0x55, 0x73, 0x65, 0x72, 0x66, 0x6c, 0x6f, 0x77, 0x10, 0x8b, 0x06, 0x12, 0x0b, 0x0a, 0x06, 0x57, + 0x69, 0x73, 0x74, 0x69, 0x61, 0x10, 0x8c, 0x06, 0x12, 0x13, 0x0a, 0x0a, 0x53, 0x70, 0x6f, 0x72, + 0x74, 0x52, 0x61, 0x64, 0x61, 0x72, 0x10, 0x8d, 0x06, 0x1a, 0x02, 0x08, 0x01, 0x12, 0x10, 0x0a, + 0x0b, 0x55, 0x70, 0x74, 0x69, 0x6d, 0x65, 0x52, 0x6f, 0x62, 0x6f, 0x74, 0x10, 0x8e, 0x06, 0x12, + 0x0e, 0x0a, 0x09, 0x43, 0x6f, 0x64, 0x65, 0x71, 0x75, 0x69, 0x72, 0x79, 0x10, 0x8f, 0x06, 0x12, + 0x11, 0x0a, 0x0c, 0x45, 0x78, 0x74, 0x72, 0x61, 0x63, 0x74, 0x6f, 0x72, 0x41, 0x50, 0x49, 0x10, + 0x90, 0x06, 0x12, 0x0d, 0x0a, 0x08, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x10, 0x91, + 0x06, 0x12, 0x0e, 0x0a, 0x09, 0x4d, 0x61, 0x67, 0x69, 0x63, 0x42, 0x65, 0x6c, 0x6c, 0x10, 0x92, + 0x06, 0x12, 0x0f, 0x0a, 0x0a, 0x53, 0x74, 0x6f, 0x72, 0x6d, 0x62, 0x6f, 0x61, 0x72, 0x64, 0x10, + 0x93, 0x06, 0x12, 0x0d, 0x0a, 0x08, 0x41, 0x70, 0x69, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x10, 0x94, + 0x06, 0x12, 0x0b, 0x0a, 0x06, 0x44, 0x69, 0x73, 0x71, 0x75, 0x73, 0x10, 0x95, 0x06, 0x12, 0x0b, + 0x0a, 0x06, 0x57, 0x6f, 0x6f, 0x70, 0x72, 0x61, 0x10, 0x96, 0x06, 0x12, 0x0e, 0x0a, 0x09, 0x50, + 0x61, 0x70, 0x65, 0x72, 0x66, 0x6f, 0x72, 0x6d, 0x10, 0x97, 0x06, 0x12, 0x0c, 0x0a, 0x07, 0x47, + 0x75, 0x6d, 0x72, 0x6f, 0x61, 0x64, 0x10, 0x98, 0x06, 0x12, 0x0f, 0x0a, 0x0a, 0x50, 0x61, 0x79, + 0x64, 0x69, 0x72, 0x74, 0x61, 0x70, 0x70, 0x10, 0x99, 0x06, 0x12, 0x0e, 0x0a, 0x09, 0x44, 0x65, + 0x74, 0x65, 0x63, 0x74, 0x69, 0x66, 0x79, 0x10, 0x9a, 0x06, 0x12, 0x0f, 0x0a, 0x0a, 0x53, 0x74, + 0x61, 0x74, 0x75, 0x73, 0x63, 0x61, 0x6b, 0x65, 0x10, 0x9b, 0x06, 0x12, 0x0f, 0x0a, 0x0a, 0x4a, + 0x75, 0x6d, 0x70, 0x73, 0x65, 0x6c, 0x6c, 0x65, 0x72, 0x10, 0x9c, 0x06, 0x12, 0x0f, 0x0a, 0x0a, + 0x4c, 0x75, 0x6e, 0x63, 0x68, 0x4d, 0x6f, 0x6e, 0x65, 0x79, 0x10, 0x9d, 0x06, 0x12, 0x0c, 0x0a, + 0x07, 0x52, 0x6f, 0x73, 0x65, 0x74, 0x74, 0x65, 0x10, 0x9e, 0x06, 0x12, 0x09, 0x0a, 0x04, 0x59, + 0x65, 0x6c, 0x70, 0x10, 0x9f, 0x06, 0x12, 0x0a, 0x0a, 0x05, 0x41, 0x74, 0x65, 0x72, 0x61, 0x10, + 0xa0, 0x06, 0x12, 0x12, 0x0a, 0x0d, 0x45, 0x63, 0x6f, 0x53, 0x74, 0x72, 0x75, 0x78, 0x75, 0x72, + 0x65, 0x49, 0x54, 0x10, 0xa1, 0x06, 0x12, 0x08, 0x0a, 0x03, 0x41, 0x68, 0x61, 0x10, 0xa2, 0x06, + 0x12, 0x0d, 0x0a, 0x08, 0x50, 0x61, 0x72, 0x73, 0x65, 0x68, 0x75, 0x62, 0x10, 0xa3, 0x06, 0x12, + 0x11, 0x0a, 0x0c, 0x50, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x43, 0x6c, 0x6f, 0x75, 0x64, 0x10, + 0xa4, 0x06, 0x12, 0x0f, 0x0a, 0x0a, 0x43, 0x6c, 0x6f, 0x75, 0x64, 0x73, 0x6d, 0x69, 0x74, 0x68, + 0x10, 0xa5, 0x06, 0x12, 0x11, 0x0a, 0x08, 0x46, 0x6c, 0x6f, 0x77, 0x64, 0x61, 0x73, 0x68, 0x10, + 0xa6, 0x06, 0x1a, 0x02, 0x08, 0x01, 0x12, 0x11, 0x0a, 0x08, 0x46, 0x6c, 0x6f, 0x77, 0x64, 0x6f, + 0x63, 0x6b, 0x10, 0xa7, 0x06, 0x1a, 0x02, 0x08, 0x01, 0x12, 0x0b, 0x0a, 0x06, 0x46, 0x69, 0x62, + 0x65, 0x72, 0x79, 0x10, 0xa8, 0x06, 0x12, 0x0d, 0x0a, 0x08, 0x54, 0x79, 0x70, 0x65, 0x74, 0x61, + 0x6c, 0x6b, 0x10, 0xa9, 0x06, 0x12, 0x0e, 0x0a, 0x09, 0x56, 0x6f, 0x6f, 0x64, 0x6f, 0x6f, 0x53, + 0x4d, 0x53, 0x10, 0xaa, 0x06, 0x12, 0x0e, 0x0a, 0x09, 0x5a, 0x75, 0x6c, 0x69, 0x70, 0x43, 0x68, + 0x61, 0x74, 0x10, 0xab, 0x06, 0x12, 0x0e, 0x0a, 0x09, 0x46, 0x6f, 0x72, 0x6d, 0x63, 0x72, 0x61, + 0x66, 0x74, 0x10, 0xac, 0x06, 0x12, 0x0c, 0x0a, 0x07, 0x49, 0x65, 0x78, 0x61, 0x70, 0x69, 0x73, + 0x10, 0xad, 0x06, 0x12, 0x0e, 0x0a, 0x09, 0x52, 0x65, 0x61, 0x63, 0x68, 0x6d, 0x61, 0x69, 0x6c, + 0x10, 0xae, 0x06, 0x12, 0x0f, 0x0a, 0x0a, 0x43, 0x68, 0x61, 0x72, 0x74, 0x6d, 0x6f, 0x67, 0x75, + 0x6c, 0x10, 0xaf, 0x06, 0x12, 0x0f, 0x0a, 0x0a, 0x41, 0x70, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x65, + 0x64, 0x64, 0x10, 0xb0, 0x06, 0x12, 0x08, 0x0a, 0x03, 0x57, 0x69, 0x74, 0x10, 0xb1, 0x06, 0x12, + 0x15, 0x0a, 0x10, 0x52, 0x65, 0x63, 0x68, 0x61, 0x72, 0x67, 0x65, 0x50, 0x61, 0x79, 0x6d, 0x65, + 0x6e, 0x74, 0x73, 0x10, 0xb2, 0x06, 0x12, 0x0f, 0x0a, 0x0a, 0x44, 0x69, 0x67, 0x67, 0x65, 0x72, + 0x6e, 0x61, 0x75, 0x74, 0x10, 0xb3, 0x06, 0x12, 0x10, 0x0a, 0x0b, 0x4d, 0x6f, 0x6e, 0x6b, 0x65, + 0x79, 0x4c, 0x65, 0x61, 0x72, 0x6e, 0x10, 0xb4, 0x06, 0x12, 0x0a, 0x0a, 0x05, 0x44, 0x75, 0x70, + 0x6c, 0x79, 0x10, 0xb5, 0x06, 0x12, 0x0e, 0x0a, 0x09, 0x50, 0x6f, 0x73, 0x74, 0x62, 0x61, 0x63, + 0x6b, 0x73, 0x10, 0xb6, 0x06, 0x12, 0x0d, 0x0a, 0x08, 0x43, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, + 0x32, 0x10, 0xb7, 0x06, 0x12, 0x0c, 0x0a, 0x07, 0x5a, 0x65, 0x6e, 0x52, 0x6f, 0x77, 0x73, 0x10, + 0xb8, 0x06, 0x12, 0x10, 0x0a, 0x0b, 0x5a, 0x69, 0x70, 0x63, 0x6f, 0x64, 0x65, 0x62, 0x61, 0x73, + 0x65, 0x10, 0xb9, 0x06, 0x12, 0x0b, 0x0a, 0x06, 0x54, 0x65, 0x66, 0x74, 0x65, 0x72, 0x10, 0xba, + 0x06, 0x12, 0x0a, 0x0a, 0x05, 0x54, 0x77, 0x69, 0x73, 0x74, 0x10, 0xbb, 0x06, 0x12, 0x16, 0x0a, + 0x11, 0x42, 0x72, 0x61, 0x69, 0x6e, 0x74, 0x72, 0x65, 0x65, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, + 0x74, 0x73, 0x10, 0xbc, 0x06, 0x12, 0x11, 0x0a, 0x0c, 0x43, 0x6c, 0x6f, 0x75, 0x64, 0x43, 0x6f, + 0x6e, 0x76, 0x65, 0x72, 0x74, 0x10, 0xbd, 0x06, 0x12, 0x0c, 0x0a, 0x07, 0x47, 0x72, 0x61, 0x66, + 0x61, 0x6e, 0x61, 0x10, 0xbe, 0x06, 0x12, 0x0f, 0x0a, 0x0a, 0x43, 0x6f, 0x6e, 0x76, 0x65, 0x72, + 0x74, 0x41, 0x70, 0x69, 0x10, 0xbf, 0x06, 0x12, 0x11, 0x0a, 0x0c, 0x54, 0x72, 0x61, 0x6e, 0x73, + 0x66, 0x65, 0x72, 0x77, 0x69, 0x73, 0x65, 0x10, 0xc0, 0x06, 0x12, 0x0c, 0x0a, 0x07, 0x42, 0x75, + 0x6c, 0x6b, 0x73, 0x6d, 0x73, 0x10, 0xc1, 0x06, 0x12, 0x0c, 0x0a, 0x07, 0x44, 0x61, 0x74, 0x61, + 0x62, 0x6f, 0x78, 0x10, 0xc2, 0x06, 0x12, 0x0e, 0x0a, 0x09, 0x4f, 0x6e, 0x65, 0x73, 0x69, 0x67, + 0x6e, 0x61, 0x6c, 0x10, 0xc3, 0x06, 0x12, 0x0c, 0x0a, 0x07, 0x52, 0x65, 0x6e, 0x74, 0x6d, 0x61, + 0x6e, 0x10, 0xc4, 0x06, 0x12, 0x0c, 0x0a, 0x07, 0x50, 0x61, 0x72, 0x73, 0x65, 0x75, 0x72, 0x10, + 0xc5, 0x06, 0x12, 0x0e, 0x0a, 0x09, 0x44, 0x6f, 0x63, 0x70, 0x61, 0x72, 0x73, 0x65, 0x72, 0x10, + 0xc6, 0x06, 0x12, 0x0d, 0x0a, 0x08, 0x46, 0x6f, 0x72, 0x6d, 0x73, 0x69, 0x74, 0x65, 0x10, 0xc7, + 0x06, 0x12, 0x11, 0x0a, 0x0c, 0x54, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x74, 0x61, 0x69, 0x6c, 0x6f, + 0x72, 0x10, 0xc8, 0x06, 0x12, 0x0c, 0x0a, 0x07, 0x4c, 0x65, 0x6d, 0x6c, 0x69, 0x73, 0x74, 0x10, + 0xc9, 0x06, 0x12, 0x0c, 0x0a, 0x07, 0x50, 0x72, 0x6f, 0x64, 0x70, 0x61, 0x64, 0x10, 0xca, 0x06, + 0x12, 0x0e, 0x0a, 0x09, 0x46, 0x6f, 0x72, 0x6d, 0x73, 0x74, 0x61, 0x63, 0x6b, 0x10, 0xcb, 0x06, + 0x12, 0x10, 0x0a, 0x0b, 0x43, 0x6f, 0x64, 0x65, 0x63, 0x6c, 0x69, 0x6d, 0x61, 0x74, 0x65, 0x10, + 0xcc, 0x06, 0x12, 0x0e, 0x0a, 0x09, 0x43, 0x6f, 0x64, 0x65, 0x6d, 0x61, 0x67, 0x69, 0x63, 0x10, + 0xcd, 0x06, 0x12, 0x0a, 0x0a, 0x05, 0x56, 0x62, 0x6f, 0x75, 0x74, 0x10, 0xce, 0x06, 0x12, 0x0e, + 0x0a, 0x09, 0x4e, 0x69, 0x67, 0x68, 0x74, 0x66, 0x61, 0x6c, 0x6c, 0x10, 0xcf, 0x06, 0x12, 0x0f, + 0x0a, 0x0a, 0x46, 0x6c, 0x69, 0x67, 0x68, 0x74, 0x4c, 0x61, 0x62, 0x73, 0x10, 0xd0, 0x06, 0x12, + 0x11, 0x0a, 0x0c, 0x53, 0x70, 0x65, 0x65, 0x63, 0x68, 0x54, 0x65, 0x78, 0x74, 0x41, 0x49, 0x10, + 0xd1, 0x06, 0x12, 0x0d, 0x0a, 0x08, 0x50, 0x6f, 0x6c, 0x6c, 0x73, 0x41, 0x50, 0x49, 0x10, 0xd2, + 0x06, 0x12, 0x0b, 0x0a, 0x06, 0x53, 0x69, 0x6d, 0x46, 0x69, 0x6e, 0x10, 0xd3, 0x06, 0x12, 0x0a, + 0x0a, 0x05, 0x53, 0x63, 0x61, 0x6c, 0x72, 0x10, 0xd4, 0x06, 0x12, 0x0f, 0x0a, 0x0a, 0x4b, 0x61, + 0x6e, 0x62, 0x61, 0x6e, 0x74, 0x6f, 0x6f, 0x6c, 0x10, 0xd5, 0x06, 0x12, 0x10, 0x0a, 0x0b, 0x42, + 0x72, 0x69, 0x67, 0x68, 0x74, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x10, 0xd6, 0x06, 0x12, 0x0c, 0x0a, + 0x07, 0x48, 0x6f, 0x74, 0x77, 0x69, 0x72, 0x65, 0x10, 0xd7, 0x06, 0x12, 0x0d, 0x0a, 0x08, 0x49, + 0x6e, 0x73, 0x74, 0x61, 0x62, 0x6f, 0x74, 0x10, 0xd8, 0x06, 0x12, 0x0c, 0x0a, 0x07, 0x54, 0x69, + 0x6d, 0x65, 0x6b, 0x69, 0x74, 0x10, 0xd9, 0x06, 0x12, 0x10, 0x0a, 0x0b, 0x49, 0x6e, 0x74, 0x65, + 0x72, 0x73, 0x65, 0x6c, 0x6c, 0x65, 0x72, 0x10, 0xda, 0x06, 0x12, 0x11, 0x0a, 0x0c, 0x4d, 0x6f, + 0x6a, 0x6f, 0x68, 0x65, 0x6c, 0x70, 0x64, 0x65, 0x73, 0x6b, 0x10, 0xdb, 0x06, 0x12, 0x0f, 0x0a, + 0x0a, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x73, 0x65, 0x6e, 0x64, 0x10, 0xdc, 0x06, 0x12, 0x10, + 0x0a, 0x0b, 0x47, 0x65, 0x74, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x10, 0xdd, 0x06, + 0x12, 0x0c, 0x0a, 0x07, 0x44, 0x79, 0x6e, 0x61, 0x64, 0x6f, 0x74, 0x10, 0xde, 0x06, 0x12, 0x0a, + 0x0a, 0x05, 0x44, 0x65, 0x6d, 0x69, 0x6f, 0x10, 0xdf, 0x06, 0x12, 0x0b, 0x0a, 0x06, 0x54, 0x6f, + 0x6b, 0x65, 0x65, 0x74, 0x10, 0xe0, 0x06, 0x12, 0x11, 0x0a, 0x0c, 0x4d, 0x79, 0x65, 0x78, 0x70, + 0x65, 0x72, 0x69, 0x6d, 0x65, 0x6e, 0x74, 0x10, 0xe1, 0x06, 0x12, 0x0e, 0x0a, 0x09, 0x43, 0x6f, + 0x70, 0x79, 0x73, 0x63, 0x61, 0x70, 0x65, 0x10, 0xe2, 0x06, 0x12, 0x0d, 0x0a, 0x08, 0x42, 0x65, + 0x73, 0x6e, 0x61, 0x70, 0x70, 0x79, 0x10, 0xe3, 0x06, 0x12, 0x0e, 0x0a, 0x09, 0x53, 0x61, 0x6c, + 0x65, 0x73, 0x6d, 0x61, 0x74, 0x65, 0x10, 0xe4, 0x06, 0x12, 0x13, 0x0a, 0x0a, 0x48, 0x65, 0x61, + 0x74, 0x6d, 0x61, 0x70, 0x61, 0x70, 0x69, 0x10, 0xe5, 0x06, 0x1a, 0x02, 0x08, 0x01, 0x12, 0x11, + 0x0a, 0x0c, 0x57, 0x65, 0x62, 0x73, 0x69, 0x74, 0x65, 0x70, 0x75, 0x6c, 0x73, 0x65, 0x10, 0xe6, + 0x06, 0x12, 0x0e, 0x0a, 0x09, 0x55, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x69, 0x66, 0x79, 0x10, 0xe7, + 0x06, 0x12, 0x0c, 0x0a, 0x07, 0x43, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x74, 0x10, 0xe8, 0x06, 0x12, + 0x0d, 0x0a, 0x08, 0x50, 0x44, 0x46, 0x6d, 0x79, 0x55, 0x52, 0x4c, 0x10, 0xe9, 0x06, 0x12, 0x10, + 0x0a, 0x0b, 0x41, 0x70, 0x69, 0x32, 0x43, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x74, 0x10, 0xea, 0x06, + 0x12, 0x0d, 0x0a, 0x08, 0x4f, 0x70, 0x73, 0x67, 0x65, 0x6e, 0x69, 0x65, 0x10, 0xeb, 0x06, 0x12, + 0x0b, 0x0a, 0x06, 0x47, 0x65, 0x6d, 0x69, 0x6e, 0x69, 0x10, 0xec, 0x06, 0x12, 0x0e, 0x0a, 0x09, + 0x48, 0x6f, 0x6e, 0x65, 0x79, 0x63, 0x6f, 0x6d, 0x62, 0x10, 0xed, 0x06, 0x12, 0x14, 0x0a, 0x0f, + 0x4b, 0x61, 0x6c, 0x74, 0x75, 0x72, 0x61, 0x41, 0x70, 0x70, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x10, + 0xee, 0x06, 0x12, 0x13, 0x0a, 0x0e, 0x4b, 0x61, 0x6c, 0x74, 0x75, 0x72, 0x61, 0x53, 0x65, 0x73, + 0x73, 0x69, 0x6f, 0x6e, 0x10, 0xef, 0x06, 0x12, 0x0a, 0x0a, 0x05, 0x42, 0x69, 0x74, 0x47, 0x6f, + 0x10, 0xf0, 0x06, 0x12, 0x0d, 0x0a, 0x08, 0x4f, 0x70, 0x74, 0x69, 0x64, 0x61, 0x73, 0x68, 0x10, + 0xf1, 0x06, 0x12, 0x0a, 0x0a, 0x05, 0x49, 0x6d, 0x67, 0x69, 0x78, 0x10, 0xf2, 0x06, 0x12, 0x10, + 0x0a, 0x0b, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x54, 0x6f, 0x54, 0x65, 0x78, 0x74, 0x10, 0xf3, 0x06, + 0x12, 0x10, 0x0a, 0x0b, 0x50, 0x61, 0x67, 0x65, 0x32, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x73, 0x10, + 0xf4, 0x06, 0x12, 0x0e, 0x0a, 0x09, 0x51, 0x75, 0x69, 0x63, 0x6b, 0x62, 0x61, 0x73, 0x65, 0x10, + 0xf5, 0x06, 0x12, 0x0d, 0x0a, 0x08, 0x52, 0x65, 0x64, 0x62, 0x6f, 0x6f, 0x74, 0x68, 0x10, 0xf6, + 0x06, 0x12, 0x0b, 0x0a, 0x06, 0x4e, 0x75, 0x62, 0x65, 0x6c, 0x61, 0x10, 0xf7, 0x06, 0x12, 0x0c, + 0x0a, 0x07, 0x49, 0x6e, 0x66, 0x6f, 0x62, 0x69, 0x70, 0x10, 0xf8, 0x06, 0x12, 0x0a, 0x0a, 0x05, + 0x55, 0x70, 0x72, 0x6f, 0x63, 0x10, 0xf9, 0x06, 0x12, 0x0f, 0x0a, 0x0a, 0x53, 0x75, 0x70, 0x70, + 0x6f, 0x72, 0x74, 0x62, 0x65, 0x65, 0x10, 0xfa, 0x06, 0x12, 0x0e, 0x0a, 0x09, 0x41, 0x66, 0x74, + 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x10, 0xfb, 0x06, 0x12, 0x0c, 0x0a, 0x07, 0x45, 0x64, 0x75, + 0x73, 0x69, 0x67, 0x6e, 0x10, 0xfc, 0x06, 0x12, 0x0b, 0x0a, 0x06, 0x54, 0x65, 0x61, 0x6d, 0x75, + 0x70, 0x10, 0xfd, 0x06, 0x12, 0x0c, 0x0a, 0x07, 0x57, 0x6f, 0x72, 0x6b, 0x64, 0x61, 0x79, 0x10, + 0xfe, 0x06, 0x12, 0x0c, 0x0a, 0x07, 0x4d, 0x6f, 0x6e, 0x67, 0x6f, 0x44, 0x42, 0x10, 0xff, 0x06, + 0x12, 0x08, 0x0a, 0x03, 0x4e, 0x47, 0x43, 0x10, 0x80, 0x07, 0x12, 0x13, 0x0a, 0x0e, 0x44, 0x69, + 0x67, 0x69, 0x74, 0x61, 0x6c, 0x4f, 0x63, 0x65, 0x61, 0x6e, 0x56, 0x32, 0x10, 0x81, 0x07, 0x12, + 0x0e, 0x0a, 0x09, 0x53, 0x51, 0x4c, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x10, 0x82, 0x07, 0x12, + 0x08, 0x0a, 0x03, 0x46, 0x54, 0x50, 0x10, 0x83, 0x07, 0x12, 0x0a, 0x0a, 0x05, 0x52, 0x65, 0x64, + 0x69, 0x73, 0x10, 0x84, 0x07, 0x12, 0x09, 0x0a, 0x04, 0x4c, 0x44, 0x41, 0x50, 0x10, 0x85, 0x07, + 0x12, 0x0c, 0x0a, 0x07, 0x53, 0x68, 0x6f, 0x70, 0x69, 0x66, 0x79, 0x10, 0x86, 0x07, 0x12, 0x0d, + 0x0a, 0x08, 0x52, 0x61, 0x62, 0x62, 0x69, 0x74, 0x4d, 0x51, 0x10, 0x87, 0x07, 0x12, 0x10, 0x0a, + 0x0b, 0x43, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x52, 0x65, 0x67, 0x65, 0x78, 0x10, 0x88, 0x07, 0x12, + 0x0e, 0x0a, 0x09, 0x45, 0x74, 0x68, 0x65, 0x72, 0x73, 0x63, 0x61, 0x6e, 0x10, 0x89, 0x07, 0x12, + 0x0b, 0x0a, 0x06, 0x49, 0x6e, 0x66, 0x75, 0x72, 0x61, 0x10, 0x8a, 0x07, 0x12, 0x0c, 0x0a, 0x07, + 0x41, 0x6c, 0x63, 0x68, 0x65, 0x6d, 0x79, 0x10, 0x8b, 0x07, 0x12, 0x10, 0x0a, 0x0b, 0x42, 0x6c, + 0x6f, 0x63, 0x6b, 0x4e, 0x61, 0x74, 0x69, 0x76, 0x65, 0x10, 0x8c, 0x07, 0x12, 0x0c, 0x0a, 0x07, + 0x4d, 0x6f, 0x72, 0x61, 0x6c, 0x69, 0x73, 0x10, 0x8d, 0x07, 0x12, 0x0c, 0x0a, 0x07, 0x42, 0x73, + 0x63, 0x53, 0x63, 0x61, 0x6e, 0x10, 0x8e, 0x07, 0x12, 0x16, 0x0a, 0x0d, 0x43, 0x6f, 0x69, 0x6e, + 0x4d, 0x61, 0x72, 0x6b, 0x65, 0x74, 0x43, 0x61, 0x70, 0x10, 0x8f, 0x07, 0x1a, 0x02, 0x08, 0x01, + 0x12, 0x0a, 0x0a, 0x05, 0x50, 0x65, 0x72, 0x63, 0x79, 0x10, 0x90, 0x07, 0x12, 0x11, 0x0a, 0x0c, + 0x54, 0x69, 0x6e, 0x65, 0x73, 0x57, 0x65, 0x62, 0x68, 0x6f, 0x6f, 0x6b, 0x10, 0x91, 0x07, 0x12, + 0x0b, 0x0a, 0x06, 0x50, 0x75, 0x6c, 0x75, 0x6d, 0x69, 0x10, 0x92, 0x07, 0x12, 0x12, 0x0a, 0x0d, + 0x53, 0x75, 0x70, 0x61, 0x62, 0x61, 0x73, 0x65, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x10, 0x93, 0x07, + 0x12, 0x10, 0x0a, 0x0b, 0x4e, 0x75, 0x47, 0x65, 0x74, 0x41, 0x70, 0x69, 0x4b, 0x65, 0x79, 0x10, + 0x94, 0x07, 0x12, 0x0a, 0x0a, 0x05, 0x41, 0x69, 0x76, 0x65, 0x6e, 0x10, 0x95, 0x07, 0x12, 0x0c, + 0x0a, 0x07, 0x50, 0x72, 0x65, 0x66, 0x65, 0x63, 0x74, 0x10, 0x96, 0x07, 0x12, 0x0d, 0x0a, 0x08, + 0x44, 0x6f, 0x63, 0x75, 0x73, 0x69, 0x67, 0x6e, 0x10, 0x97, 0x07, 0x12, 0x0e, 0x0a, 0x09, 0x43, + 0x6f, 0x75, 0x63, 0x68, 0x62, 0x61, 0x73, 0x65, 0x10, 0x98, 0x07, 0x12, 0x0e, 0x0a, 0x09, 0x44, + 0x6f, 0x63, 0x6b, 0x65, 0x72, 0x68, 0x75, 0x62, 0x10, 0x99, 0x07, 0x12, 0x19, 0x0a, 0x14, 0x54, + 0x72, 0x75, 0x66, 0x66, 0x6c, 0x65, 0x68, 0x6f, 0x67, 0x45, 0x6e, 0x74, 0x65, 0x72, 0x70, 0x72, + 0x69, 0x73, 0x65, 0x10, 0x9a, 0x07, 0x12, 0x10, 0x0a, 0x0b, 0x45, 0x6e, 0x76, 0x6f, 0x79, 0x41, + 0x70, 0x69, 0x4b, 0x65, 0x79, 0x10, 0x9b, 0x07, 0x12, 0x11, 0x0a, 0x0c, 0x47, 0x69, 0x74, 0x48, + 0x75, 0x62, 0x4f, 0x61, 0x75, 0x74, 0x68, 0x32, 0x10, 0x9c, 0x07, 0x12, 0x0f, 0x0a, 0x0a, 0x53, + 0x61, 0x6c, 0x65, 0x73, 0x66, 0x6f, 0x72, 0x63, 0x65, 0x10, 0x9d, 0x07, 0x12, 0x10, 0x0a, 0x0b, + 0x48, 0x75, 0x67, 0x67, 0x69, 0x6e, 0x67, 0x46, 0x61, 0x63, 0x65, 0x10, 0x9e, 0x07, 0x12, 0x0e, + 0x0a, 0x09, 0x53, 0x6e, 0x6f, 0x77, 0x66, 0x6c, 0x61, 0x6b, 0x65, 0x10, 0x9f, 0x07, 0x12, 0x10, + 0x0a, 0x0b, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x67, 0x72, 0x61, 0x70, 0x68, 0x10, 0xa0, 0x07, + 0x12, 0x0e, 0x0a, 0x09, 0x54, 0x61, 0x69, 0x6c, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x10, 0xa1, 0x07, + 0x12, 0x10, 0x0a, 0x0b, 0x57, 0x65, 0x62, 0x33, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x10, + 0xa2, 0x07, 0x12, 0x11, 0x0a, 0x0c, 0x41, 0x7a, 0x75, 0x72, 0x65, 0x53, 0x74, 0x6f, 0x72, 0x61, + 0x67, 0x65, 0x10, 0xa3, 0x07, 0x12, 0x12, 0x0a, 0x0d, 0x50, 0x6c, 0x61, 0x6e, 0x65, 0x74, 0x53, + 0x63, 0x61, 0x6c, 0x65, 0x44, 0x62, 0x10, 0xa4, 0x07, 0x12, 0x0e, 0x0a, 0x09, 0x41, 0x6e, 0x74, + 0x68, 0x72, 0x6f, 0x70, 0x69, 0x63, 0x10, 0xa5, 0x07, 0x12, 0x09, 0x0a, 0x04, 0x52, 0x61, 0x6d, + 0x70, 0x10, 0xa6, 0x07, 0x12, 0x0c, 0x0a, 0x07, 0x4b, 0x6c, 0x61, 0x76, 0x69, 0x79, 0x6f, 0x10, + 0xa7, 0x07, 0x12, 0x14, 0x0a, 0x0f, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x67, 0x72, 0x61, 0x70, + 0x68, 0x43, 0x6f, 0x64, 0x79, 0x10, 0xa8, 0x07, 0x12, 0x0e, 0x0a, 0x09, 0x56, 0x6f, 0x69, 0x63, + 0x65, 0x66, 0x6c, 0x6f, 0x77, 0x10, 0xa9, 0x07, 0x12, 0x0c, 0x0a, 0x07, 0x50, 0x72, 0x69, 0x76, + 0x61, 0x63, 0x79, 0x10, 0xaa, 0x07, 0x12, 0x0b, 0x0a, 0x06, 0x49, 0x50, 0x49, 0x6e, 0x66, 0x6f, + 0x10, 0xab, 0x07, 0x12, 0x10, 0x0a, 0x0b, 0x49, 0x70, 0x32, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x10, 0xac, 0x07, 0x12, 0x0e, 0x0a, 0x09, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6d, 0x6f, + 0x6a, 0x6f, 0x10, 0xad, 0x07, 0x12, 0x0e, 0x0a, 0x09, 0x50, 0x6f, 0x72, 0x74, 0x61, 0x69, 0x6e, + 0x65, 0x72, 0x10, 0xae, 0x07, 0x12, 0x13, 0x0a, 0x0e, 0x50, 0x6f, 0x72, 0x74, 0x61, 0x69, 0x6e, + 0x65, 0x72, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x10, 0xaf, 0x07, 0x12, 0x0b, 0x0a, 0x06, 0x4c, 0x6f, + 0x67, 0x67, 0x6c, 0x79, 0x10, 0xb0, 0x07, 0x12, 0x0c, 0x0a, 0x07, 0x4f, 0x70, 0x65, 0x6e, 0x56, + 0x70, 0x6e, 0x10, 0xb1, 0x07, 0x12, 0x1e, 0x0a, 0x19, 0x56, 0x61, 0x67, 0x72, 0x61, 0x6e, 0x74, + 0x43, 0x6c, 0x6f, 0x75, 0x64, 0x50, 0x65, 0x72, 0x73, 0x6f, 0x6e, 0x61, 0x6c, 0x54, 0x6f, 0x6b, + 0x65, 0x6e, 0x10, 0xb2, 0x07, 0x12, 0x10, 0x0a, 0x0b, 0x42, 0x65, 0x74, 0x74, 0x65, 0x72, 0x53, + 0x74, 0x61, 0x63, 0x6b, 0x10, 0xb3, 0x07, 0x12, 0x0d, 0x0a, 0x08, 0x5a, 0x65, 0x72, 0x6f, 0x54, + 0x69, 0x65, 0x72, 0x10, 0xb4, 0x07, 0x12, 0x0e, 0x0a, 0x09, 0x41, 0x70, 0x70, 0x4f, 0x70, 0x74, + 0x69, 0x63, 0x73, 0x10, 0xb5, 0x07, 0x12, 0x0d, 0x0a, 0x08, 0x4d, 0x65, 0x74, 0x61, 0x62, 0x61, + 0x73, 0x65, 0x10, 0xb6, 0x07, 0x12, 0x11, 0x0a, 0x0c, 0x43, 0x6f, 0x69, 0x6e, 0x62, 0x61, 0x73, + 0x65, 0x57, 0x61, 0x61, 0x53, 0x10, 0xb7, 0x07, 0x12, 0x11, 0x0a, 0x0c, 0x4c, 0x65, 0x6d, 0x6f, + 0x6e, 0x53, 0x71, 0x75, 0x65, 0x65, 0x7a, 0x79, 0x10, 0xb8, 0x07, 0x12, 0x0d, 0x0a, 0x08, 0x42, + 0x75, 0x64, 0x69, 0x62, 0x61, 0x73, 0x65, 0x10, 0xb9, 0x07, 0x12, 0x0f, 0x0a, 0x0a, 0x44, 0x65, + 0x6e, 0x6f, 0x44, 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x10, 0xba, 0x07, 0x12, 0x0b, 0x0a, 0x06, 0x53, + 0x74, 0x72, 0x69, 0x70, 0x6f, 0x10, 0xbb, 0x07, 0x12, 0x0c, 0x0a, 0x07, 0x52, 0x65, 0x70, 0x6c, + 0x79, 0x49, 0x4f, 0x10, 0xbc, 0x07, 0x12, 0x0f, 0x0a, 0x0a, 0x41, 0x7a, 0x75, 0x72, 0x65, 0x42, + 0x61, 0x74, 0x63, 0x68, 0x10, 0xbd, 0x07, 0x12, 0x1b, 0x0a, 0x16, 0x41, 0x7a, 0x75, 0x72, 0x65, + 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, + 0x79, 0x10, 0xbe, 0x07, 0x12, 0x12, 0x0a, 0x0d, 0x41, 0x57, 0x53, 0x53, 0x65, 0x73, 0x73, 0x69, + 0x6f, 0x6e, 0x4b, 0x65, 0x79, 0x10, 0xbf, 0x07, 0x12, 0x09, 0x0a, 0x04, 0x43, 0x6f, 0x64, 0x61, + 0x10, 0xc0, 0x07, 0x12, 0x0b, 0x0a, 0x06, 0x4c, 0x6f, 0x67, 0x7a, 0x49, 0x4f, 0x10, 0xc1, 0x07, + 0x12, 0x0f, 0x0a, 0x0a, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x62, 0x72, 0x69, 0x74, 0x65, 0x10, 0xc2, + 0x07, 0x12, 0x1a, 0x0a, 0x15, 0x47, 0x72, 0x61, 0x66, 0x61, 0x6e, 0x61, 0x53, 0x65, 0x72, 0x76, + 0x69, 0x63, 0x65, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x10, 0xc3, 0x07, 0x12, 0x13, 0x0a, + 0x0e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x46, 0x69, 0x6e, 0x61, 0x6e, 0x63, 0x65, 0x10, + 0xc4, 0x07, 0x12, 0x0d, 0x0a, 0x08, 0x4f, 0x76, 0x65, 0x72, 0x6c, 0x6f, 0x6f, 0x70, 0x10, 0xc5, + 0x07, 0x12, 0x0a, 0x0a, 0x05, 0x4e, 0x67, 0x72, 0x6f, 0x6b, 0x10, 0xc6, 0x07, 0x12, 0x0e, 0x0a, + 0x09, 0x52, 0x65, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x65, 0x10, 0xc7, 0x07, 0x12, 0x0d, 0x0a, + 0x08, 0x50, 0x6f, 0x73, 0x74, 0x67, 0x72, 0x65, 0x73, 0x10, 0xc8, 0x07, 0x12, 0x2a, 0x0a, 0x25, + 0x41, 0x7a, 0x75, 0x72, 0x65, 0x41, 0x63, 0x74, 0x69, 0x76, 0x65, 0x44, 0x69, 0x72, 0x65, 0x63, + 0x74, 0x6f, 0x72, 0x79, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, + 0x65, 0x63, 0x72, 0x65, 0x74, 0x10, 0xc9, 0x07, 0x12, 0x20, 0x0a, 0x1b, 0x41, 0x7a, 0x75, 0x72, + 0x65, 0x43, 0x61, 0x63, 0x68, 0x65, 0x46, 0x6f, 0x72, 0x52, 0x65, 0x64, 0x69, 0x73, 0x41, 0x63, + 0x63, 0x65, 0x73, 0x73, 0x4b, 0x65, 0x79, 0x10, 0xca, 0x07, 0x12, 0x21, 0x0a, 0x1c, 0x41, 0x7a, + 0x75, 0x72, 0x65, 0x43, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x44, 0x42, 0x4b, 0x65, 0x79, 0x49, 0x64, + 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x61, 0x62, 0x6c, 0x65, 0x10, 0xcb, 0x07, 0x12, 0x23, 0x0a, + 0x1e, 0x41, 0x7a, 0x75, 0x72, 0x65, 0x44, 0x65, 0x76, 0x6f, 0x70, 0x73, 0x50, 0x65, 0x72, 0x73, + 0x6f, 0x6e, 0x61, 0x6c, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x10, + 0xcc, 0x07, 0x12, 0x15, 0x0a, 0x10, 0x41, 0x7a, 0x75, 0x72, 0x65, 0x46, 0x75, 0x6e, 0x63, 0x74, + 0x69, 0x6f, 0x6e, 0x4b, 0x65, 0x79, 0x10, 0xcd, 0x07, 0x12, 0x2c, 0x0a, 0x27, 0x41, 0x7a, 0x75, + 0x72, 0x65, 0x4d, 0x4c, 0x57, 0x65, 0x62, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x43, 0x6c, + 0x61, 0x73, 0x73, 0x69, 0x63, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x61, 0x62, 0x6c, + 0x65, 0x4b, 0x65, 0x79, 0x10, 0xce, 0x07, 0x12, 0x12, 0x0a, 0x0d, 0x41, 0x7a, 0x75, 0x72, 0x65, + 0x53, 0x61, 0x73, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x10, 0xcf, 0x07, 0x12, 0x18, 0x0a, 0x13, 0x41, + 0x7a, 0x75, 0x72, 0x65, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x41, 0x64, 0x6d, 0x69, 0x6e, 0x4b, + 0x65, 0x79, 0x10, 0xd0, 0x07, 0x12, 0x18, 0x0a, 0x13, 0x41, 0x7a, 0x75, 0x72, 0x65, 0x53, 0x65, + 0x61, 0x72, 0x63, 0x68, 0x51, 0x75, 0x65, 0x72, 0x79, 0x4b, 0x65, 0x79, 0x10, 0xd1, 0x07, 0x12, + 0x1f, 0x0a, 0x1a, 0x41, 0x7a, 0x75, 0x72, 0x65, 0x4d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, + 0x6e, 0x74, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x10, 0xd2, 0x07, + 0x12, 0x0d, 0x0a, 0x08, 0x41, 0x7a, 0x75, 0x72, 0x65, 0x53, 0x51, 0x4c, 0x10, 0xd3, 0x07, 0x12, + 0x0a, 0x0a, 0x05, 0x46, 0x6c, 0x79, 0x49, 0x4f, 0x10, 0xd4, 0x07, 0x12, 0x0e, 0x0a, 0x09, 0x42, + 0x75, 0x69, 0x6c, 0x74, 0x57, 0x69, 0x74, 0x68, 0x10, 0xd5, 0x07, 0x12, 0x0f, 0x0a, 0x0a, 0x4a, + 0x75, 0x70, 0x69, 0x74, 0x65, 0x72, 0x4f, 0x6e, 0x65, 0x10, 0xd6, 0x07, 0x12, 0x25, 0x0a, 0x20, + 0x47, 0x43, 0x50, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x44, 0x65, + 0x66, 0x61, 0x75, 0x6c, 0x74, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x73, + 0x10, 0xd7, 0x07, 0x12, 0x08, 0x0a, 0x03, 0x57, 0x69, 0x7a, 0x10, 0xd8, 0x07, 0x12, 0x0c, 0x0a, + 0x07, 0x50, 0x61, 0x67, 0x61, 0x72, 0x6d, 0x65, 0x10, 0xd9, 0x07, 0x12, 0x0c, 0x0a, 0x07, 0x4f, + 0x6e, 0x66, 0x6c, 0x65, 0x65, 0x74, 0x10, 0xda, 0x07, 0x12, 0x0c, 0x0a, 0x07, 0x49, 0x6e, 0x74, + 0x72, 0x61, 0x34, 0x32, 0x10, 0xdb, 0x07, 0x12, 0x09, 0x0a, 0x04, 0x47, 0x72, 0x6f, 0x71, 0x10, + 0xdc, 0x07, 0x12, 0x17, 0x0a, 0x12, 0x54, 0x77, 0x69, 0x74, 0x74, 0x65, 0x72, 0x43, 0x6f, 0x6e, + 0x73, 0x75, 0x6d, 0x65, 0x72, 0x6b, 0x65, 0x79, 0x10, 0xdd, 0x07, 0x12, 0x0b, 0x0a, 0x06, 0x45, + 0x72, 0x61, 0x73, 0x65, 0x72, 0x10, 0xde, 0x07, 0x12, 0x0e, 0x0a, 0x09, 0x4c, 0x61, 0x72, 0x6b, + 0x53, 0x75, 0x69, 0x74, 0x65, 0x10, 0xdf, 0x07, 0x12, 0x14, 0x0a, 0x0f, 0x4c, 0x61, 0x72, 0x6b, + 0x53, 0x75, 0x69, 0x74, 0x65, 0x41, 0x70, 0x69, 0x4b, 0x65, 0x79, 0x10, 0xe0, 0x07, 0x12, 0x0e, + 0x0a, 0x09, 0x45, 0x6e, 0x64, 0x6f, 0x72, 0x4c, 0x61, 0x62, 0x73, 0x10, 0xe1, 0x07, 0x12, 0x0f, + 0x0a, 0x0a, 0x45, 0x6c, 0x65, 0x76, 0x65, 0x6e, 0x4c, 0x61, 0x62, 0x73, 0x10, 0xe2, 0x07, 0x12, + 0x0d, 0x0a, 0x08, 0x4e, 0x65, 0x74, 0x73, 0x75, 0x69, 0x74, 0x65, 0x10, 0xe3, 0x07, 0x12, 0x14, + 0x0a, 0x0f, 0x52, 0x6f, 0x62, 0x69, 0x6e, 0x68, 0x6f, 0x6f, 0x64, 0x43, 0x72, 0x79, 0x70, 0x74, + 0x6f, 0x10, 0xe4, 0x07, 0x12, 0x0a, 0x0a, 0x05, 0x4e, 0x56, 0x41, 0x50, 0x49, 0x10, 0xe5, 0x07, + 0x12, 0x09, 0x0a, 0x04, 0x50, 0x79, 0x50, 0x49, 0x10, 0xe6, 0x07, 0x12, 0x0f, 0x0a, 0x0a, 0x52, + 0x61, 0x69, 0x6c, 0x77, 0x61, 0x79, 0x41, 0x70, 0x70, 0x10, 0xe7, 0x07, 0x12, 0x0b, 0x0a, 0x06, + 0x4d, 0x65, 0x72, 0x61, 0x6b, 0x69, 0x10, 0xe8, 0x07, 0x12, 0x15, 0x0a, 0x10, 0x53, 0x61, 0x6c, + 0x61, 0x64, 0x43, 0x6c, 0x6f, 0x75, 0x64, 0x41, 0x70, 0x69, 0x4b, 0x65, 0x79, 0x10, 0xe9, 0x07, + 0x12, 0x08, 0x0a, 0x03, 0x42, 0x6f, 0x78, 0x10, 0xea, 0x07, 0x12, 0x0d, 0x0a, 0x08, 0x42, 0x6f, + 0x78, 0x4f, 0x61, 0x75, 0x74, 0x68, 0x10, 0xeb, 0x07, 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 2e2748df74c6..6f220b09d153 100644 --- a/proto/detectors.proto +++ b/proto/detectors.proto @@ -1011,6 +1011,8 @@ enum DetectorType { RailwayApp = 999; Meraki = 1000; SaladCloudApiKey = 1001; + Box = 1002; + BoxOauth = 1003; } message Result { From bf38b8480cad903b46c7b6acc36816426c1eb216 Mon Sep 17 00:00:00 2001 From: ahrav Date: Tue, 15 Oct 2024 12:11:45 -0700 Subject: [PATCH 27/76] [fix] - resource leak (#3402) * fix resource leak * add comment * use errors.Join * address error wrapping --- pkg/handlers/handlers.go | 9 ++---- pkg/sources/git/git.go | 59 +++++++++++++++++++++++++++++++++++++--- 2 files changed, 57 insertions(+), 11 deletions(-) diff --git a/pkg/handlers/handlers.go b/pkg/handlers/handlers.go index 8f1f5e106bef..1561d826d0d5 100644 --- a/pkg/handlers/handlers.go +++ b/pkg/handlers/handlers.go @@ -285,14 +285,9 @@ func HandleFile( } defer func() { // Ensure all data is read to prevent broken pipe. - _, copyErr := io.Copy(io.Discard, rdr) - if copyErr != nil { - err = fmt.Errorf("error discarding remaining data: %w", copyErr) - } - closeErr := rdr.Close() - if closeErr != nil { + if closeErr := rdr.Close(); closeErr != nil { if err != nil { - err = fmt.Errorf("%v; error closing reader: %w", err, closeErr) + err = errors.Join(err, closeErr) } else { err = fmt.Errorf("error closing reader: %w", closeErr) } diff --git a/pkg/sources/git/git.go b/pkg/sources/git/git.go index c6d35c436e45..c18c93879a9c 100644 --- a/pkg/sources/git/git.go +++ b/pkg/sources/git/git.go @@ -1213,7 +1213,14 @@ func getSafeRemoteURL(repo *git.Repository, preferred string) string { return safeURL } -func (s *Git) handleBinary(ctx context.Context, gitDir string, reporter sources.ChunkReporter, chunkSkel *sources.Chunk, commitHash plumbing.Hash, path string) error { +func (s *Git) handleBinary( + ctx context.Context, + gitDir string, + reporter sources.ChunkReporter, + chunkSkel *sources.Chunk, + commitHash plumbing.Hash, + path string, +) (err error) { fileCtx := context.WithValues(ctx, "commit", commitHash.String()[:7], "path", path) fileCtx.Logger().V(5).Info("handling binary file") @@ -1227,9 +1234,32 @@ func (s *Git) handleBinary(ctx context.Context, gitDir string, reporter sources. return nil } - cmd := exec.Command("git", "-C", gitDir, "cat-file", "blob", commitHash.String()+":"+path) + const ( + cmdTimeout = 60 * time.Second + waitDelay = 5 * time.Second + ) + // NOTE: This kludge ensures the context timeout for the 'git cat-file' command + // matches the timeout for the HandleFile operation. + // By setting both timeouts to the same value, we can be more confident + // that both operations will run for the same duration. + // The command execution includes a small Wait delay before terminating the process, + // giving HandleFile time to respect the context + // and return before the process is forcibly killed. + // This approach helps prevent premature termination and allows for more complete processing. + + // TODO: Develop a more robust mechanism to ensure consistent timeout behavior between the command execution + // and the HandleFile operation. This should prevent premature termination and allow for complete processing. + handlers.SetArchiveMaxTimeout(cmdTimeout) + + // Create a timeout context for the 'git cat-file' command to ensure it does not run indefinitely. + // This prevents potential resource exhaustion by terminating the command if it exceeds the specified duration. + catFileCtx, cancel := context.WithTimeoutCause(fileCtx, cmdTimeout, errors.New("git cat-file timeout")) + defer cancel() + + cmd := exec.CommandContext(catFileCtx, "git", "-C", gitDir, "cat-file", "blob", commitHash.String()+":"+path) var stderr bytes.Buffer cmd.Stderr = &stderr + cmd.WaitDelay = waitDelay // give the command a chance to finish before the timeout :) stdout, err := cmd.StdoutPipe() if err != nil { @@ -1240,9 +1270,30 @@ func (s *Git) handleBinary(ctx context.Context, gitDir string, reporter sources. return fmt.Errorf("error starting git cat-file: %w\n%s", err, stderr.Bytes()) } - defer func() { _ = cmd.Wait() }() + // Ensure all data from the reader (stdout) is consumed to prevent broken pipe errors. + // This operation discards any remaining data after HandleFile completion. + // If the reader is fully consumed, the copy is essentially a no-op. + // If an error occurs while discarding, it will be logged and combined with any existing error. + // The command's completion is then awaited and any execution errors are handled. + defer func() { + n, copyErr := io.Copy(io.Discard, stdout) + if copyErr != nil { + ctx.Logger().Error( + copyErr, + "Failed to discard remaining stdout data after HandleFile completion", + ) + } + + ctx.Logger().V(3).Info( + "HandleFile did not consume all stdout data; excess discarded", + "bytes_discarded", n) + + // Wait for the command to finish and handle any errors. + waitErr := cmd.Wait() + err = errors.Join(err, copyErr, waitErr) + }() - return handlers.HandleFile(fileCtx, stdout, chunkSkel, reporter, handlers.WithSkipArchives(s.skipArchives)) + return handlers.HandleFile(catFileCtx, stdout, chunkSkel, reporter, handlers.WithSkipArchives(s.skipArchives)) } func (s *Source) Enumerate(ctx context.Context, reporter sources.UnitReporter) error { From 4ea311dea9a075a7552625b506cb21f77a623ada Mon Sep 17 00:00:00 2001 From: JonZeolla Date: Tue, 15 Oct 2024 15:13:36 -0400 Subject: [PATCH 28/76] feat: add github comments timeframe filtering (fixes #3388) (#3390) * feat: add github comments timeframe filtering * fixup and generate protos * Cleanup --------- Co-authored-by: Zachary Rice --- main.go | 33 +- pkg/engine/github.go | 1 + pkg/pb/sourcespb/sources.pb.go | 835 ++++++++++++------------ pkg/pb/sourcespb/sources.pb.validate.go | 2 + pkg/sources/github/github.go | 67 +- pkg/sources/github/github_test.go | 5 +- pkg/sources/sources.go | 2 + proto/sources.proto | 7 +- 8 files changed, 497 insertions(+), 455 deletions(-) diff --git a/main.go b/main.go index 0dbf1f8d11e8..a3f9c793b376 100644 --- a/main.go +++ b/main.go @@ -83,22 +83,22 @@ var ( _ = gitScan.Flag("entropy", "No-op flag for backwards compat.").Bool() _ = gitScan.Flag("regex", "No-op flag for backwards compat.").Bool() - githubScan = cli.Command("github", "Find credentials in GitHub repositories.") - githubScanEndpoint = githubScan.Flag("endpoint", "GitHub endpoint.").Default("https://api.github.com").String() - githubScanRepos = githubScan.Flag("repo", `GitHub repository to scan. You can repeat this flag. Example: "https://github.com/dustin-decker/secretsandstuff"`).Strings() - githubScanOrgs = githubScan.Flag("org", `GitHub organization to scan. You can repeat this flag. Example: "trufflesecurity"`).Strings() - githubScanToken = githubScan.Flag("token", "GitHub token. Can be provided with environment variable GITHUB_TOKEN.").Envar("GITHUB_TOKEN").String() - githubIncludeForks = githubScan.Flag("include-forks", "Include forks in scan.").Bool() - githubIncludeMembers = githubScan.Flag("include-members", "Include organization member repositories in scan.").Bool() - githubIncludeRepos = githubScan.Flag("include-repos", `Repositories to include in an org scan. This can also be a glob pattern. You can repeat this flag. Must use Github repo full name. Example: "trufflesecurity/trufflehog", "trufflesecurity/t*"`).Strings() - githubIncludeWikis = githubScan.Flag("include-wikis", "Include repository wikisin scan.").Bool() - - githubExcludeRepos = githubScan.Flag("exclude-repos", `Repositories to exclude in an org scan. This can also be a glob pattern. You can repeat this flag. Must use Github repo full name. Example: "trufflesecurity/driftwood", "trufflesecurity/d*"`).Strings() - githubScanIncludePaths = githubScan.Flag("include-paths", "Path to file with newline separated regexes for files to include in scan.").Short('i').String() - githubScanExcludePaths = githubScan.Flag("exclude-paths", "Path to file with newline separated regexes for files to exclude in scan.").Short('x').String() - githubScanIssueComments = githubScan.Flag("issue-comments", "Include issue descriptions and comments in scan.").Bool() - githubScanPRComments = githubScan.Flag("pr-comments", "Include pull request descriptions and comments in scan.").Bool() - githubScanGistComments = githubScan.Flag("gist-comments", "Include gist comments in scan.").Bool() + githubScan = cli.Command("github", "Find credentials in GitHub repositories.") + githubScanEndpoint = githubScan.Flag("endpoint", "GitHub endpoint.").Default("https://api.github.com").String() + githubScanRepos = githubScan.Flag("repo", `GitHub repository to scan. You can repeat this flag. Example: "https://github.com/dustin-decker/secretsandstuff"`).Strings() + githubScanOrgs = githubScan.Flag("org", `GitHub organization to scan. You can repeat this flag. Example: "trufflesecurity"`).Strings() + githubScanToken = githubScan.Flag("token", "GitHub token. Can be provided with environment variable GITHUB_TOKEN.").Envar("GITHUB_TOKEN").String() + githubIncludeForks = githubScan.Flag("include-forks", "Include forks in scan.").Bool() + githubIncludeMembers = githubScan.Flag("include-members", "Include organization member repositories in scan.").Bool() + githubIncludeRepos = githubScan.Flag("include-repos", `Repositories to include in an org scan. This can also be a glob pattern. You can repeat this flag. Must use Github repo full name. Example: "trufflesecurity/trufflehog", "trufflesecurity/t*"`).Strings() + githubIncludeWikis = githubScan.Flag("include-wikis", "Include repository wikisin scan.").Bool() + githubExcludeRepos = githubScan.Flag("exclude-repos", `Repositories to exclude in an org scan. This can also be a glob pattern. You can repeat this flag. Must use Github repo full name. Example: "trufflesecurity/driftwood", "trufflesecurity/d*"`).Strings() + githubScanIncludePaths = githubScan.Flag("include-paths", "Path to file with newline separated regexes for files to include in scan.").Short('i').String() + githubScanExcludePaths = githubScan.Flag("exclude-paths", "Path to file with newline separated regexes for files to exclude in scan.").Short('x').String() + githubScanIssueComments = githubScan.Flag("issue-comments", "Include issue descriptions and comments in scan.").Bool() + githubScanPRComments = githubScan.Flag("pr-comments", "Include pull request descriptions and comments in scan.").Bool() + githubScanGistComments = githubScan.Flag("gist-comments", "Include gist comments in scan.").Bool() + githubCommentsTimeframeDays = githubScan.Flag("comments-timeframe", "Number of days in the past to review when scanning issue, PR, and gist comments.").Uint32() // GitHub Cross Fork Object Reference Experimental Feature githubExperimentalScan = cli.Command("github-experimental", "Run an experimental GitHub scan. Must specify at least one experimental sub-module to run: object-discovery.") @@ -626,6 +626,7 @@ func runSingleScan(ctx context.Context, cmd string, cfg engine.Config) (metrics, IncludeIssueComments: *githubScanIssueComments, IncludePullRequestComments: *githubScanPRComments, IncludeGistComments: *githubScanGistComments, + CommentsTimeframeDays: *githubCommentsTimeframeDays, Filter: filter, } if err := eng.ScanGitHub(ctx, cfg); err != nil { diff --git a/pkg/engine/github.go b/pkg/engine/github.go index 9bf84072a7d0..a166e34af4ca 100644 --- a/pkg/engine/github.go +++ b/pkg/engine/github.go @@ -27,6 +27,7 @@ func (e *Engine) ScanGitHub(ctx context.Context, c sources.GithubConfig) error { IncludeGistComments: c.IncludeGistComments, IncludeWikis: c.IncludeWikis, SkipBinaries: c.SkipBinaries, + CommentsTimeframeDays: c.CommentsTimeframeDays, } if len(c.Token) > 0 { connection.Credential = &sourcespb.GitHub_Token{ diff --git a/pkg/pb/sourcespb/sources.pb.go b/pkg/pb/sourcespb/sources.pb.go index 50b14db28fac..545ce9b39c42 100644 --- a/pkg/pb/sourcespb/sources.pb.go +++ b/pkg/pb/sourcespb/sources.pb.go @@ -1815,6 +1815,7 @@ type GitHub struct { SkipBinaries bool `protobuf:"varint,17,opt,name=skip_binaries,json=skipBinaries,proto3" json:"skip_binaries,omitempty"` SkipArchives bool `protobuf:"varint,18,opt,name=skip_archives,json=skipArchives,proto3" json:"skip_archives,omitempty"` IncludeWikis bool `protobuf:"varint,19,opt,name=include_wikis,json=includeWikis,proto3" json:"include_wikis,omitempty"` + CommentsTimeframeDays uint32 `protobuf:"varint,20,opt,name=comments_timeframe_days,json=commentsTimeframeDays,proto3" json:"comments_timeframe_days,omitempty"` } func (x *GitHub) Reset() { @@ -1989,6 +1990,13 @@ func (x *GitHub) GetIncludeWikis() bool { return false } +func (x *GitHub) GetCommentsTimeframeDays() uint32 { + if x != nil { + return x.CommentsTimeframeDays + } + return 0 +} + type isGitHub_Credential interface { isGitHub_Credential() } @@ -4600,7 +4608,7 @@ var file_sources_proto_rawDesc = []byte{ 0x61, 0x72, 0x69, 0x65, 0x73, 0x12, 0x23, 0x0a, 0x0d, 0x73, 0x6b, 0x69, 0x70, 0x5f, 0x61, 0x72, 0x63, 0x68, 0x69, 0x76, 0x65, 0x73, 0x18, 0x08, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x73, 0x6b, 0x69, 0x70, 0x41, 0x72, 0x63, 0x68, 0x69, 0x76, 0x65, 0x73, 0x42, 0x0c, 0x0a, 0x0a, 0x63, 0x72, - 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x22, 0xa8, 0x06, 0x0a, 0x06, 0x47, 0x69, 0x74, + 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x22, 0xe0, 0x06, 0x0a, 0x06, 0x47, 0x69, 0x74, 0x48, 0x75, 0x62, 0x12, 0x24, 0x0a, 0x08, 0x65, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x72, 0x03, 0x90, 0x01, 0x01, 0x52, 0x08, 0x65, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x37, 0x0a, 0x0a, 0x67, 0x69, 0x74, @@ -4650,429 +4658,432 @@ var file_sources_proto_rawDesc = []byte{ 0x28, 0x08, 0x52, 0x0c, 0x73, 0x6b, 0x69, 0x70, 0x41, 0x72, 0x63, 0x68, 0x69, 0x76, 0x65, 0x73, 0x12, 0x23, 0x0a, 0x0d, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x5f, 0x77, 0x69, 0x6b, 0x69, 0x73, 0x18, 0x13, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, - 0x57, 0x69, 0x6b, 0x69, 0x73, 0x42, 0x0c, 0x0a, 0x0a, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, - 0x69, 0x61, 0x6c, 0x22, 0xe4, 0x01, 0x0a, 0x12, 0x47, 0x69, 0x74, 0x48, 0x75, 0x62, 0x45, 0x78, - 0x70, 0x65, 0x72, 0x69, 0x6d, 0x65, 0x6e, 0x74, 0x61, 0x6c, 0x12, 0x1e, 0x0a, 0x0a, 0x72, 0x65, - 0x70, 0x6f, 0x73, 0x69, 0x74, 0x6f, 0x72, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, - 0x72, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x6f, 0x72, 0x79, 0x12, 0x16, 0x0a, 0x05, 0x74, 0x6f, - 0x6b, 0x65, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x05, 0x74, 0x6f, 0x6b, - 0x65, 0x6e, 0x12, 0x29, 0x0a, 0x10, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x64, 0x69, 0x73, - 0x63, 0x6f, 0x76, 0x65, 0x72, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0f, 0x6f, 0x62, - 0x6a, 0x65, 0x63, 0x74, 0x44, 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x79, 0x12, 0x2f, 0x0a, - 0x13, 0x63, 0x6f, 0x6c, 0x6c, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x74, 0x68, 0x72, 0x65, 0x73, - 0x68, 0x6f, 0x6c, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x12, 0x63, 0x6f, 0x6c, 0x6c, - 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x54, 0x68, 0x72, 0x65, 0x73, 0x68, 0x6f, 0x6c, 0x64, 0x12, 0x2c, - 0x0a, 0x12, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x5f, 0x63, 0x61, 0x63, 0x68, 0x65, 0x64, 0x5f, - 0x64, 0x61, 0x74, 0x61, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x10, 0x64, 0x65, 0x6c, 0x65, - 0x74, 0x65, 0x43, 0x61, 0x63, 0x68, 0x65, 0x64, 0x44, 0x61, 0x74, 0x61, 0x42, 0x0c, 0x0a, 0x0a, - 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x22, 0x42, 0x0a, 0x0b, 0x47, 0x6f, - 0x6f, 0x67, 0x6c, 0x65, 0x44, 0x72, 0x69, 0x76, 0x65, 0x12, 0x25, 0x0a, 0x0d, 0x72, 0x65, 0x66, - 0x72, 0x65, 0x73, 0x68, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, - 0x48, 0x00, 0x52, 0x0c, 0x72, 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x54, 0x6f, 0x6b, 0x65, 0x6e, - 0x42, 0x0c, 0x0a, 0x0a, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x22, 0xe5, - 0x05, 0x0a, 0x0b, 0x48, 0x75, 0x67, 0x67, 0x69, 0x6e, 0x67, 0x66, 0x61, 0x63, 0x65, 0x12, 0x24, - 0x0a, 0x08, 0x65, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, - 0x42, 0x08, 0xfa, 0x42, 0x05, 0x72, 0x03, 0x90, 0x01, 0x01, 0x52, 0x08, 0x65, 0x6e, 0x64, 0x70, - 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x16, 0x0a, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x48, 0x0a, 0x0f, - 0x75, 0x6e, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x64, 0x18, - 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, - 0x61, 0x6c, 0x73, 0x2e, 0x55, 0x6e, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, - 0x74, 0x65, 0x64, 0x48, 0x00, 0x52, 0x0f, 0x75, 0x6e, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, - 0x69, 0x63, 0x61, 0x74, 0x65, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x73, - 0x18, 0x04, 0x20, 0x03, 0x28, 0x09, 0x52, 0x06, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x73, 0x12, 0x16, - 0x0a, 0x06, 0x73, 0x70, 0x61, 0x63, 0x65, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x09, 0x52, 0x06, - 0x73, 0x70, 0x61, 0x63, 0x65, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x64, 0x61, 0x74, 0x61, 0x73, 0x65, - 0x74, 0x73, 0x18, 0x0c, 0x20, 0x03, 0x28, 0x09, 0x52, 0x08, 0x64, 0x61, 0x74, 0x61, 0x73, 0x65, - 0x74, 0x73, 0x12, 0x24, 0x0a, 0x0d, 0x6f, 0x72, 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, - 0x6f, 0x6e, 0x73, 0x18, 0x06, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0d, 0x6f, 0x72, 0x67, 0x61, 0x6e, - 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x14, 0x0a, 0x05, 0x75, 0x73, 0x65, 0x72, - 0x73, 0x18, 0x0f, 0x20, 0x03, 0x28, 0x09, 0x52, 0x05, 0x75, 0x73, 0x65, 0x72, 0x73, 0x12, 0x23, - 0x0a, 0x0d, 0x69, 0x67, 0x6e, 0x6f, 0x72, 0x65, 0x5f, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x73, 0x18, - 0x07, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0c, 0x69, 0x67, 0x6e, 0x6f, 0x72, 0x65, 0x4d, 0x6f, 0x64, - 0x65, 0x6c, 0x73, 0x12, 0x25, 0x0a, 0x0e, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x5f, 0x6d, - 0x6f, 0x64, 0x65, 0x6c, 0x73, 0x18, 0x08, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0d, 0x69, 0x6e, 0x63, - 0x6c, 0x75, 0x64, 0x65, 0x4d, 0x6f, 0x64, 0x65, 0x6c, 0x73, 0x12, 0x23, 0x0a, 0x0d, 0x69, 0x67, - 0x6e, 0x6f, 0x72, 0x65, 0x5f, 0x73, 0x70, 0x61, 0x63, 0x65, 0x73, 0x18, 0x09, 0x20, 0x03, 0x28, - 0x09, 0x52, 0x0c, 0x69, 0x67, 0x6e, 0x6f, 0x72, 0x65, 0x53, 0x70, 0x61, 0x63, 0x65, 0x73, 0x12, - 0x25, 0x0a, 0x0e, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x5f, 0x73, 0x70, 0x61, 0x63, 0x65, - 0x73, 0x18, 0x0a, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0d, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, - 0x53, 0x70, 0x61, 0x63, 0x65, 0x73, 0x12, 0x27, 0x0a, 0x0f, 0x69, 0x67, 0x6e, 0x6f, 0x72, 0x65, - 0x5f, 0x64, 0x61, 0x74, 0x61, 0x73, 0x65, 0x74, 0x73, 0x18, 0x0d, 0x20, 0x03, 0x28, 0x09, 0x52, - 0x0e, 0x69, 0x67, 0x6e, 0x6f, 0x72, 0x65, 0x44, 0x61, 0x74, 0x61, 0x73, 0x65, 0x74, 0x73, 0x12, - 0x29, 0x0a, 0x10, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x5f, 0x64, 0x61, 0x74, 0x61, 0x73, - 0x65, 0x74, 0x73, 0x18, 0x0e, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0f, 0x69, 0x6e, 0x63, 0x6c, 0x75, - 0x64, 0x65, 0x44, 0x61, 0x74, 0x61, 0x73, 0x65, 0x74, 0x73, 0x12, 0x26, 0x0a, 0x0f, 0x73, 0x6b, - 0x69, 0x70, 0x5f, 0x61, 0x6c, 0x6c, 0x5f, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x73, 0x18, 0x10, 0x20, - 0x01, 0x28, 0x08, 0x52, 0x0d, 0x73, 0x6b, 0x69, 0x70, 0x41, 0x6c, 0x6c, 0x4d, 0x6f, 0x64, 0x65, - 0x6c, 0x73, 0x12, 0x26, 0x0a, 0x0f, 0x73, 0x6b, 0x69, 0x70, 0x5f, 0x61, 0x6c, 0x6c, 0x5f, 0x73, - 0x70, 0x61, 0x63, 0x65, 0x73, 0x18, 0x11, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0d, 0x73, 0x6b, 0x69, - 0x70, 0x41, 0x6c, 0x6c, 0x53, 0x70, 0x61, 0x63, 0x65, 0x73, 0x12, 0x2a, 0x0a, 0x11, 0x73, 0x6b, - 0x69, 0x70, 0x5f, 0x61, 0x6c, 0x6c, 0x5f, 0x64, 0x61, 0x74, 0x61, 0x73, 0x65, 0x74, 0x73, 0x18, - 0x12, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0f, 0x73, 0x6b, 0x69, 0x70, 0x41, 0x6c, 0x6c, 0x44, 0x61, - 0x74, 0x61, 0x73, 0x65, 0x74, 0x73, 0x12, 0x2f, 0x0a, 0x13, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, - 0x65, 0x5f, 0x64, 0x69, 0x73, 0x63, 0x75, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x0b, 0x20, - 0x01, 0x28, 0x08, 0x52, 0x12, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x44, 0x69, 0x73, 0x63, - 0x75, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x1f, 0x0a, 0x0b, 0x69, 0x6e, 0x63, 0x6c, 0x75, - 0x64, 0x65, 0x5f, 0x70, 0x72, 0x73, 0x18, 0x13, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x69, 0x6e, - 0x63, 0x6c, 0x75, 0x64, 0x65, 0x50, 0x72, 0x73, 0x42, 0x0c, 0x0a, 0x0a, 0x63, 0x72, 0x65, 0x64, - 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x22, 0x80, 0x03, 0x0a, 0x04, 0x4a, 0x49, 0x52, 0x41, 0x12, - 0x24, 0x0a, 0x08, 0x65, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x09, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x72, 0x03, 0x90, 0x01, 0x01, 0x52, 0x08, 0x65, 0x6e, 0x64, - 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x37, 0x0a, 0x0a, 0x62, 0x61, 0x73, 0x69, 0x63, 0x5f, 0x61, - 0x75, 0x74, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x63, 0x72, 0x65, 0x64, - 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x73, 0x2e, 0x42, 0x61, 0x73, 0x69, 0x63, 0x41, 0x75, 0x74, - 0x68, 0x48, 0x00, 0x52, 0x09, 0x62, 0x61, 0x73, 0x69, 0x63, 0x41, 0x75, 0x74, 0x68, 0x12, 0x48, - 0x0a, 0x0f, 0x75, 0x6e, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, - 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, - 0x74, 0x69, 0x61, 0x6c, 0x73, 0x2e, 0x55, 0x6e, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, - 0x63, 0x61, 0x74, 0x65, 0x64, 0x48, 0x00, 0x52, 0x0f, 0x75, 0x6e, 0x61, 0x75, 0x74, 0x68, 0x65, - 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x64, 0x12, 0x2b, 0x0a, 0x05, 0x6f, 0x61, 0x75, 0x74, - 0x68, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, - 0x74, 0x69, 0x61, 0x6c, 0x73, 0x2e, 0x4f, 0x61, 0x75, 0x74, 0x68, 0x32, 0x48, 0x00, 0x52, 0x05, - 0x6f, 0x61, 0x75, 0x74, 0x68, 0x12, 0x16, 0x0a, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x06, - 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x1a, 0x0a, - 0x08, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x09, 0x52, - 0x08, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x12, 0x27, 0x0a, 0x0f, 0x69, 0x67, 0x6e, - 0x6f, 0x72, 0x65, 0x5f, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x18, 0x07, 0x20, 0x03, - 0x28, 0x09, 0x52, 0x0e, 0x69, 0x67, 0x6e, 0x6f, 0x72, 0x65, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, - 0x74, 0x73, 0x12, 0x37, 0x0a, 0x18, 0x69, 0x6e, 0x73, 0x65, 0x63, 0x75, 0x72, 0x65, 0x5f, 0x73, - 0x6b, 0x69, 0x70, 0x5f, 0x76, 0x65, 0x72, 0x69, 0x66, 0x79, 0x5f, 0x74, 0x6c, 0x73, 0x18, 0x08, - 0x20, 0x01, 0x28, 0x08, 0x52, 0x15, 0x69, 0x6e, 0x73, 0x65, 0x63, 0x75, 0x72, 0x65, 0x53, 0x6b, - 0x69, 0x70, 0x56, 0x65, 0x72, 0x69, 0x66, 0x79, 0x54, 0x6c, 0x73, 0x42, 0x0c, 0x0a, 0x0a, 0x63, - 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x22, 0x73, 0x0a, 0x19, 0x4e, 0x50, 0x4d, - 0x55, 0x6e, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x64, 0x50, - 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x12, 0x48, 0x0a, 0x0f, 0x75, 0x6e, 0x61, 0x75, 0x74, 0x68, - 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x57, 0x69, 0x6b, 0x69, 0x73, 0x12, 0x36, 0x0a, 0x17, 0x63, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, + 0x73, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x5f, 0x64, 0x61, 0x79, 0x73, + 0x18, 0x14, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x15, 0x63, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x73, + 0x54, 0x69, 0x6d, 0x65, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x44, 0x61, 0x79, 0x73, 0x42, 0x0c, 0x0a, + 0x0a, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x22, 0xe4, 0x01, 0x0a, 0x12, + 0x47, 0x69, 0x74, 0x48, 0x75, 0x62, 0x45, 0x78, 0x70, 0x65, 0x72, 0x69, 0x6d, 0x65, 0x6e, 0x74, + 0x61, 0x6c, 0x12, 0x1e, 0x0a, 0x0a, 0x72, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x6f, 0x72, 0x79, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x72, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x6f, + 0x72, 0x79, 0x12, 0x16, 0x0a, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x09, 0x48, 0x00, 0x52, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x29, 0x0a, 0x10, 0x6f, 0x62, + 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x64, 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x79, 0x18, 0x03, + 0x20, 0x01, 0x28, 0x08, 0x52, 0x0f, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x44, 0x69, 0x73, 0x63, + 0x6f, 0x76, 0x65, 0x72, 0x79, 0x12, 0x2f, 0x0a, 0x13, 0x63, 0x6f, 0x6c, 0x6c, 0x69, 0x73, 0x69, + 0x6f, 0x6e, 0x5f, 0x74, 0x68, 0x72, 0x65, 0x73, 0x68, 0x6f, 0x6c, 0x64, 0x18, 0x04, 0x20, 0x01, + 0x28, 0x03, 0x52, 0x12, 0x63, 0x6f, 0x6c, 0x6c, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x54, 0x68, 0x72, + 0x65, 0x73, 0x68, 0x6f, 0x6c, 0x64, 0x12, 0x2c, 0x0a, 0x12, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, + 0x5f, 0x63, 0x61, 0x63, 0x68, 0x65, 0x64, 0x5f, 0x64, 0x61, 0x74, 0x61, 0x18, 0x05, 0x20, 0x01, + 0x28, 0x08, 0x52, 0x10, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x43, 0x61, 0x63, 0x68, 0x65, 0x64, + 0x44, 0x61, 0x74, 0x61, 0x42, 0x0c, 0x0a, 0x0a, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, + 0x61, 0x6c, 0x22, 0x42, 0x0a, 0x0b, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x44, 0x72, 0x69, 0x76, + 0x65, 0x12, 0x25, 0x0a, 0x0d, 0x72, 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x5f, 0x74, 0x6f, 0x6b, + 0x65, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x0c, 0x72, 0x65, 0x66, 0x72, + 0x65, 0x73, 0x68, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x42, 0x0c, 0x0a, 0x0a, 0x63, 0x72, 0x65, 0x64, + 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x22, 0xe5, 0x05, 0x0a, 0x0b, 0x48, 0x75, 0x67, 0x67, 0x69, + 0x6e, 0x67, 0x66, 0x61, 0x63, 0x65, 0x12, 0x24, 0x0a, 0x08, 0x65, 0x6e, 0x64, 0x70, 0x6f, 0x69, + 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x72, 0x03, 0x90, + 0x01, 0x01, 0x52, 0x08, 0x65, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x16, 0x0a, 0x05, + 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x05, 0x74, + 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x48, 0x0a, 0x0f, 0x75, 0x6e, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, + 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, + 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x73, 0x2e, 0x55, 0x6e, 0x61, 0x75, + 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x64, 0x48, 0x00, 0x52, 0x0f, 0x75, + 0x6e, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x64, 0x12, 0x16, + 0x0a, 0x06, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x09, 0x52, 0x06, + 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x73, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x70, 0x61, 0x63, 0x65, 0x73, + 0x18, 0x05, 0x20, 0x03, 0x28, 0x09, 0x52, 0x06, 0x73, 0x70, 0x61, 0x63, 0x65, 0x73, 0x12, 0x1a, + 0x0a, 0x08, 0x64, 0x61, 0x74, 0x61, 0x73, 0x65, 0x74, 0x73, 0x18, 0x0c, 0x20, 0x03, 0x28, 0x09, + 0x52, 0x08, 0x64, 0x61, 0x74, 0x61, 0x73, 0x65, 0x74, 0x73, 0x12, 0x24, 0x0a, 0x0d, 0x6f, 0x72, + 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x06, 0x20, 0x03, 0x28, + 0x09, 0x52, 0x0d, 0x6f, 0x72, 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, + 0x12, 0x14, 0x0a, 0x05, 0x75, 0x73, 0x65, 0x72, 0x73, 0x18, 0x0f, 0x20, 0x03, 0x28, 0x09, 0x52, + 0x05, 0x75, 0x73, 0x65, 0x72, 0x73, 0x12, 0x23, 0x0a, 0x0d, 0x69, 0x67, 0x6e, 0x6f, 0x72, 0x65, + 0x5f, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x73, 0x18, 0x07, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0c, 0x69, + 0x67, 0x6e, 0x6f, 0x72, 0x65, 0x4d, 0x6f, 0x64, 0x65, 0x6c, 0x73, 0x12, 0x25, 0x0a, 0x0e, 0x69, + 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x5f, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x73, 0x18, 0x08, 0x20, + 0x03, 0x28, 0x09, 0x52, 0x0d, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x4d, 0x6f, 0x64, 0x65, + 0x6c, 0x73, 0x12, 0x23, 0x0a, 0x0d, 0x69, 0x67, 0x6e, 0x6f, 0x72, 0x65, 0x5f, 0x73, 0x70, 0x61, + 0x63, 0x65, 0x73, 0x18, 0x09, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0c, 0x69, 0x67, 0x6e, 0x6f, 0x72, + 0x65, 0x53, 0x70, 0x61, 0x63, 0x65, 0x73, 0x12, 0x25, 0x0a, 0x0e, 0x69, 0x6e, 0x63, 0x6c, 0x75, + 0x64, 0x65, 0x5f, 0x73, 0x70, 0x61, 0x63, 0x65, 0x73, 0x18, 0x0a, 0x20, 0x03, 0x28, 0x09, 0x52, + 0x0d, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x53, 0x70, 0x61, 0x63, 0x65, 0x73, 0x12, 0x27, + 0x0a, 0x0f, 0x69, 0x67, 0x6e, 0x6f, 0x72, 0x65, 0x5f, 0x64, 0x61, 0x74, 0x61, 0x73, 0x65, 0x74, + 0x73, 0x18, 0x0d, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0e, 0x69, 0x67, 0x6e, 0x6f, 0x72, 0x65, 0x44, + 0x61, 0x74, 0x61, 0x73, 0x65, 0x74, 0x73, 0x12, 0x29, 0x0a, 0x10, 0x69, 0x6e, 0x63, 0x6c, 0x75, + 0x64, 0x65, 0x5f, 0x64, 0x61, 0x74, 0x61, 0x73, 0x65, 0x74, 0x73, 0x18, 0x0e, 0x20, 0x03, 0x28, + 0x09, 0x52, 0x0f, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x44, 0x61, 0x74, 0x61, 0x73, 0x65, + 0x74, 0x73, 0x12, 0x26, 0x0a, 0x0f, 0x73, 0x6b, 0x69, 0x70, 0x5f, 0x61, 0x6c, 0x6c, 0x5f, 0x6d, + 0x6f, 0x64, 0x65, 0x6c, 0x73, 0x18, 0x10, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0d, 0x73, 0x6b, 0x69, + 0x70, 0x41, 0x6c, 0x6c, 0x4d, 0x6f, 0x64, 0x65, 0x6c, 0x73, 0x12, 0x26, 0x0a, 0x0f, 0x73, 0x6b, + 0x69, 0x70, 0x5f, 0x61, 0x6c, 0x6c, 0x5f, 0x73, 0x70, 0x61, 0x63, 0x65, 0x73, 0x18, 0x11, 0x20, + 0x01, 0x28, 0x08, 0x52, 0x0d, 0x73, 0x6b, 0x69, 0x70, 0x41, 0x6c, 0x6c, 0x53, 0x70, 0x61, 0x63, + 0x65, 0x73, 0x12, 0x2a, 0x0a, 0x11, 0x73, 0x6b, 0x69, 0x70, 0x5f, 0x61, 0x6c, 0x6c, 0x5f, 0x64, + 0x61, 0x74, 0x61, 0x73, 0x65, 0x74, 0x73, 0x18, 0x12, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0f, 0x73, + 0x6b, 0x69, 0x70, 0x41, 0x6c, 0x6c, 0x44, 0x61, 0x74, 0x61, 0x73, 0x65, 0x74, 0x73, 0x12, 0x2f, + 0x0a, 0x13, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x5f, 0x64, 0x69, 0x73, 0x63, 0x75, 0x73, + 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x08, 0x52, 0x12, 0x69, 0x6e, 0x63, + 0x6c, 0x75, 0x64, 0x65, 0x44, 0x69, 0x73, 0x63, 0x75, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x12, + 0x1f, 0x0a, 0x0b, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x5f, 0x70, 0x72, 0x73, 0x18, 0x13, + 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x50, 0x72, 0x73, + 0x42, 0x0c, 0x0a, 0x0a, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x22, 0x80, + 0x03, 0x0a, 0x04, 0x4a, 0x49, 0x52, 0x41, 0x12, 0x24, 0x0a, 0x08, 0x65, 0x6e, 0x64, 0x70, 0x6f, + 0x69, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x72, 0x03, + 0x90, 0x01, 0x01, 0x52, 0x08, 0x65, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x37, 0x0a, + 0x0a, 0x62, 0x61, 0x73, 0x69, 0x63, 0x5f, 0x61, 0x75, 0x74, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x16, 0x2e, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x73, 0x2e, + 0x42, 0x61, 0x73, 0x69, 0x63, 0x41, 0x75, 0x74, 0x68, 0x48, 0x00, 0x52, 0x09, 0x62, 0x61, 0x73, + 0x69, 0x63, 0x41, 0x75, 0x74, 0x68, 0x12, 0x48, 0x0a, 0x0f, 0x75, 0x6e, 0x61, 0x75, 0x74, 0x68, + 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x73, 0x2e, 0x55, 0x6e, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x64, 0x48, 0x00, 0x52, 0x0f, 0x75, 0x6e, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x64, - 0x42, 0x0c, 0x0a, 0x0a, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x22, 0x74, - 0x0a, 0x1a, 0x50, 0x79, 0x50, 0x49, 0x55, 0x6e, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, - 0x63, 0x61, 0x74, 0x65, 0x64, 0x50, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x12, 0x48, 0x0a, 0x0f, + 0x12, 0x2b, 0x0a, 0x05, 0x6f, 0x61, 0x75, 0x74, 0x68, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x13, 0x2e, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x73, 0x2e, 0x4f, 0x61, + 0x75, 0x74, 0x68, 0x32, 0x48, 0x00, 0x52, 0x05, 0x6f, 0x61, 0x75, 0x74, 0x68, 0x12, 0x16, 0x0a, + 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x05, + 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, + 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x09, 0x52, 0x08, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, + 0x73, 0x12, 0x27, 0x0a, 0x0f, 0x69, 0x67, 0x6e, 0x6f, 0x72, 0x65, 0x5f, 0x70, 0x72, 0x6f, 0x6a, + 0x65, 0x63, 0x74, 0x73, 0x18, 0x07, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0e, 0x69, 0x67, 0x6e, 0x6f, + 0x72, 0x65, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x12, 0x37, 0x0a, 0x18, 0x69, 0x6e, + 0x73, 0x65, 0x63, 0x75, 0x72, 0x65, 0x5f, 0x73, 0x6b, 0x69, 0x70, 0x5f, 0x76, 0x65, 0x72, 0x69, + 0x66, 0x79, 0x5f, 0x74, 0x6c, 0x73, 0x18, 0x08, 0x20, 0x01, 0x28, 0x08, 0x52, 0x15, 0x69, 0x6e, + 0x73, 0x65, 0x63, 0x75, 0x72, 0x65, 0x53, 0x6b, 0x69, 0x70, 0x56, 0x65, 0x72, 0x69, 0x66, 0x79, + 0x54, 0x6c, 0x73, 0x42, 0x0c, 0x0a, 0x0a, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, + 0x6c, 0x22, 0x73, 0x0a, 0x19, 0x4e, 0x50, 0x4d, 0x55, 0x6e, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, + 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x64, 0x50, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x12, 0x48, + 0x0a, 0x0f, 0x75, 0x6e, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, + 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, + 0x74, 0x69, 0x61, 0x6c, 0x73, 0x2e, 0x55, 0x6e, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, + 0x63, 0x61, 0x74, 0x65, 0x64, 0x48, 0x00, 0x52, 0x0f, 0x75, 0x6e, 0x61, 0x75, 0x74, 0x68, 0x65, + 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x64, 0x42, 0x0c, 0x0a, 0x0a, 0x63, 0x72, 0x65, 0x64, + 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x22, 0x74, 0x0a, 0x1a, 0x50, 0x79, 0x50, 0x49, 0x55, 0x6e, + 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x64, 0x50, 0x61, 0x63, + 0x6b, 0x61, 0x67, 0x65, 0x12, 0x48, 0x0a, 0x0f, 0x75, 0x6e, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, + 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, + 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x73, 0x2e, 0x55, 0x6e, 0x61, 0x75, + 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x64, 0x48, 0x00, 0x52, 0x0f, 0x75, + 0x6e, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x64, 0x42, 0x0c, + 0x0a, 0x0a, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x22, 0xad, 0x03, 0x0a, + 0x02, 0x53, 0x33, 0x12, 0x37, 0x0a, 0x0a, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x5f, 0x6b, 0x65, + 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, + 0x74, 0x69, 0x61, 0x6c, 0x73, 0x2e, 0x4b, 0x65, 0x79, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x48, + 0x00, 0x52, 0x09, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x4b, 0x65, 0x79, 0x12, 0x48, 0x0a, 0x0f, 0x75, 0x6e, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x64, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, + 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x73, 0x2e, 0x55, 0x6e, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x64, 0x48, 0x00, 0x52, 0x0f, 0x75, 0x6e, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, - 0x69, 0x63, 0x61, 0x74, 0x65, 0x64, 0x42, 0x0c, 0x0a, 0x0a, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, - 0x74, 0x69, 0x61, 0x6c, 0x22, 0xad, 0x03, 0x0a, 0x02, 0x53, 0x33, 0x12, 0x37, 0x0a, 0x0a, 0x61, - 0x63, 0x63, 0x65, 0x73, 0x73, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x16, 0x2e, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x73, 0x2e, 0x4b, 0x65, - 0x79, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x48, 0x00, 0x52, 0x09, 0x61, 0x63, 0x63, 0x65, 0x73, - 0x73, 0x4b, 0x65, 0x79, 0x12, 0x48, 0x0a, 0x0f, 0x75, 0x6e, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, - 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, - 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x73, 0x2e, 0x55, 0x6e, 0x61, 0x75, - 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x64, 0x48, 0x00, 0x52, 0x0f, 0x75, - 0x6e, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x64, 0x12, 0x4c, - 0x0a, 0x11, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x5f, 0x65, 0x6e, 0x76, 0x69, 0x72, 0x6f, 0x6e, 0x6d, - 0x65, 0x6e, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x63, 0x72, 0x65, 0x64, - 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x73, 0x2e, 0x43, 0x6c, 0x6f, 0x75, 0x64, 0x45, 0x6e, 0x76, - 0x69, 0x72, 0x6f, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x48, 0x00, 0x52, 0x10, 0x63, 0x6c, 0x6f, 0x75, - 0x64, 0x45, 0x6e, 0x76, 0x69, 0x72, 0x6f, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x12, 0x49, 0x0a, 0x0d, - 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x05, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, - 0x73, 0x2e, 0x41, 0x57, 0x53, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x54, 0x6f, 0x6b, 0x65, - 0x6e, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x48, 0x00, 0x52, 0x0c, 0x73, 0x65, 0x73, 0x73, 0x69, - 0x6f, 0x6e, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x18, 0x0a, 0x07, 0x62, 0x75, 0x63, 0x6b, 0x65, - 0x74, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x52, 0x07, 0x62, 0x75, 0x63, 0x6b, 0x65, 0x74, - 0x73, 0x12, 0x26, 0x0a, 0x0f, 0x6d, 0x61, 0x78, 0x5f, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x5f, - 0x73, 0x69, 0x7a, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0d, 0x6d, 0x61, 0x78, 0x4f, - 0x62, 0x6a, 0x65, 0x63, 0x74, 0x53, 0x69, 0x7a, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x72, 0x6f, 0x6c, - 0x65, 0x73, 0x18, 0x07, 0x20, 0x03, 0x28, 0x09, 0x52, 0x05, 0x72, 0x6f, 0x6c, 0x65, 0x73, 0x12, - 0x25, 0x0a, 0x0e, 0x69, 0x67, 0x6e, 0x6f, 0x72, 0x65, 0x5f, 0x62, 0x75, 0x63, 0x6b, 0x65, 0x74, - 0x73, 0x18, 0x08, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0d, 0x69, 0x67, 0x6e, 0x6f, 0x72, 0x65, 0x42, - 0x75, 0x63, 0x6b, 0x65, 0x74, 0x73, 0x42, 0x0c, 0x0a, 0x0a, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, - 0x74, 0x69, 0x61, 0x6c, 0x22, 0xc4, 0x01, 0x0a, 0x05, 0x53, 0x6c, 0x61, 0x63, 0x6b, 0x12, 0x24, - 0x0a, 0x08, 0x65, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, - 0x42, 0x08, 0xfa, 0x42, 0x05, 0x72, 0x03, 0x90, 0x01, 0x01, 0x52, 0x08, 0x65, 0x6e, 0x64, 0x70, - 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x16, 0x0a, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x32, 0x0a, 0x06, - 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x63, - 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x73, 0x2e, 0x53, 0x6c, 0x61, 0x63, 0x6b, - 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x73, 0x48, 0x00, 0x52, 0x06, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x73, - 0x12, 0x1a, 0x0a, 0x08, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x73, 0x18, 0x03, 0x20, 0x03, - 0x28, 0x09, 0x52, 0x08, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x73, 0x12, 0x1f, 0x0a, 0x0b, - 0x69, 0x67, 0x6e, 0x6f, 0x72, 0x65, 0x5f, 0x6c, 0x69, 0x73, 0x74, 0x18, 0x04, 0x20, 0x03, 0x28, - 0x09, 0x52, 0x0a, 0x69, 0x67, 0x6e, 0x6f, 0x72, 0x65, 0x4c, 0x69, 0x73, 0x74, 0x42, 0x0c, 0x0a, - 0x0a, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x22, 0x06, 0x0a, 0x04, 0x54, - 0x65, 0x73, 0x74, 0x22, 0x31, 0x0a, 0x09, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x6b, 0x69, 0x74, 0x65, - 0x12, 0x16, 0x0a, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x48, - 0x00, 0x52, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x42, 0x0c, 0x0a, 0x0a, 0x63, 0x72, 0x65, 0x64, - 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x22, 0xa5, 0x02, 0x0a, 0x06, 0x47, 0x65, 0x72, 0x72, 0x69, - 0x74, 0x12, 0x24, 0x0a, 0x08, 0x65, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x09, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x72, 0x03, 0x90, 0x01, 0x01, 0x52, 0x08, 0x65, - 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x37, 0x0a, 0x0a, 0x62, 0x61, 0x73, 0x69, 0x63, - 0x5f, 0x61, 0x75, 0x74, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x63, 0x72, - 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x73, 0x2e, 0x42, 0x61, 0x73, 0x69, 0x63, 0x41, - 0x75, 0x74, 0x68, 0x48, 0x00, 0x52, 0x09, 0x62, 0x61, 0x73, 0x69, 0x63, 0x41, 0x75, 0x74, 0x68, - 0x12, 0x48, 0x0a, 0x0f, 0x75, 0x6e, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, - 0x74, 0x65, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x63, 0x72, 0x65, 0x64, - 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x73, 0x2e, 0x55, 0x6e, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, - 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x64, 0x48, 0x00, 0x52, 0x0f, 0x75, 0x6e, 0x61, 0x75, 0x74, - 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x64, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x72, - 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x09, 0x52, 0x08, 0x70, 0x72, - 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x12, 0x23, 0x0a, 0x0d, 0x73, 0x6b, 0x69, 0x70, 0x5f, 0x62, - 0x69, 0x6e, 0x61, 0x72, 0x69, 0x65, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x73, - 0x6b, 0x69, 0x70, 0x42, 0x69, 0x6e, 0x61, 0x72, 0x69, 0x65, 0x73, 0x12, 0x23, 0x0a, 0x0d, 0x73, - 0x6b, 0x69, 0x70, 0x5f, 0x61, 0x72, 0x63, 0x68, 0x69, 0x76, 0x65, 0x73, 0x18, 0x06, 0x20, 0x01, - 0x28, 0x08, 0x52, 0x0c, 0x73, 0x6b, 0x69, 0x70, 0x41, 0x72, 0x63, 0x68, 0x69, 0x76, 0x65, 0x73, - 0x42, 0x0c, 0x0a, 0x0a, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x22, 0xa8, - 0x02, 0x0a, 0x07, 0x4a, 0x65, 0x6e, 0x6b, 0x69, 0x6e, 0x73, 0x12, 0x24, 0x0a, 0x08, 0x65, 0x6e, - 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x08, 0xfa, 0x42, - 0x05, 0x72, 0x03, 0x90, 0x01, 0x01, 0x52, 0x08, 0x65, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, - 0x12, 0x37, 0x0a, 0x0a, 0x62, 0x61, 0x73, 0x69, 0x63, 0x5f, 0x61, 0x75, 0x74, 0x68, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, - 0x6c, 0x73, 0x2e, 0x42, 0x61, 0x73, 0x69, 0x63, 0x41, 0x75, 0x74, 0x68, 0x48, 0x00, 0x52, 0x09, - 0x62, 0x61, 0x73, 0x69, 0x63, 0x41, 0x75, 0x74, 0x68, 0x12, 0x2d, 0x0a, 0x06, 0x68, 0x65, 0x61, - 0x64, 0x65, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x63, 0x72, 0x65, 0x64, - 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x73, 0x2e, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x48, 0x00, - 0x52, 0x06, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x12, 0x48, 0x0a, 0x0f, 0x75, 0x6e, 0x61, 0x75, - 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, + 0x69, 0x63, 0x61, 0x74, 0x65, 0x64, 0x12, 0x4c, 0x0a, 0x11, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x5f, + 0x65, 0x6e, 0x76, 0x69, 0x72, 0x6f, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x1d, 0x2e, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x73, 0x2e, + 0x43, 0x6c, 0x6f, 0x75, 0x64, 0x45, 0x6e, 0x76, 0x69, 0x72, 0x6f, 0x6e, 0x6d, 0x65, 0x6e, 0x74, + 0x48, 0x00, 0x52, 0x10, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x45, 0x6e, 0x76, 0x69, 0x72, 0x6f, 0x6e, + 0x6d, 0x65, 0x6e, 0x74, 0x12, 0x49, 0x0a, 0x0d, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x5f, + 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x63, 0x72, + 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x73, 0x2e, 0x41, 0x57, 0x53, 0x53, 0x65, 0x73, + 0x73, 0x69, 0x6f, 0x6e, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x48, + 0x00, 0x52, 0x0c, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x12, + 0x18, 0x0a, 0x07, 0x62, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, + 0x52, 0x07, 0x62, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x73, 0x12, 0x26, 0x0a, 0x0f, 0x6d, 0x61, 0x78, + 0x5f, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x06, 0x20, 0x01, + 0x28, 0x03, 0x52, 0x0d, 0x6d, 0x61, 0x78, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x53, 0x69, 0x7a, + 0x65, 0x12, 0x14, 0x0a, 0x05, 0x72, 0x6f, 0x6c, 0x65, 0x73, 0x18, 0x07, 0x20, 0x03, 0x28, 0x09, + 0x52, 0x05, 0x72, 0x6f, 0x6c, 0x65, 0x73, 0x12, 0x25, 0x0a, 0x0e, 0x69, 0x67, 0x6e, 0x6f, 0x72, + 0x65, 0x5f, 0x62, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x73, 0x18, 0x08, 0x20, 0x03, 0x28, 0x09, 0x52, + 0x0d, 0x69, 0x67, 0x6e, 0x6f, 0x72, 0x65, 0x42, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x73, 0x42, 0x0c, + 0x0a, 0x0a, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x22, 0xc4, 0x01, 0x0a, + 0x05, 0x53, 0x6c, 0x61, 0x63, 0x6b, 0x12, 0x24, 0x0a, 0x08, 0x65, 0x6e, 0x64, 0x70, 0x6f, 0x69, + 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x72, 0x03, 0x90, + 0x01, 0x01, 0x52, 0x08, 0x65, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x16, 0x0a, 0x05, + 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x05, 0x74, + 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x32, 0x0a, 0x06, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x73, 0x18, 0x05, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, + 0x6c, 0x73, 0x2e, 0x53, 0x6c, 0x61, 0x63, 0x6b, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x73, 0x48, 0x00, + 0x52, 0x06, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x63, 0x68, 0x61, 0x6e, + 0x6e, 0x65, 0x6c, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x52, 0x08, 0x63, 0x68, 0x61, 0x6e, + 0x6e, 0x65, 0x6c, 0x73, 0x12, 0x1f, 0x0a, 0x0b, 0x69, 0x67, 0x6e, 0x6f, 0x72, 0x65, 0x5f, 0x6c, + 0x69, 0x73, 0x74, 0x18, 0x04, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0a, 0x69, 0x67, 0x6e, 0x6f, 0x72, + 0x65, 0x4c, 0x69, 0x73, 0x74, 0x42, 0x0c, 0x0a, 0x0a, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, + 0x69, 0x61, 0x6c, 0x22, 0x06, 0x0a, 0x04, 0x54, 0x65, 0x73, 0x74, 0x22, 0x31, 0x0a, 0x09, 0x42, + 0x75, 0x69, 0x6c, 0x64, 0x6b, 0x69, 0x74, 0x65, 0x12, 0x16, 0x0a, 0x05, 0x74, 0x6f, 0x6b, 0x65, + 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, + 0x42, 0x0c, 0x0a, 0x0a, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x22, 0xa5, + 0x02, 0x0a, 0x06, 0x47, 0x65, 0x72, 0x72, 0x69, 0x74, 0x12, 0x24, 0x0a, 0x08, 0x65, 0x6e, 0x64, + 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x08, 0xfa, 0x42, 0x05, + 0x72, 0x03, 0x90, 0x01, 0x01, 0x52, 0x08, 0x65, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x12, + 0x37, 0x0a, 0x0a, 0x62, 0x61, 0x73, 0x69, 0x63, 0x5f, 0x61, 0x75, 0x74, 0x68, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, + 0x73, 0x2e, 0x42, 0x61, 0x73, 0x69, 0x63, 0x41, 0x75, 0x74, 0x68, 0x48, 0x00, 0x52, 0x09, 0x62, + 0x61, 0x73, 0x69, 0x63, 0x41, 0x75, 0x74, 0x68, 0x12, 0x48, 0x0a, 0x0f, 0x75, 0x6e, 0x61, 0x75, + 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x73, 0x2e, 0x55, 0x6e, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x64, 0x48, 0x00, 0x52, 0x0f, 0x75, 0x6e, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, - 0x65, 0x64, 0x12, 0x37, 0x0a, 0x18, 0x69, 0x6e, 0x73, 0x65, 0x63, 0x75, 0x72, 0x65, 0x5f, 0x73, - 0x6b, 0x69, 0x70, 0x5f, 0x76, 0x65, 0x72, 0x69, 0x66, 0x79, 0x5f, 0x74, 0x6c, 0x73, 0x18, 0x04, - 0x20, 0x01, 0x28, 0x08, 0x52, 0x15, 0x69, 0x6e, 0x73, 0x65, 0x63, 0x75, 0x72, 0x65, 0x53, 0x6b, - 0x69, 0x70, 0x56, 0x65, 0x72, 0x69, 0x66, 0x79, 0x54, 0x6c, 0x73, 0x42, 0x0c, 0x0a, 0x0a, 0x63, - 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x22, 0xa0, 0x02, 0x0a, 0x05, 0x54, 0x65, - 0x61, 0x6d, 0x73, 0x12, 0x24, 0x0a, 0x08, 0x65, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x72, 0x03, 0x90, 0x01, 0x01, 0x52, - 0x08, 0x65, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x16, 0x0a, 0x05, 0x74, 0x6f, 0x6b, - 0x65, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x05, 0x74, 0x6f, 0x6b, 0x65, - 0x6e, 0x12, 0x46, 0x0a, 0x0d, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, - 0x65, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x63, 0x72, 0x65, 0x64, 0x65, - 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x73, 0x2e, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x43, 0x72, 0x65, - 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x73, 0x48, 0x00, 0x52, 0x0d, 0x61, 0x75, 0x74, 0x68, - 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x64, 0x12, 0x2b, 0x0a, 0x05, 0x6f, 0x61, 0x75, - 0x74, 0x68, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x63, 0x72, 0x65, 0x64, 0x65, - 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x73, 0x2e, 0x4f, 0x61, 0x75, 0x74, 0x68, 0x32, 0x48, 0x00, 0x52, - 0x05, 0x6f, 0x61, 0x75, 0x74, 0x68, 0x12, 0x1a, 0x0a, 0x08, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, - 0x6c, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x09, 0x52, 0x08, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, - 0x6c, 0x73, 0x12, 0x1f, 0x0a, 0x0b, 0x69, 0x67, 0x6e, 0x6f, 0x72, 0x65, 0x5f, 0x6c, 0x69, 0x73, - 0x74, 0x18, 0x05, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0a, 0x69, 0x67, 0x6e, 0x6f, 0x72, 0x65, 0x4c, - 0x69, 0x73, 0x74, 0x12, 0x19, 0x0a, 0x08, 0x74, 0x65, 0x61, 0x6d, 0x5f, 0x69, 0x64, 0x73, 0x18, - 0x06, 0x20, 0x03, 0x28, 0x09, 0x52, 0x07, 0x74, 0x65, 0x61, 0x6d, 0x49, 0x64, 0x73, 0x42, 0x0c, - 0x0a, 0x0a, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x22, 0x95, 0x01, 0x0a, - 0x06, 0x53, 0x79, 0x73, 0x6c, 0x6f, 0x67, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x63, 0x6f, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x63, 0x6f, 0x6c, 0x12, 0x25, 0x0a, 0x0e, 0x6c, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x5f, 0x61, 0x64, - 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x6c, 0x69, 0x73, - 0x74, 0x65, 0x6e, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x74, 0x6c, - 0x73, 0x43, 0x65, 0x72, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x74, 0x6c, 0x73, - 0x43, 0x65, 0x72, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x74, 0x6c, 0x73, 0x4b, 0x65, 0x79, 0x18, 0x04, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x74, 0x6c, 0x73, 0x4b, 0x65, 0x79, 0x12, 0x16, 0x0a, 0x06, - 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x66, 0x6f, - 0x72, 0x6d, 0x61, 0x74, 0x22, 0xca, 0x01, 0x0a, 0x07, 0x46, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x72, + 0x65, 0x64, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x18, 0x04, + 0x20, 0x03, 0x28, 0x09, 0x52, 0x08, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x12, 0x23, + 0x0a, 0x0d, 0x73, 0x6b, 0x69, 0x70, 0x5f, 0x62, 0x69, 0x6e, 0x61, 0x72, 0x69, 0x65, 0x73, 0x18, + 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x73, 0x6b, 0x69, 0x70, 0x42, 0x69, 0x6e, 0x61, 0x72, + 0x69, 0x65, 0x73, 0x12, 0x23, 0x0a, 0x0d, 0x73, 0x6b, 0x69, 0x70, 0x5f, 0x61, 0x72, 0x63, 0x68, + 0x69, 0x76, 0x65, 0x73, 0x18, 0x06, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x73, 0x6b, 0x69, 0x70, + 0x41, 0x72, 0x63, 0x68, 0x69, 0x76, 0x65, 0x73, 0x42, 0x0c, 0x0a, 0x0a, 0x63, 0x72, 0x65, 0x64, + 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x22, 0xa8, 0x02, 0x0a, 0x07, 0x4a, 0x65, 0x6e, 0x6b, 0x69, + 0x6e, 0x73, 0x12, 0x24, 0x0a, 0x08, 0x65, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x72, 0x03, 0x90, 0x01, 0x01, 0x52, 0x08, + 0x65, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x37, 0x0a, 0x0a, 0x62, 0x61, 0x73, 0x69, + 0x63, 0x5f, 0x61, 0x75, 0x74, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x63, + 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x73, 0x2e, 0x42, 0x61, 0x73, 0x69, 0x63, + 0x41, 0x75, 0x74, 0x68, 0x48, 0x00, 0x52, 0x09, 0x62, 0x61, 0x73, 0x69, 0x63, 0x41, 0x75, 0x74, + 0x68, 0x12, 0x2d, 0x0a, 0x06, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x13, 0x2e, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x73, 0x2e, + 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x48, 0x00, 0x52, 0x06, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x12, 0x48, 0x0a, 0x0f, 0x75, 0x6e, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, - 0x74, 0x65, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x63, 0x72, 0x65, 0x64, + 0x74, 0x65, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x73, 0x2e, 0x55, 0x6e, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x64, 0x48, 0x00, 0x52, 0x0f, 0x75, 0x6e, 0x61, 0x75, 0x74, - 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x64, 0x6f, - 0x6d, 0x61, 0x69, 0x6e, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x07, 0x64, 0x6f, 0x6d, - 0x61, 0x69, 0x6e, 0x73, 0x12, 0x1b, 0x0a, 0x09, 0x6d, 0x61, 0x78, 0x5f, 0x64, 0x65, 0x70, 0x74, - 0x68, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x08, 0x6d, 0x61, 0x78, 0x44, 0x65, 0x70, 0x74, - 0x68, 0x12, 0x30, 0x0a, 0x05, 0x73, 0x69, 0x6e, 0x63, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, - 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x05, 0x73, 0x69, - 0x6e, 0x63, 0x65, 0x42, 0x0c, 0x0a, 0x0a, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, - 0x6c, 0x22, 0x51, 0x0a, 0x0d, 0x53, 0x6c, 0x61, 0x63, 0x6b, 0x52, 0x65, 0x61, 0x6c, 0x74, 0x69, - 0x6d, 0x65, 0x12, 0x32, 0x0a, 0x06, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x73, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x73, - 0x2e, 0x53, 0x6c, 0x61, 0x63, 0x6b, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x73, 0x48, 0x00, 0x52, 0x06, - 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x73, 0x42, 0x0c, 0x0a, 0x0a, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, - 0x74, 0x69, 0x61, 0x6c, 0x22, 0x62, 0x0a, 0x0a, 0x53, 0x68, 0x61, 0x72, 0x65, 0x70, 0x6f, 0x69, - 0x6e, 0x74, 0x12, 0x2b, 0x0a, 0x05, 0x6f, 0x61, 0x75, 0x74, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x13, 0x2e, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x73, 0x2e, - 0x4f, 0x61, 0x75, 0x74, 0x68, 0x32, 0x48, 0x00, 0x52, 0x05, 0x6f, 0x61, 0x75, 0x74, 0x68, 0x12, - 0x19, 0x0a, 0x08, 0x73, 0x69, 0x74, 0x65, 0x5f, 0x75, 0x72, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x07, 0x73, 0x69, 0x74, 0x65, 0x55, 0x72, 0x6c, 0x42, 0x0c, 0x0a, 0x0a, 0x63, 0x72, - 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x22, 0xf6, 0x03, 0x0a, 0x0a, 0x41, 0x7a, 0x75, - 0x72, 0x65, 0x52, 0x65, 0x70, 0x6f, 0x73, 0x12, 0x24, 0x0a, 0x08, 0x65, 0x6e, 0x64, 0x70, 0x6f, - 0x69, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x72, 0x03, - 0x90, 0x01, 0x01, 0x52, 0x08, 0x65, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x16, 0x0a, - 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x05, - 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x2b, 0x0a, 0x05, 0x6f, 0x61, 0x75, 0x74, 0x68, 0x18, 0x03, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, - 0x6c, 0x73, 0x2e, 0x4f, 0x61, 0x75, 0x74, 0x68, 0x32, 0x48, 0x00, 0x52, 0x05, 0x6f, 0x61, 0x75, - 0x74, 0x68, 0x12, 0x22, 0x0a, 0x0c, 0x72, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x6f, 0x72, 0x69, - 0x65, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0c, 0x72, 0x65, 0x70, 0x6f, 0x73, 0x69, - 0x74, 0x6f, 0x72, 0x69, 0x65, 0x73, 0x12, 0x24, 0x0a, 0x0d, 0x6f, 0x72, 0x67, 0x61, 0x6e, 0x69, - 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0d, 0x6f, - 0x72, 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x1a, 0x0a, 0x08, - 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x18, 0x06, 0x20, 0x03, 0x28, 0x09, 0x52, 0x08, - 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x12, 0x23, 0x0a, 0x0d, 0x69, 0x6e, 0x63, 0x6c, - 0x75, 0x64, 0x65, 0x5f, 0x66, 0x6f, 0x72, 0x6b, 0x73, 0x18, 0x07, 0x20, 0x01, 0x28, 0x08, 0x52, - 0x0c, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x46, 0x6f, 0x72, 0x6b, 0x73, 0x12, 0x21, 0x0a, - 0x0c, 0x69, 0x67, 0x6e, 0x6f, 0x72, 0x65, 0x5f, 0x72, 0x65, 0x70, 0x6f, 0x73, 0x18, 0x08, 0x20, - 0x03, 0x28, 0x09, 0x52, 0x0b, 0x69, 0x67, 0x6e, 0x6f, 0x72, 0x65, 0x52, 0x65, 0x70, 0x6f, 0x73, - 0x12, 0x23, 0x0a, 0x0d, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x5f, 0x72, 0x65, 0x70, 0x6f, - 0x73, 0x18, 0x09, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0c, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, - 0x52, 0x65, 0x70, 0x6f, 0x73, 0x12, 0x29, 0x0a, 0x10, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, - 0x5f, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x18, 0x0a, 0x20, 0x03, 0x28, 0x09, 0x52, - 0x0f, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x73, - 0x12, 0x27, 0x0a, 0x0f, 0x69, 0x67, 0x6e, 0x6f, 0x72, 0x65, 0x5f, 0x70, 0x72, 0x6f, 0x6a, 0x65, - 0x63, 0x74, 0x73, 0x18, 0x0b, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0e, 0x69, 0x67, 0x6e, 0x6f, 0x72, - 0x65, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x12, 0x23, 0x0a, 0x0d, 0x73, 0x6b, 0x69, - 0x70, 0x5f, 0x62, 0x69, 0x6e, 0x61, 0x72, 0x69, 0x65, 0x73, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x08, - 0x52, 0x0c, 0x73, 0x6b, 0x69, 0x70, 0x42, 0x69, 0x6e, 0x61, 0x72, 0x69, 0x65, 0x73, 0x12, 0x23, - 0x0a, 0x0d, 0x73, 0x6b, 0x69, 0x70, 0x5f, 0x61, 0x72, 0x63, 0x68, 0x69, 0x76, 0x65, 0x73, 0x18, - 0x0d, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x73, 0x6b, 0x69, 0x70, 0x41, 0x72, 0x63, 0x68, 0x69, - 0x76, 0x65, 0x73, 0x42, 0x0c, 0x0a, 0x0a, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, - 0x6c, 0x22, 0xd5, 0x04, 0x0a, 0x07, 0x50, 0x6f, 0x73, 0x74, 0x6d, 0x61, 0x6e, 0x12, 0x48, 0x0a, - 0x0f, 0x75, 0x6e, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x64, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, - 0x69, 0x61, 0x6c, 0x73, 0x2e, 0x55, 0x6e, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, - 0x61, 0x74, 0x65, 0x64, 0x48, 0x00, 0x52, 0x0f, 0x75, 0x6e, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, - 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x64, 0x12, 0x16, 0x0a, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x12, - 0x1e, 0x0a, 0x0a, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x73, 0x18, 0x03, 0x20, - 0x03, 0x28, 0x09, 0x52, 0x0a, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x73, 0x12, - 0x20, 0x0a, 0x0b, 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x04, - 0x20, 0x03, 0x28, 0x09, 0x52, 0x0b, 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, - 0x73, 0x12, 0x22, 0x0a, 0x0c, 0x65, 0x6e, 0x76, 0x69, 0x72, 0x6f, 0x6e, 0x6d, 0x65, 0x6e, 0x74, - 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0c, 0x65, 0x6e, 0x76, 0x69, 0x72, 0x6f, 0x6e, - 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x2f, 0x0a, 0x13, 0x65, 0x78, 0x63, 0x6c, 0x75, 0x64, 0x65, - 0x5f, 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x06, 0x20, 0x03, - 0x28, 0x09, 0x52, 0x12, 0x65, 0x78, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x43, 0x6f, 0x6c, 0x6c, 0x65, - 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x31, 0x0a, 0x14, 0x65, 0x78, 0x63, 0x6c, 0x75, 0x64, - 0x65, 0x5f, 0x65, 0x6e, 0x76, 0x69, 0x72, 0x6f, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x18, 0x07, - 0x20, 0x03, 0x28, 0x09, 0x52, 0x13, 0x65, 0x78, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x45, 0x6e, 0x76, - 0x69, 0x72, 0x6f, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x2f, 0x0a, 0x13, 0x69, 0x6e, 0x63, - 0x6c, 0x75, 0x64, 0x65, 0x5f, 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, - 0x18, 0x08, 0x20, 0x03, 0x28, 0x09, 0x52, 0x12, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x43, - 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x31, 0x0a, 0x14, 0x69, 0x6e, - 0x63, 0x6c, 0x75, 0x64, 0x65, 0x5f, 0x65, 0x6e, 0x76, 0x69, 0x72, 0x6f, 0x6e, 0x6d, 0x65, 0x6e, - 0x74, 0x73, 0x18, 0x09, 0x20, 0x03, 0x28, 0x09, 0x52, 0x13, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, - 0x65, 0x45, 0x6e, 0x76, 0x69, 0x72, 0x6f, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x2b, 0x0a, - 0x11, 0x64, 0x65, 0x74, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x5f, 0x6b, 0x65, 0x79, 0x77, 0x6f, 0x72, - 0x64, 0x73, 0x18, 0x0a, 0x20, 0x03, 0x28, 0x09, 0x52, 0x10, 0x64, 0x65, 0x74, 0x65, 0x63, 0x74, - 0x6f, 0x72, 0x4b, 0x65, 0x79, 0x77, 0x6f, 0x72, 0x64, 0x73, 0x12, 0x27, 0x0a, 0x0f, 0x77, 0x6f, - 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x73, 0x18, 0x0b, 0x20, - 0x03, 0x28, 0x09, 0x52, 0x0e, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x50, 0x61, - 0x74, 0x68, 0x73, 0x12, 0x29, 0x0a, 0x10, 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, - 0x6e, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x73, 0x18, 0x0c, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0f, 0x63, - 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x50, 0x61, 0x74, 0x68, 0x73, 0x12, 0x2b, - 0x0a, 0x11, 0x65, 0x6e, 0x76, 0x69, 0x72, 0x6f, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x70, 0x61, - 0x74, 0x68, 0x73, 0x18, 0x0d, 0x20, 0x03, 0x28, 0x09, 0x52, 0x10, 0x65, 0x6e, 0x76, 0x69, 0x72, - 0x6f, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x50, 0x61, 0x74, 0x68, 0x73, 0x42, 0x0c, 0x0a, 0x0a, 0x63, - 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x22, 0x76, 0x0a, 0x07, 0x57, 0x65, 0x62, - 0x68, 0x6f, 0x6f, 0x6b, 0x12, 0x2e, 0x0a, 0x0e, 0x6c, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x5f, 0x61, - 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x07, 0xfa, 0x42, - 0x04, 0x72, 0x02, 0x68, 0x01, 0x52, 0x0d, 0x6c, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x41, 0x64, 0x64, - 0x72, 0x65, 0x73, 0x73, 0x12, 0x2d, 0x0a, 0x06, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, - 0x6c, 0x73, 0x2e, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x48, 0x00, 0x52, 0x06, 0x68, 0x65, 0x61, - 0x64, 0x65, 0x72, 0x42, 0x0c, 0x0a, 0x0a, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, - 0x6c, 0x22, 0xcd, 0x02, 0x0a, 0x0d, 0x45, 0x6c, 0x61, 0x73, 0x74, 0x69, 0x63, 0x73, 0x65, 0x61, - 0x72, 0x63, 0x68, 0x12, 0x14, 0x0a, 0x05, 0x6e, 0x6f, 0x64, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, - 0x28, 0x09, 0x52, 0x05, 0x6e, 0x6f, 0x64, 0x65, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x75, 0x73, 0x65, - 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x75, 0x73, 0x65, - 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, - 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, - 0x64, 0x12, 0x19, 0x0a, 0x08, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x5f, 0x69, 0x64, 0x18, 0x04, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x07, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x49, 0x64, 0x12, 0x17, 0x0a, 0x07, - 0x61, 0x70, 0x69, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x61, - 0x70, 0x69, 0x4b, 0x65, 0x79, 0x12, 0x23, 0x0a, 0x0d, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, - 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x73, 0x65, - 0x72, 0x76, 0x69, 0x63, 0x65, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x23, 0x0a, 0x0d, 0x69, 0x6e, - 0x64, 0x65, 0x78, 0x5f, 0x70, 0x61, 0x74, 0x74, 0x65, 0x72, 0x6e, 0x18, 0x07, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x0c, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x50, 0x61, 0x74, 0x74, 0x65, 0x72, 0x6e, 0x12, - 0x1d, 0x0a, 0x0a, 0x71, 0x75, 0x65, 0x72, 0x79, 0x5f, 0x6a, 0x73, 0x6f, 0x6e, 0x18, 0x08, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x09, 0x71, 0x75, 0x65, 0x72, 0x79, 0x4a, 0x73, 0x6f, 0x6e, 0x12, 0x27, - 0x0a, 0x0f, 0x73, 0x69, 0x6e, 0x63, 0x65, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, - 0x70, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x73, 0x69, 0x6e, 0x63, 0x65, 0x54, 0x69, - 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x28, 0x0a, 0x10, 0x62, 0x65, 0x73, 0x74, 0x5f, - 0x65, 0x66, 0x66, 0x6f, 0x72, 0x74, 0x5f, 0x73, 0x63, 0x61, 0x6e, 0x18, 0x0a, 0x20, 0x01, 0x28, - 0x08, 0x52, 0x0e, 0x62, 0x65, 0x73, 0x74, 0x45, 0x66, 0x66, 0x6f, 0x72, 0x74, 0x53, 0x63, 0x61, - 0x6e, 0x22, 0xde, 0x01, 0x0a, 0x06, 0x53, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x1a, 0x0a, 0x08, - 0x65, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, - 0x65, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x1f, 0x0a, 0x0a, 0x61, 0x75, 0x74, 0x68, - 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x09, - 0x61, 0x75, 0x74, 0x68, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x19, 0x0a, 0x07, 0x64, 0x73, 0x6e, - 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x06, 0x64, 0x73, - 0x6e, 0x4b, 0x65, 0x79, 0x12, 0x19, 0x0a, 0x07, 0x61, 0x70, 0x69, 0x5f, 0x6b, 0x65, 0x79, 0x18, - 0x04, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x06, 0x61, 0x70, 0x69, 0x4b, 0x65, 0x79, 0x12, - 0x37, 0x0a, 0x18, 0x69, 0x6e, 0x73, 0x65, 0x63, 0x75, 0x72, 0x65, 0x5f, 0x73, 0x6b, 0x69, 0x70, - 0x5f, 0x76, 0x65, 0x72, 0x69, 0x66, 0x79, 0x5f, 0x74, 0x6c, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, - 0x08, 0x52, 0x15, 0x69, 0x6e, 0x73, 0x65, 0x63, 0x75, 0x72, 0x65, 0x53, 0x6b, 0x69, 0x70, 0x56, - 0x65, 0x72, 0x69, 0x66, 0x79, 0x54, 0x6c, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x72, 0x6f, 0x6a, - 0x65, 0x63, 0x74, 0x73, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x72, 0x6f, 0x6a, - 0x65, 0x63, 0x74, 0x73, 0x42, 0x0c, 0x0a, 0x0a, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, - 0x61, 0x6c, 0x2a, 0xc9, 0x08, 0x0a, 0x0a, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x54, 0x79, 0x70, - 0x65, 0x12, 0x1d, 0x0a, 0x19, 0x53, 0x4f, 0x55, 0x52, 0x43, 0x45, 0x5f, 0x54, 0x59, 0x50, 0x45, - 0x5f, 0x41, 0x5a, 0x55, 0x52, 0x45, 0x5f, 0x53, 0x54, 0x4f, 0x52, 0x41, 0x47, 0x45, 0x10, 0x00, - 0x12, 0x19, 0x0a, 0x15, 0x53, 0x4f, 0x55, 0x52, 0x43, 0x45, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, - 0x42, 0x49, 0x54, 0x42, 0x55, 0x43, 0x4b, 0x45, 0x54, 0x10, 0x01, 0x12, 0x18, 0x0a, 0x14, 0x53, - 0x4f, 0x55, 0x52, 0x43, 0x45, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x43, 0x49, 0x52, 0x43, 0x4c, - 0x45, 0x43, 0x49, 0x10, 0x02, 0x12, 0x1a, 0x0a, 0x16, 0x53, 0x4f, 0x55, 0x52, 0x43, 0x45, 0x5f, - 0x54, 0x59, 0x50, 0x45, 0x5f, 0x43, 0x4f, 0x4e, 0x46, 0x4c, 0x55, 0x45, 0x4e, 0x43, 0x45, 0x10, - 0x03, 0x12, 0x16, 0x0a, 0x12, 0x53, 0x4f, 0x55, 0x52, 0x43, 0x45, 0x5f, 0x54, 0x59, 0x50, 0x45, - 0x5f, 0x44, 0x4f, 0x43, 0x4b, 0x45, 0x52, 0x10, 0x04, 0x12, 0x13, 0x0a, 0x0f, 0x53, 0x4f, 0x55, - 0x52, 0x43, 0x45, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x45, 0x43, 0x52, 0x10, 0x05, 0x12, 0x13, - 0x0a, 0x0f, 0x53, 0x4f, 0x55, 0x52, 0x43, 0x45, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x47, 0x43, - 0x53, 0x10, 0x06, 0x12, 0x16, 0x0a, 0x12, 0x53, 0x4f, 0x55, 0x52, 0x43, 0x45, 0x5f, 0x54, 0x59, - 0x50, 0x45, 0x5f, 0x47, 0x49, 0x54, 0x48, 0x55, 0x42, 0x10, 0x07, 0x12, 0x1a, 0x0a, 0x16, 0x53, - 0x4f, 0x55, 0x52, 0x43, 0x45, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x50, 0x55, 0x42, 0x4c, 0x49, - 0x43, 0x5f, 0x47, 0x49, 0x54, 0x10, 0x08, 0x12, 0x16, 0x0a, 0x12, 0x53, 0x4f, 0x55, 0x52, 0x43, - 0x45, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x47, 0x49, 0x54, 0x4c, 0x41, 0x42, 0x10, 0x09, 0x12, - 0x14, 0x0a, 0x10, 0x53, 0x4f, 0x55, 0x52, 0x43, 0x45, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x4a, - 0x49, 0x52, 0x41, 0x10, 0x0a, 0x12, 0x24, 0x0a, 0x20, 0x53, 0x4f, 0x55, 0x52, 0x43, 0x45, 0x5f, - 0x54, 0x59, 0x50, 0x45, 0x5f, 0x4e, 0x50, 0x4d, 0x5f, 0x55, 0x4e, 0x41, 0x55, 0x54, 0x48, 0x44, - 0x5f, 0x50, 0x41, 0x43, 0x4b, 0x41, 0x47, 0x45, 0x53, 0x10, 0x0b, 0x12, 0x25, 0x0a, 0x21, 0x53, - 0x4f, 0x55, 0x52, 0x43, 0x45, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x50, 0x59, 0x50, 0x49, 0x5f, - 0x55, 0x4e, 0x41, 0x55, 0x54, 0x48, 0x44, 0x5f, 0x50, 0x41, 0x43, 0x4b, 0x41, 0x47, 0x45, 0x53, - 0x10, 0x0c, 0x12, 0x12, 0x0a, 0x0e, 0x53, 0x4f, 0x55, 0x52, 0x43, 0x45, 0x5f, 0x54, 0x59, 0x50, - 0x45, 0x5f, 0x53, 0x33, 0x10, 0x0d, 0x12, 0x15, 0x0a, 0x11, 0x53, 0x4f, 0x55, 0x52, 0x43, 0x45, - 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x53, 0x4c, 0x41, 0x43, 0x4b, 0x10, 0x0e, 0x12, 0x1a, 0x0a, - 0x16, 0x53, 0x4f, 0x55, 0x52, 0x43, 0x45, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x46, 0x49, 0x4c, - 0x45, 0x53, 0x59, 0x53, 0x54, 0x45, 0x4d, 0x10, 0x0f, 0x12, 0x13, 0x0a, 0x0f, 0x53, 0x4f, 0x55, - 0x52, 0x43, 0x45, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x47, 0x49, 0x54, 0x10, 0x10, 0x12, 0x14, - 0x0a, 0x10, 0x53, 0x4f, 0x55, 0x52, 0x43, 0x45, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x54, 0x45, - 0x53, 0x54, 0x10, 0x11, 0x12, 0x1b, 0x0a, 0x17, 0x53, 0x4f, 0x55, 0x52, 0x43, 0x45, 0x5f, 0x54, - 0x59, 0x50, 0x45, 0x5f, 0x53, 0x33, 0x5f, 0x55, 0x4e, 0x41, 0x55, 0x54, 0x48, 0x45, 0x44, 0x10, - 0x12, 0x12, 0x2a, 0x0a, 0x26, 0x53, 0x4f, 0x55, 0x52, 0x43, 0x45, 0x5f, 0x54, 0x59, 0x50, 0x45, - 0x5f, 0x47, 0x49, 0x54, 0x48, 0x55, 0x42, 0x5f, 0x55, 0x4e, 0x41, 0x55, 0x54, 0x48, 0x45, 0x4e, - 0x54, 0x49, 0x43, 0x41, 0x54, 0x45, 0x44, 0x5f, 0x4f, 0x52, 0x47, 0x10, 0x13, 0x12, 0x19, 0x0a, - 0x15, 0x53, 0x4f, 0x55, 0x52, 0x43, 0x45, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x42, 0x55, 0x49, - 0x4c, 0x44, 0x4b, 0x49, 0x54, 0x45, 0x10, 0x14, 0x12, 0x16, 0x0a, 0x12, 0x53, 0x4f, 0x55, 0x52, - 0x43, 0x45, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x47, 0x45, 0x52, 0x52, 0x49, 0x54, 0x10, 0x15, - 0x12, 0x17, 0x0a, 0x13, 0x53, 0x4f, 0x55, 0x52, 0x43, 0x45, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, - 0x4a, 0x45, 0x4e, 0x4b, 0x49, 0x4e, 0x53, 0x10, 0x16, 0x12, 0x15, 0x0a, 0x11, 0x53, 0x4f, 0x55, - 0x52, 0x43, 0x45, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x54, 0x45, 0x41, 0x4d, 0x53, 0x10, 0x17, - 0x12, 0x21, 0x0a, 0x1d, 0x53, 0x4f, 0x55, 0x52, 0x43, 0x45, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, - 0x4a, 0x46, 0x52, 0x4f, 0x47, 0x5f, 0x41, 0x52, 0x54, 0x49, 0x46, 0x41, 0x43, 0x54, 0x4f, 0x52, - 0x59, 0x10, 0x18, 0x12, 0x16, 0x0a, 0x12, 0x53, 0x4f, 0x55, 0x52, 0x43, 0x45, 0x5f, 0x54, 0x59, - 0x50, 0x45, 0x5f, 0x53, 0x59, 0x53, 0x4c, 0x4f, 0x47, 0x10, 0x19, 0x12, 0x27, 0x0a, 0x23, 0x53, - 0x4f, 0x55, 0x52, 0x43, 0x45, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x50, 0x55, 0x42, 0x4c, 0x49, - 0x43, 0x5f, 0x45, 0x56, 0x45, 0x4e, 0x54, 0x5f, 0x4d, 0x4f, 0x4e, 0x49, 0x54, 0x4f, 0x52, 0x49, - 0x4e, 0x47, 0x10, 0x1a, 0x12, 0x1e, 0x0a, 0x1a, 0x53, 0x4f, 0x55, 0x52, 0x43, 0x45, 0x5f, 0x54, - 0x59, 0x50, 0x45, 0x5f, 0x53, 0x4c, 0x41, 0x43, 0x4b, 0x5f, 0x52, 0x45, 0x41, 0x4c, 0x54, 0x49, - 0x4d, 0x45, 0x10, 0x1b, 0x12, 0x1c, 0x0a, 0x18, 0x53, 0x4f, 0x55, 0x52, 0x43, 0x45, 0x5f, 0x54, - 0x59, 0x50, 0x45, 0x5f, 0x47, 0x4f, 0x4f, 0x47, 0x4c, 0x45, 0x5f, 0x44, 0x52, 0x49, 0x56, 0x45, - 0x10, 0x1c, 0x12, 0x1a, 0x0a, 0x16, 0x53, 0x4f, 0x55, 0x52, 0x43, 0x45, 0x5f, 0x54, 0x59, 0x50, - 0x45, 0x5f, 0x53, 0x48, 0x41, 0x52, 0x45, 0x50, 0x4f, 0x49, 0x4e, 0x54, 0x10, 0x1d, 0x12, 0x1c, - 0x0a, 0x18, 0x53, 0x4f, 0x55, 0x52, 0x43, 0x45, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x47, 0x43, - 0x53, 0x5f, 0x55, 0x4e, 0x41, 0x55, 0x54, 0x48, 0x45, 0x44, 0x10, 0x1e, 0x12, 0x1b, 0x0a, 0x17, - 0x53, 0x4f, 0x55, 0x52, 0x43, 0x45, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x41, 0x5a, 0x55, 0x52, - 0x45, 0x5f, 0x52, 0x45, 0x50, 0x4f, 0x53, 0x10, 0x1f, 0x12, 0x18, 0x0a, 0x14, 0x53, 0x4f, 0x55, - 0x52, 0x43, 0x45, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x54, 0x52, 0x41, 0x56, 0x49, 0x53, 0x43, - 0x49, 0x10, 0x20, 0x12, 0x17, 0x0a, 0x13, 0x53, 0x4f, 0x55, 0x52, 0x43, 0x45, 0x5f, 0x54, 0x59, - 0x50, 0x45, 0x5f, 0x50, 0x4f, 0x53, 0x54, 0x4d, 0x41, 0x4e, 0x10, 0x21, 0x12, 0x17, 0x0a, 0x13, - 0x53, 0x4f, 0x55, 0x52, 0x43, 0x45, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x57, 0x45, 0x42, 0x48, - 0x4f, 0x4f, 0x4b, 0x10, 0x22, 0x12, 0x1d, 0x0a, 0x19, 0x53, 0x4f, 0x55, 0x52, 0x43, 0x45, 0x5f, - 0x54, 0x59, 0x50, 0x45, 0x5f, 0x45, 0x4c, 0x41, 0x53, 0x54, 0x49, 0x43, 0x53, 0x45, 0x41, 0x52, - 0x43, 0x48, 0x10, 0x23, 0x12, 0x1b, 0x0a, 0x17, 0x53, 0x4f, 0x55, 0x52, 0x43, 0x45, 0x5f, 0x54, - 0x59, 0x50, 0x45, 0x5f, 0x48, 0x55, 0x47, 0x47, 0x49, 0x4e, 0x47, 0x46, 0x41, 0x43, 0x45, 0x10, - 0x24, 0x12, 0x23, 0x0a, 0x1f, 0x53, 0x4f, 0x55, 0x52, 0x43, 0x45, 0x5f, 0x54, 0x59, 0x50, 0x45, - 0x5f, 0x47, 0x49, 0x54, 0x48, 0x55, 0x42, 0x5f, 0x45, 0x58, 0x50, 0x45, 0x52, 0x49, 0x4d, 0x45, - 0x4e, 0x54, 0x41, 0x4c, 0x10, 0x25, 0x12, 0x16, 0x0a, 0x12, 0x53, 0x4f, 0x55, 0x52, 0x43, 0x45, - 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x53, 0x45, 0x4e, 0x54, 0x52, 0x59, 0x10, 0x26, 0x42, 0x3b, - 0x5a, 0x39, 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, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x70, 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x33, + 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x64, 0x12, 0x37, 0x0a, 0x18, 0x69, 0x6e, + 0x73, 0x65, 0x63, 0x75, 0x72, 0x65, 0x5f, 0x73, 0x6b, 0x69, 0x70, 0x5f, 0x76, 0x65, 0x72, 0x69, + 0x66, 0x79, 0x5f, 0x74, 0x6c, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x15, 0x69, 0x6e, + 0x73, 0x65, 0x63, 0x75, 0x72, 0x65, 0x53, 0x6b, 0x69, 0x70, 0x56, 0x65, 0x72, 0x69, 0x66, 0x79, + 0x54, 0x6c, 0x73, 0x42, 0x0c, 0x0a, 0x0a, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, + 0x6c, 0x22, 0xa0, 0x02, 0x0a, 0x05, 0x54, 0x65, 0x61, 0x6d, 0x73, 0x12, 0x24, 0x0a, 0x08, 0x65, + 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x08, 0xfa, + 0x42, 0x05, 0x72, 0x03, 0x90, 0x01, 0x01, 0x52, 0x08, 0x65, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, + 0x74, 0x12, 0x16, 0x0a, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, + 0x48, 0x00, 0x52, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x46, 0x0a, 0x0d, 0x61, 0x75, 0x74, + 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x1e, 0x2e, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x73, 0x2e, 0x43, + 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x73, + 0x48, 0x00, 0x52, 0x0d, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, + 0x64, 0x12, 0x2b, 0x0a, 0x05, 0x6f, 0x61, 0x75, 0x74, 0x68, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x13, 0x2e, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x73, 0x2e, 0x4f, + 0x61, 0x75, 0x74, 0x68, 0x32, 0x48, 0x00, 0x52, 0x05, 0x6f, 0x61, 0x75, 0x74, 0x68, 0x12, 0x1a, + 0x0a, 0x08, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x09, + 0x52, 0x08, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x73, 0x12, 0x1f, 0x0a, 0x0b, 0x69, 0x67, + 0x6e, 0x6f, 0x72, 0x65, 0x5f, 0x6c, 0x69, 0x73, 0x74, 0x18, 0x05, 0x20, 0x03, 0x28, 0x09, 0x52, + 0x0a, 0x69, 0x67, 0x6e, 0x6f, 0x72, 0x65, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x19, 0x0a, 0x08, 0x74, + 0x65, 0x61, 0x6d, 0x5f, 0x69, 0x64, 0x73, 0x18, 0x06, 0x20, 0x03, 0x28, 0x09, 0x52, 0x07, 0x74, + 0x65, 0x61, 0x6d, 0x49, 0x64, 0x73, 0x42, 0x0c, 0x0a, 0x0a, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, + 0x74, 0x69, 0x61, 0x6c, 0x22, 0x95, 0x01, 0x0a, 0x06, 0x53, 0x79, 0x73, 0x6c, 0x6f, 0x67, 0x12, + 0x1a, 0x0a, 0x08, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x08, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x12, 0x25, 0x0a, 0x0e, 0x6c, + 0x69, 0x73, 0x74, 0x65, 0x6e, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x0d, 0x6c, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x41, 0x64, 0x64, 0x72, 0x65, + 0x73, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x74, 0x6c, 0x73, 0x43, 0x65, 0x72, 0x74, 0x18, 0x03, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x07, 0x74, 0x6c, 0x73, 0x43, 0x65, 0x72, 0x74, 0x12, 0x16, 0x0a, 0x06, + 0x74, 0x6c, 0x73, 0x4b, 0x65, 0x79, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x74, 0x6c, + 0x73, 0x4b, 0x65, 0x79, 0x12, 0x16, 0x0a, 0x06, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x18, 0x05, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x22, 0xca, 0x01, 0x0a, + 0x07, 0x46, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x72, 0x12, 0x48, 0x0a, 0x0f, 0x75, 0x6e, 0x61, 0x75, + 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x1c, 0x2e, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x73, 0x2e, + 0x55, 0x6e, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x64, 0x48, + 0x00, 0x52, 0x0f, 0x75, 0x6e, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, + 0x65, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x73, 0x18, 0x02, 0x20, + 0x03, 0x28, 0x09, 0x52, 0x07, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x73, 0x12, 0x1b, 0x0a, 0x09, + 0x6d, 0x61, 0x78, 0x5f, 0x64, 0x65, 0x70, 0x74, 0x68, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, + 0x08, 0x6d, 0x61, 0x78, 0x44, 0x65, 0x70, 0x74, 0x68, 0x12, 0x30, 0x0a, 0x05, 0x73, 0x69, 0x6e, + 0x63, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, + 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, + 0x74, 0x61, 0x6d, 0x70, 0x52, 0x05, 0x73, 0x69, 0x6e, 0x63, 0x65, 0x42, 0x0c, 0x0a, 0x0a, 0x63, + 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x22, 0x51, 0x0a, 0x0d, 0x53, 0x6c, 0x61, + 0x63, 0x6b, 0x52, 0x65, 0x61, 0x6c, 0x74, 0x69, 0x6d, 0x65, 0x12, 0x32, 0x0a, 0x06, 0x74, 0x6f, + 0x6b, 0x65, 0x6e, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x63, 0x72, 0x65, + 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x73, 0x2e, 0x53, 0x6c, 0x61, 0x63, 0x6b, 0x54, 0x6f, + 0x6b, 0x65, 0x6e, 0x73, 0x48, 0x00, 0x52, 0x06, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x73, 0x42, 0x0c, + 0x0a, 0x0a, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x22, 0x62, 0x0a, 0x0a, + 0x53, 0x68, 0x61, 0x72, 0x65, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x2b, 0x0a, 0x05, 0x6f, 0x61, + 0x75, 0x74, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x63, 0x72, 0x65, 0x64, + 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x73, 0x2e, 0x4f, 0x61, 0x75, 0x74, 0x68, 0x32, 0x48, 0x00, + 0x52, 0x05, 0x6f, 0x61, 0x75, 0x74, 0x68, 0x12, 0x19, 0x0a, 0x08, 0x73, 0x69, 0x74, 0x65, 0x5f, + 0x75, 0x72, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x73, 0x69, 0x74, 0x65, 0x55, + 0x72, 0x6c, 0x42, 0x0c, 0x0a, 0x0a, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, + 0x22, 0xf6, 0x03, 0x0a, 0x0a, 0x41, 0x7a, 0x75, 0x72, 0x65, 0x52, 0x65, 0x70, 0x6f, 0x73, 0x12, + 0x24, 0x0a, 0x08, 0x65, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x09, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x72, 0x03, 0x90, 0x01, 0x01, 0x52, 0x08, 0x65, 0x6e, 0x64, + 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x16, 0x0a, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x2b, 0x0a, + 0x05, 0x6f, 0x61, 0x75, 0x74, 0x68, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x63, + 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x73, 0x2e, 0x4f, 0x61, 0x75, 0x74, 0x68, + 0x32, 0x48, 0x00, 0x52, 0x05, 0x6f, 0x61, 0x75, 0x74, 0x68, 0x12, 0x22, 0x0a, 0x0c, 0x72, 0x65, + 0x70, 0x6f, 0x73, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x65, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x09, + 0x52, 0x0c, 0x72, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x65, 0x73, 0x12, 0x24, + 0x0a, 0x0d, 0x6f, 0x72, 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, + 0x05, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0d, 0x6f, 0x72, 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x73, + 0x18, 0x06, 0x20, 0x03, 0x28, 0x09, 0x52, 0x08, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x73, + 0x12, 0x23, 0x0a, 0x0d, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x5f, 0x66, 0x6f, 0x72, 0x6b, + 0x73, 0x18, 0x07, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, + 0x46, 0x6f, 0x72, 0x6b, 0x73, 0x12, 0x21, 0x0a, 0x0c, 0x69, 0x67, 0x6e, 0x6f, 0x72, 0x65, 0x5f, + 0x72, 0x65, 0x70, 0x6f, 0x73, 0x18, 0x08, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0b, 0x69, 0x67, 0x6e, + 0x6f, 0x72, 0x65, 0x52, 0x65, 0x70, 0x6f, 0x73, 0x12, 0x23, 0x0a, 0x0d, 0x69, 0x6e, 0x63, 0x6c, + 0x75, 0x64, 0x65, 0x5f, 0x72, 0x65, 0x70, 0x6f, 0x73, 0x18, 0x09, 0x20, 0x03, 0x28, 0x09, 0x52, + 0x0c, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x52, 0x65, 0x70, 0x6f, 0x73, 0x12, 0x29, 0x0a, + 0x10, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x5f, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, + 0x73, 0x18, 0x0a, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0f, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, + 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x12, 0x27, 0x0a, 0x0f, 0x69, 0x67, 0x6e, 0x6f, + 0x72, 0x65, 0x5f, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x18, 0x0b, 0x20, 0x03, 0x28, + 0x09, 0x52, 0x0e, 0x69, 0x67, 0x6e, 0x6f, 0x72, 0x65, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, + 0x73, 0x12, 0x23, 0x0a, 0x0d, 0x73, 0x6b, 0x69, 0x70, 0x5f, 0x62, 0x69, 0x6e, 0x61, 0x72, 0x69, + 0x65, 0x73, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x73, 0x6b, 0x69, 0x70, 0x42, 0x69, + 0x6e, 0x61, 0x72, 0x69, 0x65, 0x73, 0x12, 0x23, 0x0a, 0x0d, 0x73, 0x6b, 0x69, 0x70, 0x5f, 0x61, + 0x72, 0x63, 0x68, 0x69, 0x76, 0x65, 0x73, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x73, + 0x6b, 0x69, 0x70, 0x41, 0x72, 0x63, 0x68, 0x69, 0x76, 0x65, 0x73, 0x42, 0x0c, 0x0a, 0x0a, 0x63, + 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x22, 0xd5, 0x04, 0x0a, 0x07, 0x50, 0x6f, + 0x73, 0x74, 0x6d, 0x61, 0x6e, 0x12, 0x48, 0x0a, 0x0f, 0x75, 0x6e, 0x61, 0x75, 0x74, 0x68, 0x65, + 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, + 0x2e, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x73, 0x2e, 0x55, 0x6e, 0x61, + 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x64, 0x48, 0x00, 0x52, 0x0f, + 0x75, 0x6e, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x64, 0x12, + 0x16, 0x0a, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, + 0x52, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x1e, 0x0a, 0x0a, 0x77, 0x6f, 0x72, 0x6b, 0x73, + 0x70, 0x61, 0x63, 0x65, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0a, 0x77, 0x6f, 0x72, + 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x73, 0x12, 0x20, 0x0a, 0x0b, 0x63, 0x6f, 0x6c, 0x6c, 0x65, + 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0b, 0x63, 0x6f, + 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x22, 0x0a, 0x0c, 0x65, 0x6e, 0x76, + 0x69, 0x72, 0x6f, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x09, 0x52, + 0x0c, 0x65, 0x6e, 0x76, 0x69, 0x72, 0x6f, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x2f, 0x0a, + 0x13, 0x65, 0x78, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x5f, 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, + 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x06, 0x20, 0x03, 0x28, 0x09, 0x52, 0x12, 0x65, 0x78, 0x63, 0x6c, + 0x75, 0x64, 0x65, 0x43, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x31, + 0x0a, 0x14, 0x65, 0x78, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x5f, 0x65, 0x6e, 0x76, 0x69, 0x72, 0x6f, + 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x18, 0x07, 0x20, 0x03, 0x28, 0x09, 0x52, 0x13, 0x65, 0x78, + 0x63, 0x6c, 0x75, 0x64, 0x65, 0x45, 0x6e, 0x76, 0x69, 0x72, 0x6f, 0x6e, 0x6d, 0x65, 0x6e, 0x74, + 0x73, 0x12, 0x2f, 0x0a, 0x13, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x5f, 0x63, 0x6f, 0x6c, + 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x08, 0x20, 0x03, 0x28, 0x09, 0x52, 0x12, + 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x43, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, + 0x6e, 0x73, 0x12, 0x31, 0x0a, 0x14, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x5f, 0x65, 0x6e, + 0x76, 0x69, 0x72, 0x6f, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x18, 0x09, 0x20, 0x03, 0x28, 0x09, + 0x52, 0x13, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x45, 0x6e, 0x76, 0x69, 0x72, 0x6f, 0x6e, + 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x2b, 0x0a, 0x11, 0x64, 0x65, 0x74, 0x65, 0x63, 0x74, 0x6f, + 0x72, 0x5f, 0x6b, 0x65, 0x79, 0x77, 0x6f, 0x72, 0x64, 0x73, 0x18, 0x0a, 0x20, 0x03, 0x28, 0x09, + 0x52, 0x10, 0x64, 0x65, 0x74, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x4b, 0x65, 0x79, 0x77, 0x6f, 0x72, + 0x64, 0x73, 0x12, 0x27, 0x0a, 0x0f, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, + 0x70, 0x61, 0x74, 0x68, 0x73, 0x18, 0x0b, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0e, 0x77, 0x6f, 0x72, + 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x50, 0x61, 0x74, 0x68, 0x73, 0x12, 0x29, 0x0a, 0x10, 0x63, + 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x73, 0x18, + 0x0c, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0f, 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, + 0x6e, 0x50, 0x61, 0x74, 0x68, 0x73, 0x12, 0x2b, 0x0a, 0x11, 0x65, 0x6e, 0x76, 0x69, 0x72, 0x6f, + 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x73, 0x18, 0x0d, 0x20, 0x03, 0x28, + 0x09, 0x52, 0x10, 0x65, 0x6e, 0x76, 0x69, 0x72, 0x6f, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x50, 0x61, + 0x74, 0x68, 0x73, 0x42, 0x0c, 0x0a, 0x0a, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, + 0x6c, 0x22, 0x76, 0x0a, 0x07, 0x57, 0x65, 0x62, 0x68, 0x6f, 0x6f, 0x6b, 0x12, 0x2e, 0x0a, 0x0e, + 0x6c, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x42, 0x07, 0xfa, 0x42, 0x04, 0x72, 0x02, 0x68, 0x01, 0x52, 0x0d, 0x6c, + 0x69, 0x73, 0x74, 0x65, 0x6e, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x2d, 0x0a, 0x06, + 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x63, + 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x73, 0x2e, 0x48, 0x65, 0x61, 0x64, 0x65, + 0x72, 0x48, 0x00, 0x52, 0x06, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x42, 0x0c, 0x0a, 0x0a, 0x63, + 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x22, 0xcd, 0x02, 0x0a, 0x0d, 0x45, 0x6c, + 0x61, 0x73, 0x74, 0x69, 0x63, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x12, 0x14, 0x0a, 0x05, 0x6e, + 0x6f, 0x64, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x05, 0x6e, 0x6f, 0x64, 0x65, + 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x1a, 0x0a, + 0x08, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x08, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x12, 0x19, 0x0a, 0x08, 0x63, 0x6c, 0x6f, + 0x75, 0x64, 0x5f, 0x69, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x63, 0x6c, 0x6f, + 0x75, 0x64, 0x49, 0x64, 0x12, 0x17, 0x0a, 0x07, 0x61, 0x70, 0x69, 0x5f, 0x6b, 0x65, 0x79, 0x18, + 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x61, 0x70, 0x69, 0x4b, 0x65, 0x79, 0x12, 0x23, 0x0a, + 0x0d, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x06, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x54, 0x6f, 0x6b, + 0x65, 0x6e, 0x12, 0x23, 0x0a, 0x0d, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x5f, 0x70, 0x61, 0x74, 0x74, + 0x65, 0x72, 0x6e, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x69, 0x6e, 0x64, 0x65, 0x78, + 0x50, 0x61, 0x74, 0x74, 0x65, 0x72, 0x6e, 0x12, 0x1d, 0x0a, 0x0a, 0x71, 0x75, 0x65, 0x72, 0x79, + 0x5f, 0x6a, 0x73, 0x6f, 0x6e, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x71, 0x75, 0x65, + 0x72, 0x79, 0x4a, 0x73, 0x6f, 0x6e, 0x12, 0x27, 0x0a, 0x0f, 0x73, 0x69, 0x6e, 0x63, 0x65, 0x5f, + 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x0e, 0x73, 0x69, 0x6e, 0x63, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, + 0x28, 0x0a, 0x10, 0x62, 0x65, 0x73, 0x74, 0x5f, 0x65, 0x66, 0x66, 0x6f, 0x72, 0x74, 0x5f, 0x73, + 0x63, 0x61, 0x6e, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0e, 0x62, 0x65, 0x73, 0x74, 0x45, + 0x66, 0x66, 0x6f, 0x72, 0x74, 0x53, 0x63, 0x61, 0x6e, 0x22, 0xde, 0x01, 0x0a, 0x06, 0x53, 0x65, + 0x6e, 0x74, 0x72, 0x79, 0x12, 0x1a, 0x0a, 0x08, 0x65, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x65, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, + 0x12, 0x1f, 0x0a, 0x0a, 0x61, 0x75, 0x74, 0x68, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x09, 0x61, 0x75, 0x74, 0x68, 0x54, 0x6f, 0x6b, 0x65, + 0x6e, 0x12, 0x19, 0x0a, 0x07, 0x64, 0x73, 0x6e, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x03, 0x20, 0x01, + 0x28, 0x09, 0x48, 0x00, 0x52, 0x06, 0x64, 0x73, 0x6e, 0x4b, 0x65, 0x79, 0x12, 0x19, 0x0a, 0x07, + 0x61, 0x70, 0x69, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, + 0x06, 0x61, 0x70, 0x69, 0x4b, 0x65, 0x79, 0x12, 0x37, 0x0a, 0x18, 0x69, 0x6e, 0x73, 0x65, 0x63, + 0x75, 0x72, 0x65, 0x5f, 0x73, 0x6b, 0x69, 0x70, 0x5f, 0x76, 0x65, 0x72, 0x69, 0x66, 0x79, 0x5f, + 0x74, 0x6c, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x15, 0x69, 0x6e, 0x73, 0x65, 0x63, + 0x75, 0x72, 0x65, 0x53, 0x6b, 0x69, 0x70, 0x56, 0x65, 0x72, 0x69, 0x66, 0x79, 0x54, 0x6c, 0x73, + 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x18, 0x06, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x08, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x42, 0x0c, 0x0a, 0x0a, + 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x2a, 0xc9, 0x08, 0x0a, 0x0a, 0x53, + 0x6f, 0x75, 0x72, 0x63, 0x65, 0x54, 0x79, 0x70, 0x65, 0x12, 0x1d, 0x0a, 0x19, 0x53, 0x4f, 0x55, + 0x52, 0x43, 0x45, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x41, 0x5a, 0x55, 0x52, 0x45, 0x5f, 0x53, + 0x54, 0x4f, 0x52, 0x41, 0x47, 0x45, 0x10, 0x00, 0x12, 0x19, 0x0a, 0x15, 0x53, 0x4f, 0x55, 0x52, + 0x43, 0x45, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x42, 0x49, 0x54, 0x42, 0x55, 0x43, 0x4b, 0x45, + 0x54, 0x10, 0x01, 0x12, 0x18, 0x0a, 0x14, 0x53, 0x4f, 0x55, 0x52, 0x43, 0x45, 0x5f, 0x54, 0x59, + 0x50, 0x45, 0x5f, 0x43, 0x49, 0x52, 0x43, 0x4c, 0x45, 0x43, 0x49, 0x10, 0x02, 0x12, 0x1a, 0x0a, + 0x16, 0x53, 0x4f, 0x55, 0x52, 0x43, 0x45, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x43, 0x4f, 0x4e, + 0x46, 0x4c, 0x55, 0x45, 0x4e, 0x43, 0x45, 0x10, 0x03, 0x12, 0x16, 0x0a, 0x12, 0x53, 0x4f, 0x55, + 0x52, 0x43, 0x45, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x44, 0x4f, 0x43, 0x4b, 0x45, 0x52, 0x10, + 0x04, 0x12, 0x13, 0x0a, 0x0f, 0x53, 0x4f, 0x55, 0x52, 0x43, 0x45, 0x5f, 0x54, 0x59, 0x50, 0x45, + 0x5f, 0x45, 0x43, 0x52, 0x10, 0x05, 0x12, 0x13, 0x0a, 0x0f, 0x53, 0x4f, 0x55, 0x52, 0x43, 0x45, + 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x47, 0x43, 0x53, 0x10, 0x06, 0x12, 0x16, 0x0a, 0x12, 0x53, + 0x4f, 0x55, 0x52, 0x43, 0x45, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x47, 0x49, 0x54, 0x48, 0x55, + 0x42, 0x10, 0x07, 0x12, 0x1a, 0x0a, 0x16, 0x53, 0x4f, 0x55, 0x52, 0x43, 0x45, 0x5f, 0x54, 0x59, + 0x50, 0x45, 0x5f, 0x50, 0x55, 0x42, 0x4c, 0x49, 0x43, 0x5f, 0x47, 0x49, 0x54, 0x10, 0x08, 0x12, + 0x16, 0x0a, 0x12, 0x53, 0x4f, 0x55, 0x52, 0x43, 0x45, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x47, + 0x49, 0x54, 0x4c, 0x41, 0x42, 0x10, 0x09, 0x12, 0x14, 0x0a, 0x10, 0x53, 0x4f, 0x55, 0x52, 0x43, + 0x45, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x4a, 0x49, 0x52, 0x41, 0x10, 0x0a, 0x12, 0x24, 0x0a, + 0x20, 0x53, 0x4f, 0x55, 0x52, 0x43, 0x45, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x4e, 0x50, 0x4d, + 0x5f, 0x55, 0x4e, 0x41, 0x55, 0x54, 0x48, 0x44, 0x5f, 0x50, 0x41, 0x43, 0x4b, 0x41, 0x47, 0x45, + 0x53, 0x10, 0x0b, 0x12, 0x25, 0x0a, 0x21, 0x53, 0x4f, 0x55, 0x52, 0x43, 0x45, 0x5f, 0x54, 0x59, + 0x50, 0x45, 0x5f, 0x50, 0x59, 0x50, 0x49, 0x5f, 0x55, 0x4e, 0x41, 0x55, 0x54, 0x48, 0x44, 0x5f, + 0x50, 0x41, 0x43, 0x4b, 0x41, 0x47, 0x45, 0x53, 0x10, 0x0c, 0x12, 0x12, 0x0a, 0x0e, 0x53, 0x4f, + 0x55, 0x52, 0x43, 0x45, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x53, 0x33, 0x10, 0x0d, 0x12, 0x15, + 0x0a, 0x11, 0x53, 0x4f, 0x55, 0x52, 0x43, 0x45, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x53, 0x4c, + 0x41, 0x43, 0x4b, 0x10, 0x0e, 0x12, 0x1a, 0x0a, 0x16, 0x53, 0x4f, 0x55, 0x52, 0x43, 0x45, 0x5f, + 0x54, 0x59, 0x50, 0x45, 0x5f, 0x46, 0x49, 0x4c, 0x45, 0x53, 0x59, 0x53, 0x54, 0x45, 0x4d, 0x10, + 0x0f, 0x12, 0x13, 0x0a, 0x0f, 0x53, 0x4f, 0x55, 0x52, 0x43, 0x45, 0x5f, 0x54, 0x59, 0x50, 0x45, + 0x5f, 0x47, 0x49, 0x54, 0x10, 0x10, 0x12, 0x14, 0x0a, 0x10, 0x53, 0x4f, 0x55, 0x52, 0x43, 0x45, + 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x54, 0x45, 0x53, 0x54, 0x10, 0x11, 0x12, 0x1b, 0x0a, 0x17, + 0x53, 0x4f, 0x55, 0x52, 0x43, 0x45, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x53, 0x33, 0x5f, 0x55, + 0x4e, 0x41, 0x55, 0x54, 0x48, 0x45, 0x44, 0x10, 0x12, 0x12, 0x2a, 0x0a, 0x26, 0x53, 0x4f, 0x55, + 0x52, 0x43, 0x45, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x47, 0x49, 0x54, 0x48, 0x55, 0x42, 0x5f, + 0x55, 0x4e, 0x41, 0x55, 0x54, 0x48, 0x45, 0x4e, 0x54, 0x49, 0x43, 0x41, 0x54, 0x45, 0x44, 0x5f, + 0x4f, 0x52, 0x47, 0x10, 0x13, 0x12, 0x19, 0x0a, 0x15, 0x53, 0x4f, 0x55, 0x52, 0x43, 0x45, 0x5f, + 0x54, 0x59, 0x50, 0x45, 0x5f, 0x42, 0x55, 0x49, 0x4c, 0x44, 0x4b, 0x49, 0x54, 0x45, 0x10, 0x14, + 0x12, 0x16, 0x0a, 0x12, 0x53, 0x4f, 0x55, 0x52, 0x43, 0x45, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, + 0x47, 0x45, 0x52, 0x52, 0x49, 0x54, 0x10, 0x15, 0x12, 0x17, 0x0a, 0x13, 0x53, 0x4f, 0x55, 0x52, + 0x43, 0x45, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x4a, 0x45, 0x4e, 0x4b, 0x49, 0x4e, 0x53, 0x10, + 0x16, 0x12, 0x15, 0x0a, 0x11, 0x53, 0x4f, 0x55, 0x52, 0x43, 0x45, 0x5f, 0x54, 0x59, 0x50, 0x45, + 0x5f, 0x54, 0x45, 0x41, 0x4d, 0x53, 0x10, 0x17, 0x12, 0x21, 0x0a, 0x1d, 0x53, 0x4f, 0x55, 0x52, + 0x43, 0x45, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x4a, 0x46, 0x52, 0x4f, 0x47, 0x5f, 0x41, 0x52, + 0x54, 0x49, 0x46, 0x41, 0x43, 0x54, 0x4f, 0x52, 0x59, 0x10, 0x18, 0x12, 0x16, 0x0a, 0x12, 0x53, + 0x4f, 0x55, 0x52, 0x43, 0x45, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x53, 0x59, 0x53, 0x4c, 0x4f, + 0x47, 0x10, 0x19, 0x12, 0x27, 0x0a, 0x23, 0x53, 0x4f, 0x55, 0x52, 0x43, 0x45, 0x5f, 0x54, 0x59, + 0x50, 0x45, 0x5f, 0x50, 0x55, 0x42, 0x4c, 0x49, 0x43, 0x5f, 0x45, 0x56, 0x45, 0x4e, 0x54, 0x5f, + 0x4d, 0x4f, 0x4e, 0x49, 0x54, 0x4f, 0x52, 0x49, 0x4e, 0x47, 0x10, 0x1a, 0x12, 0x1e, 0x0a, 0x1a, + 0x53, 0x4f, 0x55, 0x52, 0x43, 0x45, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x53, 0x4c, 0x41, 0x43, + 0x4b, 0x5f, 0x52, 0x45, 0x41, 0x4c, 0x54, 0x49, 0x4d, 0x45, 0x10, 0x1b, 0x12, 0x1c, 0x0a, 0x18, + 0x53, 0x4f, 0x55, 0x52, 0x43, 0x45, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x47, 0x4f, 0x4f, 0x47, + 0x4c, 0x45, 0x5f, 0x44, 0x52, 0x49, 0x56, 0x45, 0x10, 0x1c, 0x12, 0x1a, 0x0a, 0x16, 0x53, 0x4f, + 0x55, 0x52, 0x43, 0x45, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x53, 0x48, 0x41, 0x52, 0x45, 0x50, + 0x4f, 0x49, 0x4e, 0x54, 0x10, 0x1d, 0x12, 0x1c, 0x0a, 0x18, 0x53, 0x4f, 0x55, 0x52, 0x43, 0x45, + 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x47, 0x43, 0x53, 0x5f, 0x55, 0x4e, 0x41, 0x55, 0x54, 0x48, + 0x45, 0x44, 0x10, 0x1e, 0x12, 0x1b, 0x0a, 0x17, 0x53, 0x4f, 0x55, 0x52, 0x43, 0x45, 0x5f, 0x54, + 0x59, 0x50, 0x45, 0x5f, 0x41, 0x5a, 0x55, 0x52, 0x45, 0x5f, 0x52, 0x45, 0x50, 0x4f, 0x53, 0x10, + 0x1f, 0x12, 0x18, 0x0a, 0x14, 0x53, 0x4f, 0x55, 0x52, 0x43, 0x45, 0x5f, 0x54, 0x59, 0x50, 0x45, + 0x5f, 0x54, 0x52, 0x41, 0x56, 0x49, 0x53, 0x43, 0x49, 0x10, 0x20, 0x12, 0x17, 0x0a, 0x13, 0x53, + 0x4f, 0x55, 0x52, 0x43, 0x45, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x50, 0x4f, 0x53, 0x54, 0x4d, + 0x41, 0x4e, 0x10, 0x21, 0x12, 0x17, 0x0a, 0x13, 0x53, 0x4f, 0x55, 0x52, 0x43, 0x45, 0x5f, 0x54, + 0x59, 0x50, 0x45, 0x5f, 0x57, 0x45, 0x42, 0x48, 0x4f, 0x4f, 0x4b, 0x10, 0x22, 0x12, 0x1d, 0x0a, + 0x19, 0x53, 0x4f, 0x55, 0x52, 0x43, 0x45, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x45, 0x4c, 0x41, + 0x53, 0x54, 0x49, 0x43, 0x53, 0x45, 0x41, 0x52, 0x43, 0x48, 0x10, 0x23, 0x12, 0x1b, 0x0a, 0x17, + 0x53, 0x4f, 0x55, 0x52, 0x43, 0x45, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x48, 0x55, 0x47, 0x47, + 0x49, 0x4e, 0x47, 0x46, 0x41, 0x43, 0x45, 0x10, 0x24, 0x12, 0x23, 0x0a, 0x1f, 0x53, 0x4f, 0x55, + 0x52, 0x43, 0x45, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x47, 0x49, 0x54, 0x48, 0x55, 0x42, 0x5f, + 0x45, 0x58, 0x50, 0x45, 0x52, 0x49, 0x4d, 0x45, 0x4e, 0x54, 0x41, 0x4c, 0x10, 0x25, 0x12, 0x16, + 0x0a, 0x12, 0x53, 0x4f, 0x55, 0x52, 0x43, 0x45, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x53, 0x45, + 0x4e, 0x54, 0x52, 0x59, 0x10, 0x26, 0x42, 0x3b, 0x5a, 0x39, 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, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, + 0x73, 0x70, 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( diff --git a/pkg/pb/sourcespb/sources.pb.validate.go b/pkg/pb/sourcespb/sources.pb.validate.go index 7f3bb98ce311..08d327aa20eb 100644 --- a/pkg/pb/sourcespb/sources.pb.validate.go +++ b/pkg/pb/sourcespb/sources.pb.validate.go @@ -2542,6 +2542,8 @@ func (m *GitHub) validate(all bool) error { // no validation rules for IncludeWikis + // no validation rules for CommentsTimeframeDays + switch v := m.Credential.(type) { case *GitHub_GithubApp: if v == nil { diff --git a/pkg/sources/github/github.go b/pkg/sources/github/github.go index 8c945834731d..4e2fac186ddd 100644 --- a/pkg/sources/github/github.go +++ b/pkg/sources/github/github.go @@ -66,9 +66,10 @@ type Source struct { resumeInfoSlice []string connector connector - includePRComments bool - includeIssueComments bool - includeGistComments bool + includePRComments bool + includeIssueComments bool + includeGistComments bool + commentsTimeframeDays uint32 sources.Progress sources.CommonSourceUnitUnmarshaller @@ -255,6 +256,7 @@ func (s *Source) Init(aCtx context.Context, name string, jobID sources.JobID, so s.includeIssueComments = s.conn.IncludeIssueComments s.includePRComments = s.conn.IncludePullRequestComments s.includeGistComments = s.conn.IncludeGistComments + s.commentsTimeframeDays = s.conn.CommentsTimeframeDays // Head or base should only be used with incoming webhooks if (len(s.conn.Head) > 0 || len(s.conn.Base) > 0) && len(s.repos) != 1 { @@ -1001,10 +1003,17 @@ func (s *Source) scanComments(ctx context.Context, repoPath string, repoInfo rep return err } + var cutoffTime *time.Time + if s.commentsTimeframeDays > 0 { + daysToFilter := int(s.commentsTimeframeDays) + t := time.Now().AddDate(0, 0, -daysToFilter) + cutoffTime = &t + } + if s.includeGistComments && isGistUrl(urlParts) { - return s.processGistComments(ctx, urlString, urlParts, repoInfo, reporter) + return s.processGistComments(ctx, urlString, urlParts, repoInfo, reporter, cutoffTime) } else if s.includeIssueComments || s.includePRComments { - return s.processRepoComments(ctx, repoInfo, reporter) + return s.processRepoComments(ctx, repoInfo, reporter, cutoffTime) } return nil } @@ -1064,7 +1073,7 @@ func getRepoURLParts(repoURLString string) (string, []string, error) { const initialPage = 1 // page to start listing from -func (s *Source) processGistComments(ctx context.Context, gistURL string, urlParts []string, repoInfo repoInfo, reporter sources.ChunkReporter) error { +func (s *Source) processGistComments(ctx context.Context, gistURL string, urlParts []string, repoInfo repoInfo, reporter sources.ChunkReporter, cutoffTime *time.Time) error { ctx.Logger().V(2).Info("Scanning GitHub Gist comments") // GitHub Gist URL. @@ -1083,7 +1092,7 @@ func (s *Source) processGistComments(ctx context.Context, gistURL string, urlPar return err } - if err = s.chunkGistComments(ctx, gistURL, repoInfo, comments, reporter); err != nil { + if err = s.chunkGistComments(ctx, gistURL, repoInfo, comments, reporter, cutoffTime); err != nil { return err } @@ -1103,8 +1112,13 @@ func isGistUrl(urlParts []string) bool { return strings.EqualFold(urlParts[0], "gist.github.com") || (len(urlParts) == 4 && strings.EqualFold(urlParts[1], "gist")) } -func (s *Source) chunkGistComments(ctx context.Context, gistURL string, gistInfo repoInfo, comments []*github.GistComment, reporter sources.ChunkReporter) error { +func (s *Source) chunkGistComments(ctx context.Context, gistURL string, gistInfo repoInfo, comments []*github.GistComment, reporter sources.ChunkReporter, cutoffTime *time.Time) error { for _, comment := range comments { + // Stop processing comments as soon as one created before the cutoff time is detected, as these are sorted + if cutoffTime != nil && comment.GetCreatedAt().Before(*cutoffTime) { + break + } + // Create chunk and send it to the channel. chunk := sources.Chunk{ SourceName: s.name, @@ -1137,10 +1151,10 @@ func (s *Source) chunkGistComments(ctx context.Context, gistURL string, gistInfo // Note: these can't be consts because the address is needed when using with the GitHub library. var ( // sortType defines the criteria for sorting comments. - // By default, comments are sorted by their creation date. - sortType = "created" + // By setting this to "updated" we can use this to reliably manage the comment timeframe filtering below + sortType = "updated" // directionType defines the direction of sorting. - // "desc" means comments will be sorted in descending order, showing the latest comments first. + // "desc" means comments will be sorted in descending order, showing the latest comments first, which is critical for managing the comment timeframe filtering directionType = "desc" // allComments is a placeholder for specifying the comment ID to start listing from. // A value of 0 means that all comments will be listed. @@ -1149,13 +1163,13 @@ var ( state = "all" ) -func (s *Source) processRepoComments(ctx context.Context, repoInfo repoInfo, reporter sources.ChunkReporter) error { +func (s *Source) processRepoComments(ctx context.Context, repoInfo repoInfo, reporter sources.ChunkReporter, cutoffTime *time.Time) error { if s.includeIssueComments { ctx.Logger().V(2).Info("Scanning issues") if err := s.processIssues(ctx, repoInfo, reporter); err != nil { return err } - if err := s.processIssueComments(ctx, repoInfo, reporter); err != nil { + if err := s.processIssueComments(ctx, repoInfo, reporter, cutoffTime); err != nil { return err } } @@ -1165,7 +1179,7 @@ func (s *Source) processRepoComments(ctx context.Context, repoInfo repoInfo, rep if err := s.processPRs(ctx, repoInfo, reporter); err != nil { return err } - if err := s.processPRComments(ctx, repoInfo, reporter); err != nil { + if err := s.processPRComments(ctx, repoInfo, reporter, cutoffTime); err != nil { return err } } @@ -1210,7 +1224,6 @@ func (s *Source) processIssues(ctx context.Context, repoInfo repoInfo, reporter func (s *Source) chunkIssues(ctx context.Context, repoInfo repoInfo, issues []*github.Issue, reporter sources.ChunkReporter) error { for _, issue := range issues { - // Skip pull requests since covered by processPRs. if issue.IsPullRequest() { continue @@ -1245,7 +1258,7 @@ func (s *Source) chunkIssues(ctx context.Context, repoInfo repoInfo, issues []*g return nil } -func (s *Source) processIssueComments(ctx context.Context, repoInfo repoInfo, reporter sources.ChunkReporter) error { +func (s *Source) processIssueComments(ctx context.Context, repoInfo repoInfo, reporter sources.ChunkReporter, cutoffTime *time.Time) error { issueOpts := &github.IssueListCommentsOptions{ Sort: &sortType, Direction: &directionType, @@ -1264,7 +1277,7 @@ func (s *Source) processIssueComments(ctx context.Context, repoInfo repoInfo, re return err } - if err = s.chunkIssueComments(ctx, repoInfo, issueComments, reporter); err != nil { + if err = s.chunkIssueComments(ctx, repoInfo, issueComments, reporter, cutoffTime); err != nil { return err } @@ -1276,8 +1289,13 @@ func (s *Source) processIssueComments(ctx context.Context, repoInfo repoInfo, re return nil } -func (s *Source) chunkIssueComments(ctx context.Context, repoInfo repoInfo, comments []*github.IssueComment, reporter sources.ChunkReporter) error { +func (s *Source) chunkIssueComments(ctx context.Context, repoInfo repoInfo, comments []*github.IssueComment, reporter sources.ChunkReporter, cutoffTime *time.Time) error { for _, comment := range comments { + // Stop processing comments as soon as one created before the cutoff time is detected, as these are sorted + if cutoffTime != nil && comment.GetUpdatedAt().Before(*cutoffTime) { + continue + } + // Create chunk and send it to the channel. chunk := sources.Chunk{ SourceName: s.name, @@ -1340,7 +1358,7 @@ func (s *Source) processPRs(ctx context.Context, repoInfo repoInfo, reporter sou return nil } -func (s *Source) processPRComments(ctx context.Context, repoInfo repoInfo, reporter sources.ChunkReporter) error { +func (s *Source) processPRComments(ctx context.Context, repoInfo repoInfo, reporter sources.ChunkReporter, cutoffTime *time.Time) error { prOpts := &github.PullRequestListCommentsOptions{ Sort: sortType, Direction: directionType, @@ -1359,7 +1377,7 @@ func (s *Source) processPRComments(ctx context.Context, repoInfo repoInfo, repor return err } - if err = s.chunkPullRequestComments(ctx, repoInfo, prComments, reporter); err != nil { + if err = s.chunkPullRequestComments(ctx, repoInfo, prComments, reporter, cutoffTime); err != nil { return err } @@ -1403,14 +1421,19 @@ func (s *Source) chunkPullRequests(ctx context.Context, repoInfo repoInfo, prs [ return nil } -func (s *Source) chunkPullRequestComments(ctx context.Context, repoInfo repoInfo, comments []*github.PullRequestComment, reporter sources.ChunkReporter) error { +func (s *Source) chunkPullRequestComments(ctx context.Context, repoInfo repoInfo, comments []*github.PullRequestComment, reporter sources.ChunkReporter, cutoffTime *time.Time) error { for _, comment := range comments { + // Stop processing comments as soon as one created before the cutoff time is detected, as these are sorted + if cutoffTime != nil && comment.GetUpdatedAt().Before(*cutoffTime) { + continue + } + // Create chunk and send it to the channel. chunk := sources.Chunk{ SourceName: s.name, SourceID: s.SourceID(), - SourceType: s.Type(), JobID: s.JobID(), + SourceType: s.Type(), SourceMetadata: &source_metadatapb.MetaData{ Data: &source_metadatapb.MetaData_Github{ Github: &source_metadatapb.Github{ diff --git a/pkg/sources/github/github_test.go b/pkg/sources/github/github_test.go index 2965bbf5cb3b..3eda8bdbaad4 100644 --- a/pkg/sources/github/github_test.go +++ b/pkg/sources/github/github_test.go @@ -97,8 +97,9 @@ func TestAddReposByOrg(t *testing.T) { Credential: &sourcespb.GitHub_Token{ Token: "super secret token", }, - Repositories: nil, - IgnoreRepos: []string{"secret/super-*-repo2"}, + Repositories: nil, + IgnoreRepos: []string{"secret/super-*-repo2"}, + CommentsTimeframeDays: 10, }) err := s.getReposByOrg(context.Background(), "super-secret-org", noopReporter()) assert.Nil(t, err) diff --git a/pkg/sources/sources.go b/pkg/sources/sources.go index 39d280b2b0f2..0d6807b80d57 100644 --- a/pkg/sources/sources.go +++ b/pkg/sources/sources.go @@ -236,6 +236,8 @@ type GithubConfig struct { SkipBinaries bool // IncludeWikis indicates whether to include repository wikis in the scan. IncludeWikis bool + // CommentsTimeframeDays indicates how many days of comments to include in the scan. + CommentsTimeframeDays uint32 } // GitHubExperimentalConfig defines the optional configuration for an experimental GitHub source. diff --git a/proto/sources.proto b/proto/sources.proto index 31973d354ca5..71e90d8ccede 100644 --- a/proto/sources.proto +++ b/proto/sources.proto @@ -243,6 +243,7 @@ message GitHub { bool skip_binaries = 17; bool skip_archives = 18; bool include_wikis = 19; + uint32 comments_timeframe_days = 20; } message GitHubExperimental { @@ -427,13 +428,13 @@ message Postman { credentials.Unauthenticated unauthenticated = 1; string token = 2; } - repeated string workspaces = 3; + repeated string workspaces = 3; repeated string collections = 4; repeated string environments = 5; repeated string exclude_collections = 6; - repeated string exclude_environments = 7; + repeated string exclude_environments = 7; repeated string include_collections = 8; - repeated string include_environments = 9; + repeated string include_environments = 9; repeated string detector_keywords = 10; repeated string workspace_paths = 11; repeated string collection_paths = 12; From 75dd64b9eb7bb1f9f21e42355f52784abfdf862e Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 15 Oct 2024 12:18:03 -0700 Subject: [PATCH 29/76] fix(deps): update module google.golang.org/api to v0.201.0 (#3416) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- go.mod | 4 ++-- go.sum | 4 ++++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/go.mod b/go.mod index 3b4d7ce80ff8..311e42522c6c 100644 --- a/go.mod +++ b/go.mod @@ -108,7 +108,7 @@ require ( golang.org/x/oauth2 v0.23.0 golang.org/x/sync v0.8.0 golang.org/x/text v0.19.0 - google.golang.org/api v0.200.0 + google.golang.org/api v0.201.0 google.golang.org/protobuf v1.35.1 gopkg.in/h2non/gock.v1 v1.1.2 gopkg.in/yaml.v2 v2.4.0 @@ -120,7 +120,7 @@ require ( require ( cel.dev/expr v0.16.1 // indirect - cloud.google.com/go v0.115.1 // indirect + cloud.google.com/go v0.116.0 // indirect cloud.google.com/go/auth v0.9.8 // indirect cloud.google.com/go/auth/oauth2adapt v0.2.4 // indirect cloud.google.com/go/compute/metadata v0.5.2 // indirect diff --git a/go.sum b/go.sum index 90700c1ad38f..4e64d7f24b63 100644 --- a/go.sum +++ b/go.sum @@ -11,6 +11,8 @@ cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6T cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M= cloud.google.com/go v0.115.1 h1:Jo0SM9cQnSkYfp44+v+NQXHpcHqlnRJk2qxh6yvxxxQ= cloud.google.com/go v0.115.1/go.mod h1:DuujITeaufu3gL68/lOFIirVNJwQeyf5UXyi+Wbgknc= +cloud.google.com/go v0.116.0 h1:B3fRrSDkLRt5qSHWe40ERJvhvnQwdZiHu0bJOpldweE= +cloud.google.com/go v0.116.0/go.mod h1:cEPSRWPzZEswwdr9BxE6ChEn01dWlTaF05LiC2Xs70U= cloud.google.com/go/auth v0.9.5 h1:4CTn43Eynw40aFVr3GpPqsQponx2jv0BQpjvajsbbzw= cloud.google.com/go/auth v0.9.5/go.mod h1:Xo0n7n66eHyOWWCnitop6870Ilwo3PiZyodVkkH1xWM= cloud.google.com/go/auth v0.9.8 h1:+CSJ0Gw9iVeSENVCKJoLHhdUykDgXSc4Qn+gu2BRtR8= @@ -1105,6 +1107,8 @@ google.golang.org/api v0.199.0 h1:aWUXClp+VFJmqE0JPvpZOK3LDQMyFKYIow4etYd9qxs= google.golang.org/api v0.199.0/go.mod h1:ohG4qSztDJmZdjK/Ar6MhbAmb/Rpi4JHOqagsh90K28= google.golang.org/api v0.200.0 h1:0ytfNWn101is6e9VBoct2wrGDjOi5vn7jw5KtaQgDrU= google.golang.org/api v0.200.0/go.mod h1:Tc5u9kcbjO7A8SwGlYj4IiVifJU01UqXtEgDMYmBmV8= +google.golang.org/api v0.201.0 h1:+7AD9JNM3tREtawRMu8sOjSbb8VYcYXJG/2eEOmfDu0= +google.golang.org/api v0.201.0/go.mod h1:HVY0FCHVs89xIW9fzf/pBvOEm+OolHa86G/txFezyq4= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= From aa23f3d204f1cecde8dcefea5acdbcc6263513c6 Mon Sep 17 00:00:00 2001 From: ktranSC <167803002+ktranSC@users.noreply.github.com> Date: Tue, 15 Oct 2024 12:18:40 -0700 Subject: [PATCH 30/76] Add feature flags to CLI args (#3359) * Update main.go * Update main.go --- main.go | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/main.go b/main.go index a3f9c793b376..f5b629fb7ae6 100644 --- a/main.go +++ b/main.go @@ -30,6 +30,7 @@ import ( "github.com/trufflesecurity/trufflehog/v3/pkg/handlers" "github.com/trufflesecurity/trufflehog/v3/pkg/log" "github.com/trufflesecurity/trufflehog/v3/pkg/output" + "github.com/trufflesecurity/trufflehog/v3/pkg/feature" "github.com/trufflesecurity/trufflehog/v3/pkg/sources" "github.com/trufflesecurity/trufflehog/v3/pkg/tui" "github.com/trufflesecurity/trufflehog/v3/pkg/updater" @@ -70,6 +71,12 @@ var ( excludeDetectors = cli.Flag("exclude-detectors", "Comma separated list of detector types to exclude. Protobuf name or IDs may be used, as well as ranges. IDs defined here take precedence over the include list.").String() jobReportFile = cli.Flag("output-report", "Write a scan report to the provided path.").Hidden().OpenFile(os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0666) + // Add feature flags + forceSkipBinaries = cli.Flag("force-skip-binaries", "Force skipping binaries.").Bool() + forceSkipArchives = cli.Flag("force-skip-archives", "Force skipping archives.").Bool() + skipAdditionalRefs = cli.Flag("skip-additional-refs", "Skip additional references.").Bool() + userAgentSuffix = cli.Flag("user-agent-suffix", "Suffix to add to User-Agent.").String() + gitScan = cli.Command("git", "Find credentials in git repositories.") gitScanURI = gitScan.Arg("uri", "Git repository URL. https://, file://, or ssh:// schema expected.").Required().String() gitScanIncludePaths = gitScan.Flag("include-paths", "Path to file with newline separated regexes for files to include in scan.").Short('i').String() @@ -368,6 +375,23 @@ func run(state overseer.State) { }() } + // Set feature configurations from CLI flags + if *forceSkipBinaries { + feature.ForceSkipBinaries.Store(true) + } + + if *forceSkipArchives { + feature.ForceSkipArchives.Store(true) + } + + if *skipAdditionalRefs { + feature.SkipAdditionalRefs.Store(true) + } + + if *userAgentSuffix != "" { + feature.UserAgentSuffix.Store(*userAgentSuffix) + } + conf := &config.Config{} if *configFilename != "" { var err error From c39c5cb4a7254ec35c732b3d8feb2b0fe0cc1412 Mon Sep 17 00:00:00 2001 From: Richard Gomez <32133502+rgmz@users.noreply.github.com> Date: Tue, 15 Oct 2024 15:23:18 -0400 Subject: [PATCH 31/76] fix: include integration test in generate.go (#3415) --- hack/generate/generate.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/hack/generate/generate.go b/hack/generate/generate.go index e6286bed144c..68ff6211384f 100644 --- a/hack/generate/generate.go +++ b/hack/generate/generate.go @@ -43,6 +43,11 @@ func main() { WritePath: filepath.Join(folderPath(), nameLower+"_test.go"), ReplaceString: []string{"alchemy"}, }, + { + TemplatePath: "pkg/detectors/alchemy/alchemy_integration_test.go", + WritePath: filepath.Join(folderPath(), nameLower+"_integration_test.go"), + ReplaceString: []string{"alchemy"}, + }, }) // case "source": // mustWriteTemplates([]templateJob{ From 8988cb51be4c97bcd362d7524fc67b47ac967a58 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 15 Oct 2024 12:43:19 -0700 Subject: [PATCH 32/76] fix(deps): update module github.com/prometheus/client_golang to v1.20.5 (#3412) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- go.mod | 2 +- go.sum | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/go.mod b/go.mod index 311e42522c6c..f549483d5f64 100644 --- a/go.mod +++ b/go.mod @@ -78,7 +78,7 @@ require ( github.com/patrickmn/go-cache v2.1.0+incompatible github.com/paulbellamy/ratecounter v0.2.0 github.com/pkg/errors v0.9.1 - github.com/prometheus/client_golang v1.20.4 + github.com/prometheus/client_golang v1.20.5 github.com/rabbitmq/amqp091-go v1.10.0 github.com/sassoftware/go-rpmutils v0.4.0 github.com/schollz/progressbar/v3 v3.16.1 diff --git a/go.sum b/go.sum index 4e64d7f24b63..adbe5df40f0d 100644 --- a/go.sum +++ b/go.sum @@ -673,6 +673,8 @@ github.com/prashantv/gostub v1.1.0 h1:BTyx3RfQjRHnUWaGF9oQos79AlQ5k8WNktv7VGvVH4 github.com/prashantv/gostub v1.1.0/go.mod h1:A5zLQHz7ieHGG7is6LLXLz7I8+3LZzsrV0P1IAHhP5U= github.com/prometheus/client_golang v1.20.4 h1:Tgh3Yr67PaOv/uTqloMsCEdeuFTatm5zIq5+qNN23vI= github.com/prometheus/client_golang v1.20.4/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE= +github.com/prometheus/client_golang v1.20.5 h1:cxppBPuYhUnsO6yo/aoRol4L7q7UFfdm+bR9r+8l63Y= +github.com/prometheus/client_golang v1.20.5/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E= github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY= From e6c43ca86341970e67441b3c2c7bd9a8547dfc6d Mon Sep 17 00:00:00 2001 From: Kashif Khan <70996046+kashifkhan0771@users.noreply.github.com> Date: Wed, 16 Oct 2024 17:53:06 +0500 Subject: [PATCH 33/76] ignore https as false postive for slackwebhook detector (#3425) --- .gitignore | 1 + pkg/detectors/slackwebhook/slackwebhook.go | 12 + .../slackwebhook_integration_test.go | 191 ++++++++++++++++ .../slackwebhook/slackwebhook_test.go | 211 +++++------------- 4 files changed, 254 insertions(+), 161 deletions(-) create mode 100644 pkg/detectors/slackwebhook/slackwebhook_integration_test.go diff --git a/.gitignore b/.gitignore index 84eaebc5a2ea..6abf4e766574 100644 --- a/.gitignore +++ b/.gitignore @@ -9,3 +9,4 @@ tmp/go-test.json .captain/detectors/timings.yaml .captain/detectors/quarantines.yaml .captain/detectors/flakes.yaml +.vscode diff --git a/pkg/detectors/slackwebhook/slackwebhook.go b/pkg/detectors/slackwebhook/slackwebhook.go index df9783afa3d1..8453513cfd01 100644 --- a/pkg/detectors/slackwebhook/slackwebhook.go +++ b/pkg/detectors/slackwebhook/slackwebhook.go @@ -20,6 +20,7 @@ type Scanner struct { // Ensure the Scanner satisfies the interface at compile time. var _ detectors.Detector = (*Scanner)(nil) +var _ detectors.CustomFalsePositiveChecker = (*Scanner)(nil) var ( defaultClient = detectors.DetectorHttpClientWithNoLocalAddresses @@ -115,3 +116,14 @@ func (s Scanner) Type() detectorspb.DetectorType { func (s Scanner) Description() string { return "Slack webhooks are used to send messages from external sources into Slack channels. If compromised, they can be used to send unauthorized messages." } + +func (s Scanner) IsFalsePositive(result detectors.Result) (bool, string) { + // ignore "https:" as a false positive for slack webhook detector + if strings.Contains(string(result.Raw), "https:") { + return false, "" + } + + // back to the default false positive checks + return detectors.IsKnownFalsePositive(string(result.Raw), detectors.DefaultFalsePositives, true) + +} diff --git a/pkg/detectors/slackwebhook/slackwebhook_integration_test.go b/pkg/detectors/slackwebhook/slackwebhook_integration_test.go new file mode 100644 index 000000000000..706b5b62e25b --- /dev/null +++ b/pkg/detectors/slackwebhook/slackwebhook_integration_test.go @@ -0,0 +1,191 @@ +//go:build detectors +// +build detectors + +package slackwebhook + +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 TestSlackWebhook_FromChunk(t *testing.T) { + ctx, cancel := context.WithTimeout(context.Background(), time.Second*5) + defer cancel() + testSecrets, err := common.GetSecret(ctx, "trufflehog-testing", "detectors5") + if err != nil { + t.Fatalf("could not get test secrets from GCP: %s", err) + } + secret := testSecrets.MustGetField("SLACKWEBHOOK_TOKEN") + inactiveSecret := testSecrets.MustGetField("SLACKWEBHOOK_INACTIVE") + deletedWebhook := testSecrets.MustGetField("SLACKWEBHOOK_DELETED") + deletedUserActiveWebhook := testSecrets.MustGetField("SLACKWEBHOOK_DELETED_USER_ACTIVE_WEBHOOK") + + 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: "active webhook", + s: Scanner{}, + args: args{ + ctx: context.Background(), + data: []byte(fmt.Sprintf("You can find a slackwebhook secret %s within", secret)), + verify: true, + }, + want: []detectors.Result{ + { + DetectorType: detectorspb.DetectorType_SlackWebhook, + ExtraData: map[string]string{"rotation_guide": "https://howtorotate.com/docs/tutorials/slack-webhook/"}, + Verified: true, + }, + }, + wantErr: false, + wantVerificationErr: false, + }, + { + name: "active webhook created by a deactivated user", + s: Scanner{}, + args: args{ + ctx: context.Background(), + data: []byte(fmt.Sprintf("You can find a slackwebhook secret %s within", deletedUserActiveWebhook)), + verify: true, + }, + want: []detectors.Result{ + { + DetectorType: detectorspb.DetectorType_SlackWebhook, + ExtraData: map[string]string{"rotation_guide": "https://howtorotate.com/docs/tutorials/slack-webhook/"}, + Verified: true, + }, + }, + wantErr: false, + wantVerificationErr: false, + }, + { + name: "deleted webhook", + s: Scanner{}, + args: args{ + ctx: context.Background(), + data: []byte(fmt.Sprintf("You can find a slackwebhook secret %s within", deletedWebhook)), + verify: true, + }, + want: []detectors.Result{ + { + DetectorType: detectorspb.DetectorType_SlackWebhook, + ExtraData: map[string]string{"rotation_guide": "https://howtorotate.com/docs/tutorials/slack-webhook/"}, + Verified: false, + }, + }, + wantErr: false, + wantVerificationErr: false, + }, + { + name: "webhook from app with revoked token", + s: Scanner{}, + args: args{ + ctx: context.Background(), + data: []byte(fmt.Sprintf("You can find a slackwebhook secret %s within", inactiveSecret)), + verify: true, + }, + want: []detectors.Result{ + { + DetectorType: detectorspb.DetectorType_SlackWebhook, + ExtraData: map[string]string{"rotation_guide": "https://howtorotate.com/docs/tutorials/slack-webhook/"}, + Verified: false, + }, + }, + wantErr: false, + wantVerificationErr: false, + }, + { + name: "unexpected webhook response", + s: Scanner{client: common.ConstantResponseHttpClient(500, "oh no")}, + args: args{ + ctx: context.Background(), + data: []byte(fmt.Sprintf("You can find a slackwebhook secret %s within", secret)), + verify: true, + }, + want: []detectors.Result{ + { + DetectorType: detectorspb.DetectorType_SlackWebhook, + ExtraData: map[string]string{"rotation_guide": "https://howtorotate.com/docs/tutorials/slack-webhook/"}, + Verified: false, + }, + }, + wantErr: false, + wantVerificationErr: true, + }, + { + name: "timeout", + s: Scanner{client: common.SaneHttpClientTimeOut(1 * time.Microsecond)}, + args: args{ + ctx: context.Background(), + data: []byte(fmt.Sprintf("You can find a slackwebhook secret %s within", secret)), + verify: true, + }, + want: []detectors.Result{ + { + DetectorType: detectorspb.DetectorType_SlackWebhook, + ExtraData: map[string]string{"rotation_guide": "https://howtorotate.com/docs/tutorials/slack-webhook/"}, + Verified: false, + }, + }, + wantErr: false, + wantVerificationErr: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := tt.s.FromData(tt.args.ctx, tt.args.verify, tt.args.data) + if (err != nil) != tt.wantErr { + t.Errorf("SlackWebhook.FromData() error = %v, wantErr %v", err, tt.wantErr) + return + } + 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.Fatalf("wantVerificationError = %v, verification error = %v", tt.wantVerificationErr, got[i].VerificationError()) + } + } + ignoreOpts := cmpopts.IgnoreFields(detectors.Result{}, "Raw", "verificationError") + if diff := cmp.Diff(got, tt.want, ignoreOpts); diff != "" { + t.Errorf("SlackWebhook.FromData() %s diff: (-got +want)\n%s", tt.name, diff) + } + }) + } +} + +func BenchmarkFromData(benchmark *testing.B) { + ctx := context.Background() + s := Scanner{} + for name, data := range detectors.MustGetBenchmarkData() { + benchmark.Run(name, func(b *testing.B) { + b.ResetTimer() + for n := 0; n < b.N; n++ { + _, err := s.FromData(ctx, false, data) + if err != nil { + b.Fatal(err) + } + } + }) + } +} diff --git a/pkg/detectors/slackwebhook/slackwebhook_test.go b/pkg/detectors/slackwebhook/slackwebhook_test.go index 706b5b62e25b..1a63f0c8641b 100644 --- a/pkg/detectors/slackwebhook/slackwebhook_test.go +++ b/pkg/detectors/slackwebhook/slackwebhook_test.go @@ -1,190 +1,79 @@ -//go:build detectors -// +build detectors - package slackwebhook 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" + "github.com/trufflesecurity/trufflehog/v3/pkg/engine/ahocorasick" ) -func TestSlackWebhook_FromChunk(t *testing.T) { - ctx, cancel := context.WithTimeout(context.Background(), time.Second*5) - defer cancel() - testSecrets, err := common.GetSecret(ctx, "trufflehog-testing", "detectors5") - if err != nil { - t.Fatalf("could not get test secrets from GCP: %s", err) - } - secret := testSecrets.MustGetField("SLACKWEBHOOK_TOKEN") - inactiveSecret := testSecrets.MustGetField("SLACKWEBHOOK_INACTIVE") - deletedWebhook := testSecrets.MustGetField("SLACKWEBHOOK_DELETED") - deletedUserActiveWebhook := testSecrets.MustGetField("SLACKWEBHOOK_DELETED_USER_ACTIVE_WEBHOOK") +var ( + validPattern = "https://hooks.slack.com/services/TAGGINGEXAMPLE/BASE/91nziTEEzAAcaNZiz1mPPoXyS" + invalidPattern = "https://hooks.slack.com/apps/LAGGINGEXAMPLE/BASE/91nziTEEzAAcaNZiz1mPPoXyS" +) + +func TestSlackWebHook_Pattern(t *testing.T) { + d := Scanner{} + ahoCorasickCore := ahocorasick.NewAhoCorasickCore([]detectors.Detector{d}) - 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 string + input string + want []string }{ { - name: "active webhook", - s: Scanner{}, - args: args{ - ctx: context.Background(), - data: []byte(fmt.Sprintf("You can find a slackwebhook secret %s within", secret)), - verify: true, - }, - want: []detectors.Result{ - { - DetectorType: detectorspb.DetectorType_SlackWebhook, - ExtraData: map[string]string{"rotation_guide": "https://howtorotate.com/docs/tutorials/slack-webhook/"}, - Verified: true, - }, - }, - wantErr: false, - wantVerificationErr: false, - }, - { - name: "active webhook created by a deactivated user", - s: Scanner{}, - args: args{ - ctx: context.Background(), - data: []byte(fmt.Sprintf("You can find a slackwebhook secret %s within", deletedUserActiveWebhook)), - verify: true, - }, - want: []detectors.Result{ - { - DetectorType: detectorspb.DetectorType_SlackWebhook, - ExtraData: map[string]string{"rotation_guide": "https://howtorotate.com/docs/tutorials/slack-webhook/"}, - Verified: true, - }, - }, - wantErr: false, - wantVerificationErr: false, - }, - { - name: "deleted webhook", - s: Scanner{}, - args: args{ - ctx: context.Background(), - data: []byte(fmt.Sprintf("You can find a slackwebhook secret %s within", deletedWebhook)), - verify: true, - }, - want: []detectors.Result{ - { - DetectorType: detectorspb.DetectorType_SlackWebhook, - ExtraData: map[string]string{"rotation_guide": "https://howtorotate.com/docs/tutorials/slack-webhook/"}, - Verified: false, - }, - }, - wantErr: false, - wantVerificationErr: false, - }, - { - name: "webhook from app with revoked token", - s: Scanner{}, - args: args{ - ctx: context.Background(), - data: []byte(fmt.Sprintf("You can find a slackwebhook secret %s within", inactiveSecret)), - verify: true, - }, - want: []detectors.Result{ - { - DetectorType: detectorspb.DetectorType_SlackWebhook, - ExtraData: map[string]string{"rotation_guide": "https://howtorotate.com/docs/tutorials/slack-webhook/"}, - Verified: false, - }, - }, - wantErr: false, - wantVerificationErr: false, - }, - { - name: "unexpected webhook response", - s: Scanner{client: common.ConstantResponseHttpClient(500, "oh no")}, - args: args{ - ctx: context.Background(), - data: []byte(fmt.Sprintf("You can find a slackwebhook secret %s within", secret)), - verify: true, - }, - want: []detectors.Result{ - { - DetectorType: detectorspb.DetectorType_SlackWebhook, - ExtraData: map[string]string{"rotation_guide": "https://howtorotate.com/docs/tutorials/slack-webhook/"}, - Verified: false, - }, - }, - wantErr: false, - wantVerificationErr: true, + name: "valid pattern", + input: validPattern, + want: []string{validPattern}, }, { - name: "timeout", - s: Scanner{client: common.SaneHttpClientTimeOut(1 * time.Microsecond)}, - args: args{ - ctx: context.Background(), - data: []byte(fmt.Sprintf("You can find a slackwebhook secret %s within", secret)), - verify: true, - }, - want: []detectors.Result{ - { - DetectorType: detectorspb.DetectorType_SlackWebhook, - ExtraData: map[string]string{"rotation_guide": "https://howtorotate.com/docs/tutorials/slack-webhook/"}, - Verified: false, - }, - }, - wantErr: false, - wantVerificationErr: true, + name: "invalid pattern", + input: invalidPattern, + want: nil, }, } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - got, err := tt.s.FromData(tt.args.ctx, tt.args.verify, tt.args.data) - if (err != nil) != tt.wantErr { - t.Errorf("SlackWebhook.FromData() error = %v, wantErr %v", err, tt.wantErr) + + 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 } - for i := range got { - if len(got[i].Raw) == 0 { - t.Fatalf("no raw secret present: \n %+v", got[i]) + + 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)) } - if (got[i].VerificationError() != nil) != tt.wantVerificationErr { - t.Fatalf("wantVerificationError = %v, verification error = %v", tt.wantVerificationErr, got[i].VerificationError()) + 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{}{} } } - ignoreOpts := cmpopts.IgnoreFields(detectors.Result{}, "Raw", "verificationError") - if diff := cmp.Diff(got, tt.want, ignoreOpts); diff != "" { - t.Errorf("SlackWebhook.FromData() %s diff: (-got +want)\n%s", tt.name, diff) + expected := make(map[string]struct{}, len(test.want)) + for _, v := range test.want { + expected[v] = struct{}{} } - }) - } -} -func BenchmarkFromData(benchmark *testing.B) { - ctx := context.Background() - s := Scanner{} - for name, data := range detectors.MustGetBenchmarkData() { - benchmark.Run(name, func(b *testing.B) { - b.ResetTimer() - for n := 0; n < b.N; n++ { - _, err := s.FromData(ctx, false, data) - if err != nil { - b.Fatal(err) - } + if diff := cmp.Diff(expected, actual); diff != "" { + t.Errorf("%s diff: (-want +got)\n%s", test.name, diff) } }) } From c46d52b11acd43a58ca46d4e13bd19bdd3006c8d Mon Sep 17 00:00:00 2001 From: Dustin Decker Date: Thu, 17 Oct 2024 08:04:37 -0700 Subject: [PATCH 34/76] Compress release with UPX (#3445) --- .github/workflows/release.yml | 4 ++++ .goreleaser.yml | 3 +++ 2 files changed, 7 insertions(+) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 33c86fd6a8b8..db77574b4de1 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -39,6 +39,10 @@ jobs: go-version: "1.23" - name: Cosign install uses: sigstore/cosign-installer@dc72c7d5c4d10cd6bcb8cf6e3fd625a9e5e537da # v3.7.0 + - name: Install UPX + run: | + sudo apt-get update + sudo apt-get install -y upx - name: Run GoReleaser uses: goreleaser/goreleaser-action@v6 with: diff --git a/.goreleaser.yml b/.goreleaser.yml index 77bc73d8cf0a..6fca8511fdc0 100644 --- a/.goreleaser.yml +++ b/.goreleaser.yml @@ -11,6 +11,9 @@ builds: goarch: - amd64 - arm64 + hooks: + post: + - bash -c 'if [ "{{ .Env.GGOOS }}" != "darwin" ]; then upx -q "{{ .Path }}"; fi' dockers: - image_templates: ["trufflesecurity/{{ .ProjectName }}:{{ .Version }}-amd64"] dockerfile: Dockerfile.goreleaser From b66c1670749c06f8d18f96bcbc5a6b80f7a7108e Mon Sep 17 00:00:00 2001 From: Dustin Decker Date: Thu, 17 Oct 2024 09:12:46 -0700 Subject: [PATCH 35/76] Revert "Compress release with UPX (#3445)" (#3455) This reverts commit c46d52b11acd43a58ca46d4e13bd19bdd3006c8d. --- .github/workflows/release.yml | 4 ---- .goreleaser.yml | 3 --- 2 files changed, 7 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index db77574b4de1..33c86fd6a8b8 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -39,10 +39,6 @@ jobs: go-version: "1.23" - name: Cosign install uses: sigstore/cosign-installer@dc72c7d5c4d10cd6bcb8cf6e3fd625a9e5e537da # v3.7.0 - - name: Install UPX - run: | - sudo apt-get update - sudo apt-get install -y upx - name: Run GoReleaser uses: goreleaser/goreleaser-action@v6 with: diff --git a/.goreleaser.yml b/.goreleaser.yml index 6fca8511fdc0..77bc73d8cf0a 100644 --- a/.goreleaser.yml +++ b/.goreleaser.yml @@ -11,9 +11,6 @@ builds: goarch: - amd64 - arm64 - hooks: - post: - - bash -c 'if [ "{{ .Env.GGOOS }}" != "darwin" ]; then upx -q "{{ .Path }}"; fi' dockers: - image_templates: ["trufflesecurity/{{ .ProjectName }}:{{ .Version }}-amd64"] dockerfile: Dockerfile.goreleaser From 871a2b0f06f602899f8c928ce19d2737a3758e6c Mon Sep 17 00:00:00 2001 From: ahrav Date: Thu, 17 Oct 2024 12:53:40 -0700 Subject: [PATCH 36/76] fix timeout (#3460) --- pkg/sources/s3/s3.go | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/pkg/sources/s3/s3.go b/pkg/sources/s3/s3.go index ebd39a1028d4..1ef54391ba3b 100644 --- a/pkg/sources/s3/s3.go +++ b/pkg/sources/s3/s3.go @@ -326,14 +326,20 @@ func (s *Source) pageChunker(ctx context.Context, client *s3.S3, chunksChan chan return nil } - // files break with spaces, must replace with + - // objKey := strings.ReplaceAll(*obj.Key, " ", "+") - ctx, cancel := context.WithTimeout(ctx, time.Second*5) - defer cancel() - res, err := client.GetObjectWithContext(ctx, &s3.GetObjectInput{ - Bucket: &bucket, - Key: obj.Key, - }) + // Use an anonymous function to retrieve the S3 object with a dedicated timeout context. + // This ensures that the timeout is isolated and does not affect any downstream operations. (e.g. HandleFile) + getObject := func() (*s3.GetObjectOutput, error) { + const getObjectTimeout = 5 * time.Second + objCtx, cancel := context.WithTimeout(ctx, getObjectTimeout) + defer cancel() + + return client.GetObjectWithContext(objCtx, &s3.GetObjectInput{ + Bucket: &bucket, + Key: obj.Key, + }) + } + + res, err := getObject() if err != nil { if !strings.Contains(err.Error(), "AccessDenied") { s.log.Error(err, "could not get S3 object", "object", *obj.Key) From 3499df65f29186b3b337c8fee942f0b4cb267092 Mon Sep 17 00:00:00 2001 From: Sahil Silare <32628578+sahil9001@users.noreply.github.com> Date: Sat, 19 Oct 2024 01:56:24 +0530 Subject: [PATCH 37/76] fix: fixed verification logic & endpoint for AyrShare (#3452) * fix: fixed verification endpoint for AyrShare * fix: changed verification endpoint for ayrshare * fix: fixed error handling --- pkg/detectors/ayrshare/ayrshare.go | 32 +++++++++++++++++++++++++----- 1 file changed, 27 insertions(+), 5 deletions(-) diff --git a/pkg/detectors/ayrshare/ayrshare.go b/pkg/detectors/ayrshare/ayrshare.go index db2f43cccadc..c4204ca7b346 100644 --- a/pkg/detectors/ayrshare/ayrshare.go +++ b/pkg/detectors/ayrshare/ayrshare.go @@ -2,11 +2,14 @@ package ayrshare import ( "context" + "encoding/json" "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" @@ -21,7 +24,7 @@ var ( client = common.SaneHttpClient() // Make sure that your group is surrounded in boundary characters such as below to reduce false positives. - keyPat = regexp.MustCompile(detectors.PrefixRegex([]string{"ayrshare"}) + `\b([A-Z]{7}-[A-Z0-9]{7}-[A-Z0-9]{7}-[A-Z0-9]{7})\b`) + keyPat = regexp.MustCompile(detectors.PrefixRegex([]string{"ayrshare"}) + `\b([A-Z0-9]{8}-[A-Z0-9]{8}-[A-Z0-9]{8}-[A-Z0-9]{8})\b`) ) // Keywords are used for efficiently pre-filtering chunks. @@ -48,17 +51,36 @@ func (s Scanner) FromData(ctx context.Context, verify bool, data []byte) (result } if verify { - req, err := http.NewRequestWithContext(ctx, "GET", "https://app.ayrshare.com/api/analytics/links", nil) + req, err := http.NewRequestWithContext(ctx, "GET", "https://app.ayrshare.com/api/user", 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 { + defer func() { + _, _ = io.Copy(io.Discard, res.Body) + _ = res.Body.Close() + }() + + if res.StatusCode == http.StatusOK { s1.Verified = true + bodyBytes, err := io.ReadAll(res.Body) + if err != nil { + continue + } + + var responseBody map[string]interface{} + if err := json.Unmarshal(bodyBytes, &responseBody); err == nil { + if email, ok := responseBody["email"].(string); ok { + s1.ExtraData = map[string]string{ + "email": email, + } + } + } } + } else { + s1.SetVerificationError(err, resMatch) } } From f7252c525a89fd538e629c4faa7ffd0b2cc16a17 Mon Sep 17 00:00:00 2001 From: Sahil Silare <32628578+sahil9001@users.noreply.github.com> Date: Sat, 19 Oct 2024 02:02:17 +0530 Subject: [PATCH 38/76] fix: fixed autoklose verification endpoint (#3447) * fix: fixed autoklose verification endpoint * fix: addressed review comments * fix: addressed review comments * fix: added guard checks for 401 and 200 * fix: added code --- pkg/detectors/autoklose/autoklose.go | 38 ++++++++++++++++------- pkg/detectors/autoklose/autoklose_test.go | 3 ++ 2 files changed, 29 insertions(+), 12 deletions(-) diff --git a/pkg/detectors/autoklose/autoklose.go b/pkg/detectors/autoklose/autoklose.go index 9ee8fde5d3c0..a73b73a95329 100644 --- a/pkg/detectors/autoklose/autoklose.go +++ b/pkg/detectors/autoklose/autoklose.go @@ -4,11 +4,12 @@ import ( "context" "encoding/json" "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" @@ -50,24 +51,37 @@ func (s Scanner) FromData(ctx context.Context, verify bool, data []byte) (result } if verify { - req, err := http.NewRequestWithContext(ctx, "GET", fmt.Sprintf("https://api.autoklose.com/api/campaigns/?api_token=%s", resMatch), nil) + // API Documentation: https://api.aklab.xyz/#auth-info-fd71acd1-2e41-4991-8789-3edfd258479a + req, err := http.NewRequestWithContext(ctx, "GET", fmt.Sprintf("https://api.autoklose.com/api/me/?api_token=%s", resMatch), nil) if err != nil { continue } + req.Header.Add("Accept", "application/json") res, err := client.Do(req) if err == nil { - bodyBytes, err := io.ReadAll(res.Body) - if err != nil { - continue - } - defer res.Body.Close() - if res.StatusCode >= 200 && res.StatusCode < 300 { - if json.Valid(bodyBytes) { - s1.Verified = true - } else { - s1.Verified = false + defer func() { + _, _ = io.Copy(io.Discard, res.Body) + _ = res.Body.Close() + }() + + if res.StatusCode == http.StatusOK { + s1.Verified = true + bodyBytes, err := io.ReadAll(res.Body) + if err != nil { + continue + } + + var responseBody map[string]interface{} + if err := json.Unmarshal(bodyBytes, &responseBody); err == nil { + if email, ok := responseBody["email"].(string); ok { + s1.ExtraData = map[string]string{ + "email": email, + } + } } } + } else { + s1.SetVerificationError(err, resMatch) } } diff --git a/pkg/detectors/autoklose/autoklose_test.go b/pkg/detectors/autoklose/autoklose_test.go index 3976ccf761fd..9675d22cba0f 100644 --- a/pkg/detectors/autoklose/autoklose_test.go +++ b/pkg/detectors/autoklose/autoklose_test.go @@ -50,6 +50,9 @@ func TestAutoklose_FromChunk(t *testing.T) { { DetectorType: detectorspb.DetectorType_Autoklose, Verified: true, + ExtraData: map[string]string{ + "email": "mladen.stevanovic@vanillasoft.com", + }, }, }, wantErr: false, From 88b8c862a6ee7cb884257038a06e5f8aaa9d2db8 Mon Sep 17 00:00:00 2001 From: Damanpreet Singh Date: Sat, 19 Oct 2024 02:17:42 +0530 Subject: [PATCH 39/76] Update yousign detector endpoints to check againt prod and staging urls (#3426) --- pkg/detectors/yousign/yousign.go | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/pkg/detectors/yousign/yousign.go b/pkg/detectors/yousign/yousign.go index e9680772d963..96bd55ef592c 100644 --- a/pkg/detectors/yousign/yousign.go +++ b/pkg/detectors/yousign/yousign.go @@ -3,10 +3,11 @@ package yousign import ( "context" "fmt" - regexp "github.com/wasilibs/go-re2" "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" @@ -14,6 +15,10 @@ import ( type Scanner struct{} +// docs: https://dev.yousign.com/#api-v3-documentation-new +const PROD_URL = "https://api.yousign.com" +const STAGING_URL = "https://staging-api.yousign.com" + // Ensure the Scanner satisfies the interface at compile time. var _ detectors.Detector = (*Scanner)(nil) @@ -48,7 +53,7 @@ func (s Scanner) FromData(ctx context.Context, verify bool, data []byte) (result } if verify { - req, err := http.NewRequestWithContext(ctx, "GET", "https://staging-api.yousign.com/users", nil) + req, err := http.NewRequestWithContext(ctx, "GET", fmt.Sprintf("%s/users", PROD_URL), nil) if err != nil { continue } @@ -59,6 +64,20 @@ func (s Scanner) FromData(ctx context.Context, verify bool, data []byte) (result defer res.Body.Close() if res.StatusCode >= 200 && res.StatusCode < 300 { s1.Verified = true + } else { + req, err = http.NewRequestWithContext(ctx, "GET", fmt.Sprintf("%s/users", STAGING_URL), nil) + if err != nil { + continue + } + req.Header.Add("Content-Type", "application/json") + 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 + } + } } } } From 6e055ea578367a481497533b6302c86682ea5568 Mon Sep 17 00:00:00 2001 From: ahrav Date: Fri, 18 Oct 2024 16:13:03 -0700 Subject: [PATCH 40/76] increase timeout to 30s (#3422) * increase timeout to 30s * add debug * use context logger and include size in logs * close reader * address comments --- pkg/sources/s3/s3.go | 66 ++++++++++++++++++++++++++++++-------------- 1 file changed, 45 insertions(+), 21 deletions(-) diff --git a/pkg/sources/s3/s3.go b/pkg/sources/s3/s3.go index 1ef54391ba3b..b43d2500093c 100644 --- a/pkg/sources/s3/s3.go +++ b/pkg/sources/s3/s3.go @@ -131,6 +131,7 @@ func (s *Source) setMaxObjectSize(maxObjectSize int64) { func (s *Source) newClient(region, roleArn string) (*s3.S3, error) { cfg := aws.NewConfig() cfg.CredentialsChainVerboseErrors = aws.Bool(true) + cfg.LogLevel = aws.LogLevel(aws.LogDebugWithRequestErrors) cfg.Region = aws.String(region) switch cred := s.conn.GetCredential().(type) { @@ -271,38 +272,54 @@ func (s *Source) getRegionalClientForBucket(ctx context.Context, defaultRegionCl } // pageChunker emits chunks onto the given channel from a page -func (s *Source) pageChunker(ctx context.Context, client *s3.S3, chunksChan chan *sources.Chunk, bucket string, page *s3.ListObjectsV2Output, errorCount *sync.Map, pageNumber int, objectCount *uint64) { +func (s *Source) pageChunker( + ctx context.Context, + client *s3.S3, + chunksChan chan *sources.Chunk, + bucket string, + page *s3.ListObjectsV2Output, + errorCount *sync.Map, + pageNumber int, + objectCount *uint64, +) { for _, obj := range page.Contents { - obj := obj - if common.IsDone(ctx) { - return - } - if obj == nil { continue } - // skip GLACIER and GLACIER_IR objects + ctx = context.WithValues( + ctx, + "key", *obj.Key, + "bucket", bucket, + "page", pageNumber, + "size", *obj.Size, + ) + + if common.IsDone(ctx) { + return + } + + // Skip GLACIER and GLACIER_IR objects. if obj.StorageClass == nil || strings.Contains(*obj.StorageClass, "GLACIER") { - s.log.V(5).Info("Skipping object in storage class", "storage_class", *obj.StorageClass, "object", *obj.Key) + ctx.Logger().V(5).Info("Skipping object in storage class", "storage_class", *obj.StorageClass) continue } - // ignore large files + // Ignore large files. if *obj.Size > s.maxObjectSize { - s.log.V(5).Info("Skipping %d byte file (over maxObjectSize limit)", "object", *obj.Key) + ctx.Logger().V(5).Info("Skipping %d byte file (over maxObjectSize limit)") continue } - // file empty file + // File empty file. if *obj.Size == 0 { - s.log.V(5).Info("Skipping 0 byte file", "object", *obj.Key) + ctx.Logger().V(5).Info("Skipping empty file") continue } - // skip incompatible extensions + // Skip incompatible extensions. if common.SkipFile(*obj.Key) { - s.log.V(5).Info("Skipping file with incompatible extension", "object", *obj.Key) + ctx.Logger().V(5).Info("Skipping file with incompatible extension") continue } @@ -310,7 +327,7 @@ func (s *Source) pageChunker(ctx context.Context, client *s3.S3, chunksChan chan defer common.RecoverWithExit(ctx) if strings.HasSuffix(*obj.Key, "/") { - s.log.V(5).Info("Skipping directory", "object", *obj.Key) + ctx.Logger().V(5).Info("Skipping directory") return nil } @@ -322,14 +339,14 @@ func (s *Source) pageChunker(ctx context.Context, client *s3.S3, chunksChan chan nErr = 0 } if nErr.(int) > 3 { - s.log.V(2).Info("Skipped due to excessive errors", "object", *obj.Key) + ctx.Logger().V(2).Info("Skipped due to excessive errors") return nil } // Use an anonymous function to retrieve the S3 object with a dedicated timeout context. // This ensures that the timeout is isolated and does not affect any downstream operations. (e.g. HandleFile) getObject := func() (*s3.GetObjectOutput, error) { - const getObjectTimeout = 5 * time.Second + const getObjectTimeout = 30 * time.Second objCtx, cancel := context.WithTimeout(ctx, getObjectTimeout) defer cancel() @@ -342,7 +359,14 @@ func (s *Source) pageChunker(ctx context.Context, client *s3.S3, chunksChan chan res, err := getObject() if err != nil { if !strings.Contains(err.Error(), "AccessDenied") { - s.log.Error(err, "could not get S3 object", "object", *obj.Key) + ctx.Logger().Error(err, "could not get S3 object") + } + // According to the documentation for GetObjectWithContext, + // the response can be non-nil even if there was an error. + // It's uncertain if the body will be nil in such cases, + // but we'll close it if it's not. + if res != nil && res.Body != nil { + res.Body.Close() } nErr, ok := errorCount.Load(prefix) @@ -350,14 +374,14 @@ func (s *Source) pageChunker(ctx context.Context, client *s3.S3, chunksChan chan nErr = 0 } if nErr.(int) > 3 { - s.log.V(3).Info("Skipped due to excessive errors", "object", *obj.Key) + ctx.Logger().V(3).Info("Skipped due to excessive errors") return nil } nErr = nErr.(int) + 1 errorCount.Store(prefix, nErr) // too many consecutive errors on this page if nErr.(int) > 3 { - s.log.V(2).Info("Too many consecutive errors, excluding prefix", "prefix", prefix) + ctx.Logger().V(2).Info("Too many consecutive errors, excluding prefix", "prefix", prefix) } return nil } @@ -393,7 +417,7 @@ func (s *Source) pageChunker(ctx context.Context, client *s3.S3, chunksChan chan } atomic.AddUint64(objectCount, 1) - s.log.V(5).Info("S3 object scanned.", "object_count", objectCount, "page_number", pageNumber) + ctx.Logger().V(5).Info("S3 object scanned.", "object_count", objectCount) nErr, ok = errorCount.Load(prefix) if !ok { nErr = 0 From 9bca91d6122b8d381ae7b487c44d2a4f332814eb Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 19 Oct 2024 09:49:50 -0700 Subject: [PATCH 41/76] fix(deps): update module cloud.google.com/go/storage to v1.45.0 (#3467) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- go.mod | 2 +- go.sum | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/go.mod b/go.mod index f549483d5f64..515b07bd07d5 100644 --- a/go.mod +++ b/go.mod @@ -15,7 +15,7 @@ replace github.com/STARRY-S/zip => github.com/STARRY-S/zip v0.1.0 require ( cloud.google.com/go/secretmanager v1.14.1 - cloud.google.com/go/storage v1.44.0 + cloud.google.com/go/storage v1.45.0 github.com/Azure/go-autorest/autorest/azure/auth v0.5.13 github.com/AzureAD/microsoft-authentication-library-for-go v1.2.2 github.com/BobuSumisu/aho-corasick v1.0.3 diff --git a/go.sum b/go.sum index adbe5df40f0d..aa08ef934b7e 100644 --- a/go.sum +++ b/go.sum @@ -42,6 +42,8 @@ cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiy cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= cloud.google.com/go/storage v1.44.0 h1:abBzXf4UJKMmQ04xxJf9dYM/fNl24KHoTuBjyJDX2AI= cloud.google.com/go/storage v1.44.0/go.mod h1:wpPblkIuMP5jCB/E48Pz9zIo2S/zD8g+ITmxKkPCITE= +cloud.google.com/go/storage v1.45.0 h1:5av0QcIVj77t+44mV4gffFC/LscFRUhto6UBMB5SimM= +cloud.google.com/go/storage v1.45.0/go.mod h1:wpPblkIuMP5jCB/E48Pz9zIo2S/zD8g+ITmxKkPCITE= cloud.google.com/go/trace v1.11.0 h1:UHX6cOJm45Zw/KIbqHe4kII8PupLt/V5tscZUkeiJVI= cloud.google.com/go/trace v1.11.0/go.mod h1:Aiemdi52635dBR7o3zuc9lLjXo3BwGaChEjCa3tJNmM= dario.cat/mergo v1.0.0 h1:AGCNq9Evsj31mOgNPcLyXc+4PNABt905YmuqPYYpBWk= From fa78cd7e10bad48a2c57d6999f9c27e2b4f46fea Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 19 Oct 2024 09:50:25 -0700 Subject: [PATCH 42/76] fix(deps): update module go.uber.org/mock to v0.5.0 (#3468) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- go.mod | 2 +- go.sum | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/go.mod b/go.mod index 515b07bd07d5..d7f98f067a3b 100644 --- a/go.mod +++ b/go.mod @@ -100,7 +100,7 @@ require ( github.com/xo/dburl v0.23.2 go.mongodb.org/mongo-driver v1.17.1 go.uber.org/automaxprocs v1.6.0 - go.uber.org/mock v0.4.0 + go.uber.org/mock v0.5.0 go.uber.org/zap v1.27.0 golang.org/x/crypto v0.28.0 golang.org/x/exp v0.0.0-20241009180824-f66d83c29e7c diff --git a/go.sum b/go.sum index aa08ef934b7e..c70da4b25f5a 100644 --- a/go.sum +++ b/go.sum @@ -869,6 +869,8 @@ go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/mock v0.4.0 h1:VcM4ZOtdbR4f6VXfiOpwpVJDL6lCReaZ6mw31wqh7KU= go.uber.org/mock v0.4.0/go.mod h1:a6FSlNadKUHUa9IP5Vyt1zh4fC7uAwxMutEAscFbkZc= +go.uber.org/mock v0.5.0 h1:KAMbZvZPyBPWgD14IrIQ38QCyjwpvVVV6K/bHl1IwQU= +go.uber.org/mock v0.5.0/go.mod h1:ge71pBPLYDk7QIi1LupWxdAykm7KIEFchiOqd6z7qMM= go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= From 3ab60865c84ee384a099f4e9b6001f6a50a7d1a2 Mon Sep 17 00:00:00 2001 From: Cody Rose Date: Mon, 21 Oct 2024 09:51:53 -0400 Subject: [PATCH 43/76] Extract FP logic correctly at other call site #3476 --- pkg/engine/engine.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/engine/engine.go b/pkg/engine/engine.go index 4e0ee318df07..1c79fe50f9a3 100644 --- a/pkg/engine/engine.go +++ b/pkg/engine/engine.go @@ -1035,7 +1035,7 @@ func (e *Engine) detectChunk(ctx context.Context, data detectableChunk) { ctx = context.WithValue(ctx, "detector", data.detector.Key.Loggable()) - isFalsePositive := detectors.GetFalsePositiveCheck(data.detector) + isFalsePositive := detectors.GetFalsePositiveCheck(data.detector.Detector) var matchCount int // To reduce the overhead of regex calls in the detector, From 5c99a9964a907bbcd5b7d70b38cdf3655bade6b6 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 21 Oct 2024 08:43:05 -0700 Subject: [PATCH 44/76] fix(deps): update module github.com/jedib0t/go-pretty/v6 to v6.6.1 (#3487) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- go.mod | 2 +- go.sum | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/go.mod b/go.mod index d7f98f067a3b..52c160fe3160 100644 --- a/go.mod +++ b/go.mod @@ -60,7 +60,7 @@ require ( github.com/hashicorp/go-retryablehttp v0.7.7 github.com/hashicorp/golang-lru/v2 v2.0.7 github.com/jedib0t/go-pretty v4.3.0+incompatible - github.com/jedib0t/go-pretty/v6 v6.6.0 + github.com/jedib0t/go-pretty/v6 v6.6.1 github.com/jlaffaye/ftp v0.2.0 github.com/joho/godotenv v1.5.1 github.com/jpillora/overseer v1.1.6 diff --git a/go.sum b/go.sum index c70da4b25f5a..c54e4874a94b 100644 --- a/go.sum +++ b/go.sum @@ -514,6 +514,8 @@ github.com/jedib0t/go-pretty v4.3.0+incompatible h1:CGs8AVhEKg/n9YbUenWmNStRW2PH github.com/jedib0t/go-pretty v4.3.0+incompatible/go.mod h1:XemHduiw8R651AF9Pt4FwCTKeG3oo7hrHJAoznj9nag= github.com/jedib0t/go-pretty/v6 v6.6.0 h1:wmZVuAcEkZRT+Aq1xXpE8IGat4vE5WXOMmBpbQqERXw= github.com/jedib0t/go-pretty/v6 v6.6.0/go.mod h1:zbn98qrYlh95FIhwwsbIip0LYpwSG8SUOScs+v9/t0E= +github.com/jedib0t/go-pretty/v6 v6.6.1 h1:iJ65Xjb680rHcikRj6DSIbzCex2huitmc7bDtxYVWyc= +github.com/jedib0t/go-pretty/v6 v6.6.1/go.mod h1:zbn98qrYlh95FIhwwsbIip0LYpwSG8SUOScs+v9/t0E= github.com/jlaffaye/ftp v0.2.0 h1:lXNvW7cBu7R/68bknOX3MrRIIqZ61zELs1P2RAiA3lg= github.com/jlaffaye/ftp v0.2.0/go.mod h1:is2Ds5qkhceAPy2xD6RLI6hmp/qysSoymZ+Z2uTnspI= github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg= From 86d2c6ded3069d9527b83d7068ac756a91514866 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 21 Oct 2024 08:44:06 -0700 Subject: [PATCH 45/76] fix(deps): update testcontainers-go monorepo to v0.34.0 (#3488) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- go.mod | 14 +++++++------- go.sum | 14 ++++++++++++++ 2 files changed, 21 insertions(+), 7 deletions(-) diff --git a/go.mod b/go.mod index 52c160fe3160..016dad7255d1 100644 --- a/go.mod +++ b/go.mod @@ -88,12 +88,12 @@ require ( github.com/snowflakedb/gosnowflake v1.11.2 github.com/stretchr/testify v1.9.0 github.com/tailscale/depaware v0.0.0-20240804103531-585336c3e1b3 - github.com/testcontainers/testcontainers-go v0.33.0 - github.com/testcontainers/testcontainers-go/modules/elasticsearch v0.33.0 - github.com/testcontainers/testcontainers-go/modules/mongodb v0.33.0 - github.com/testcontainers/testcontainers-go/modules/mssql v0.33.0 - github.com/testcontainers/testcontainers-go/modules/mysql v0.33.0 - github.com/testcontainers/testcontainers-go/modules/postgres v0.33.0 + github.com/testcontainers/testcontainers-go v0.34.0 + github.com/testcontainers/testcontainers-go/modules/elasticsearch v0.34.0 + github.com/testcontainers/testcontainers-go/modules/mongodb v0.34.0 + github.com/testcontainers/testcontainers-go/modules/mssql v0.34.0 + github.com/testcontainers/testcontainers-go/modules/mysql v0.34.0 + github.com/testcontainers/testcontainers-go/modules/postgres v0.34.0 github.com/trufflesecurity/disk-buffer-reader v0.2.1 github.com/wasilibs/go-re2 v1.7.0 github.com/xanzy/go-gitlab v0.112.0 @@ -178,7 +178,7 @@ require ( github.com/couchbase/gocbcoreps v0.1.3 // indirect github.com/couchbase/goprotostellar v1.0.2 // indirect github.com/couchbaselabs/gocbconnstr/v2 v2.0.0-20240607131231-fb385523de28 // indirect - github.com/cpuguy83/dockercfg v0.3.1 // indirect + github.com/cpuguy83/dockercfg v0.3.2 // indirect github.com/cyphar/filepath-securejoin v0.2.4 // indirect github.com/danieljoos/wincred v1.1.2 // indirect github.com/davecgh/go-spew v1.1.1 // indirect diff --git a/go.sum b/go.sum index c54e4874a94b..906668679003 100644 --- a/go.sum +++ b/go.sum @@ -236,6 +236,8 @@ github.com/couchbaselabs/gocbconnstr/v2 v2.0.0-20240607131231-fb385523de28 h1:lh github.com/couchbaselabs/gocbconnstr/v2 v2.0.0-20240607131231-fb385523de28/go.mod h1:o7T431UOfFVHDNvMBUmUxpHnhivwv7BziUao/nMl81E= github.com/cpuguy83/dockercfg v0.3.1 h1:/FpZ+JaygUR/lZP2NlFI2DVfrOEMAIKP5wWEJdoYe9E= github.com/cpuguy83/dockercfg v0.3.1/go.mod h1:sugsbF4//dDlL/i+S+rtpIWp+5h0BHJHfjj5/jFyUJc= +github.com/cpuguy83/dockercfg v0.3.2 h1:DlJTyZGBDlXqUZ2Dk2Q3xHs/FtnooJJVaad2S9GKorA= +github.com/cpuguy83/dockercfg v0.3.2/go.mod h1:sugsbF4//dDlL/i+S+rtpIWp+5h0BHJHfjj5/jFyUJc= github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/creack/pty v1.1.18 h1:n56/Zwd5o6whRC5PMGretI4IdRLlmBXYNjScPaBgsbY= github.com/creack/pty v1.1.18/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4= @@ -754,16 +756,28 @@ github.com/tailscale/depaware v0.0.0-20240804103531-585336c3e1b3 h1:1wRadBXZ4ddC github.com/tailscale/depaware v0.0.0-20240804103531-585336c3e1b3/go.mod h1:p9lPsd+cx33L3H9nNoecRRxPssFKUwwI50I3pZ0yT+8= github.com/testcontainers/testcontainers-go v0.33.0 h1:zJS9PfXYT5O0ZFXM2xxXfk4J5UMw/kRiISng037Gxdw= github.com/testcontainers/testcontainers-go v0.33.0/go.mod h1:W80YpTa8D5C3Yy16icheD01UTDu+LmXIA2Keo+jWtT8= +github.com/testcontainers/testcontainers-go v0.34.0 h1:5fbgF0vIN5u+nD3IWabQwRybuB4GY8G2HHgCkbMzMHo= +github.com/testcontainers/testcontainers-go v0.34.0/go.mod h1:6P/kMkQe8yqPHfPWNulFGdFHTD8HB2vLq/231xY2iPQ= github.com/testcontainers/testcontainers-go/modules/elasticsearch v0.33.0 h1:tVsooNzk7SgYDO1OnqeIgihDYiD/vSBNBqwqCfauIJY= github.com/testcontainers/testcontainers-go/modules/elasticsearch v0.33.0/go.mod h1:qmspvRf+Hx0iyqKQUmTg1jTNiO7HHGNrx98t/HksVfg= +github.com/testcontainers/testcontainers-go/modules/elasticsearch v0.34.0 h1:BBwJUs9xBpt1uOfO+yAr2pYW75MsyzuO/o70HTPnhe4= +github.com/testcontainers/testcontainers-go/modules/elasticsearch v0.34.0/go.mod h1:OqhRGYR+5VG0Dw506F6Ho9I4YG1kB+o9uPTKC0uPUA8= github.com/testcontainers/testcontainers-go/modules/mongodb v0.33.0 h1:iXVA84s5hKMS5gn01GWOYHE3ymy/2b+0YkpFeTxB2XY= github.com/testcontainers/testcontainers-go/modules/mongodb v0.33.0/go.mod h1:R6tMjTojRiaoo89fh/hf7tOmfzohdqSU17R9DwSVSog= +github.com/testcontainers/testcontainers-go/modules/mongodb v0.34.0 h1:o3bgcECyBFfMwqexCH/6vIJ8XzbCffCP/Euesu33rgY= +github.com/testcontainers/testcontainers-go/modules/mongodb v0.34.0/go.mod h1:ljLR42dN7k40CX0dp30R8BRIB3OOdvr7rBANEpfmMs4= github.com/testcontainers/testcontainers-go/modules/mssql v0.33.0 h1:gD4pHUPnEm5Bwup8KFdVmwXJLpyVy1hsp6bOXHAUlTA= github.com/testcontainers/testcontainers-go/modules/mssql v0.33.0/go.mod h1:HdgR2Q9SsGqohT6nhtU3tnG56iNGUV1Tr5If0QypZl0= +github.com/testcontainers/testcontainers-go/modules/mssql v0.34.0 h1:4Pf7ILuLnxhpeTgQfKzEMPuMQhasU3VaYer9l5HrQ3s= +github.com/testcontainers/testcontainers-go/modules/mssql v0.34.0/go.mod h1:L2eMWZ49X0XjewabzJ6TXSY5z4SAWM/2WOBqlIxYFD8= github.com/testcontainers/testcontainers-go/modules/mysql v0.33.0 h1:1JN7YEEepTMJmGI2hW678IiiYoLM5HDp3vbCPmUokJ8= github.com/testcontainers/testcontainers-go/modules/mysql v0.33.0/go.mod h1:9tZZwRW5s3RaI5X0Wnc+GXNJFXqbkKmob2nBHbfA/5E= +github.com/testcontainers/testcontainers-go/modules/mysql v0.34.0 h1:Tqz17mGXjPORHFS/oBUGdeJyIsZXLsVVHRhaBqhewGI= +github.com/testcontainers/testcontainers-go/modules/mysql v0.34.0/go.mod h1:hDpm3DLfjo7rd6232wWflEBDGr6Ow9ys43mJTiJwWx8= github.com/testcontainers/testcontainers-go/modules/postgres v0.33.0 h1:c+Gt+XLJjqFAejgX4hSpnHIpC9eAhvgI/TFWL/PbrFI= github.com/testcontainers/testcontainers-go/modules/postgres v0.33.0/go.mod h1:I4DazHBoWDyf69ByOIyt3OdNjefiUx372459txOpQ3o= +github.com/testcontainers/testcontainers-go/modules/postgres v0.34.0 h1:c51aBXT3v2HEBVarmaBnsKzvgZjC5amn0qsj8Naqi50= +github.com/testcontainers/testcontainers-go/modules/postgres v0.34.0/go.mod h1:EWP75ogLQU4M4L8U+20mFipjV4WIR9WtlMXSB6/wiuc= github.com/tetratelabs/wazero v1.8.0 h1:iEKu0d4c2Pd+QSRieYbnQC9yiFlMS9D+Jr0LsRmcF4g= github.com/tetratelabs/wazero v1.8.0/go.mod h1:yAI0XTsMBhREkM/YDAK/zNou3GoiAce1P6+rp/wQhjs= github.com/therootcompany/xz v1.0.1 h1:CmOtsn1CbtmyYiusbfmhmkpAAETj0wBIH6kCYaX+xzw= From abecab0d8fb9fb3e79366abc3909825488e9bb40 Mon Sep 17 00:00:00 2001 From: Bill Rich Date: Mon, 21 Oct 2024 17:16:26 -0700 Subject: [PATCH 46/76] Remove proto (#3489) Only used for tracking analyzer types --- pkg/analyzer/analyzers/airbrake/airbrake.go | 3 +- pkg/analyzer/analyzers/analyzers.go | 106 ++++++--- pkg/analyzer/analyzers/asana/asana.go | 3 +- pkg/analyzer/analyzers/bitbucket/bitbucket.go | 5 +- pkg/analyzer/analyzers/github/github.go | 3 +- pkg/analyzer/analyzers/gitlab/gitlab.go | 3 +- .../analyzers/huggingface/huggingface.go | 5 +- pkg/analyzer/analyzers/mailchimp/mailchimp.go | 5 +- pkg/analyzer/analyzers/mailgun/mailgun.go | 5 +- pkg/analyzer/analyzers/mysql/mysql.go | 5 +- pkg/analyzer/analyzers/openai/openai.go | 3 +- pkg/analyzer/analyzers/opsgenie/opsgenie.go | 5 +- pkg/analyzer/analyzers/postgres/postgres.go | 5 +- pkg/analyzer/analyzers/postman/postman.go | 5 +- pkg/analyzer/analyzers/sendgrid/sendgrid.go | 5 +- pkg/analyzer/analyzers/shopify/shopify.go | 5 +- pkg/analyzer/analyzers/slack/slack.go | 5 +- .../analyzers/sourcegraph/sourcegraph.go | 5 +- pkg/analyzer/analyzers/square/square.go | 5 +- pkg/analyzer/analyzers/stripe/stripe.go | 5 +- pkg/analyzer/analyzers/twilio/twilio.go | 7 +- pkg/analyzer/cli.go | 6 +- pkg/analyzer/pb/analyzerpb/analyzer.pb.go | 203 ------------------ .../pb/analyzerpb/analyzer.pb.validate.go | 36 ---- pkg/analyzer/proto/analyzer.proto | 29 --- pkg/analyzer/tui/form.go | 2 +- pkg/analyzer/tui/keytype.go | 4 +- pkg/analyzer/tui/tui.go | 2 +- 28 files changed, 122 insertions(+), 358 deletions(-) delete mode 100644 pkg/analyzer/pb/analyzerpb/analyzer.pb.go delete mode 100644 pkg/analyzer/pb/analyzerpb/analyzer.pb.validate.go delete mode 100644 pkg/analyzer/proto/analyzer.proto diff --git a/pkg/analyzer/analyzers/airbrake/airbrake.go b/pkg/analyzer/analyzers/airbrake/airbrake.go index 5575541e16cc..e02d40e93c85 100644 --- a/pkg/analyzer/analyzers/airbrake/airbrake.go +++ b/pkg/analyzer/analyzers/airbrake/airbrake.go @@ -11,7 +11,6 @@ import ( "github.com/jedib0t/go-pretty/table" "github.com/trufflesecurity/trufflehog/v3/pkg/analyzer/analyzers" "github.com/trufflesecurity/trufflehog/v3/pkg/analyzer/config" - "github.com/trufflesecurity/trufflehog/v3/pkg/analyzer/pb/analyzerpb" "github.com/trufflesecurity/trufflehog/v3/pkg/context" ) @@ -21,7 +20,7 @@ type Analyzer struct { Cfg *config.Config } -func (Analyzer) Type() analyzerpb.AnalyzerType { return analyzerpb.AnalyzerType_Airbrake } +func (Analyzer) Type() analyzers.AnalyzerType { return analyzers.AnalyzerTypeAirbrake } func (a Analyzer) Analyze(_ context.Context, credInfo map[string]string) (*analyzers.AnalyzerResult, error) { info, err := AnalyzePermissions(a.Cfg, credInfo["key"]) diff --git a/pkg/analyzer/analyzers/analyzers.go b/pkg/analyzer/analyzers/analyzers.go index f897f4fe2c7a..06eea241f192 100644 --- a/pkg/analyzer/analyzers/analyzers.go +++ b/pkg/analyzer/analyzers/analyzers.go @@ -5,21 +5,23 @@ import ( "encoding/json" "io" "net/http" + "sort" "github.com/fatih/color" - "github.com/trufflesecurity/trufflehog/v3/pkg/analyzer/pb/analyzerpb" "github.com/trufflesecurity/trufflehog/v3/pkg/context" ) type ( Analyzer interface { - Type() analyzerpb.AnalyzerType + Type() AnalyzerType Analyze(ctx context.Context, credentialInfo map[string]string) (*AnalyzerResult, error) } + AnalyzerType int + // AnalyzerResult is the output of analysis. AnalyzerResult struct { - AnalyzerType analyzerpb.AnalyzerType + AnalyzerType AnalyzerType Bindings []Binding UnboundedResources []Resource Metadata map[string]any @@ -56,30 +58,80 @@ const ( FullAccess string = "full_access" ) -// Sorted list of all available analyzers. Used for valid sub-commands and TUI -// selection. TODO: Change slice type to Analyzer interface when all available -// analyzers implement it. -var AvailableAnalyzers = []string{ - "Airbrake", - "Asana", - "Bitbucket", - "GitHub", - "GitLab", - "HuggingFace", - "Mailchimp", - "Mailgun", - "MySQL", - "OpenAI", - "Opsgenie", - "Postgres", - "Postman", - "Sendgrid", - "Shopify", - "Slack", - "Sourcegraph", - "Square", - "Stripe", - "Twilio", +const ( + AnalyzerTypeInvalid AnalyzerType = iota + AnalyzerTypeAirbrake + AnalyzerTypeAsana + AnalyzerTypeBitbucket + AnalyzerTypeGitHub + AnalyzerTypeGitLab + AnalyzerTypeHuggingFace + AnalyzerTypeMailchimp + AnalyzerTypeMailgun + AnalyzerTypeMySQL + AnalyzerTypeOpenAI + AnalyzerTypeOpsgenie + AnalyzerTypePostgres + AnalyzerTypePostman + AnalyzerTypeSendgrid + AnalyzerTypeShopify + AnalyzerTypeSlack + AnalyzerTypeSourcegraph + AnalyzerTypeSquare + AnalyzerTypeStripe + AnalyzerTypeTwilio + // Add new items here with AnalyzerType prefix +) + +// analyzerTypeStrings maps the enum to its string representation. +var analyzerTypeStrings = map[AnalyzerType]string{ + AnalyzerTypeInvalid: "Invalid", + AnalyzerTypeAirbrake: "Airbrake", + AnalyzerTypeAsana: "Asana", + AnalyzerTypeBitbucket: "Bitbucket", + AnalyzerTypeGitHub: "GitHub", + AnalyzerTypeGitLab: "GitLab", + AnalyzerTypeHuggingFace: "HuggingFace", + AnalyzerTypeMailchimp: "Mailchimp", + AnalyzerTypeMailgun: "Mailgun", + AnalyzerTypeMySQL: "MySQL", + AnalyzerTypeOpenAI: "OpenAI", + AnalyzerTypeOpsgenie: "Opsgenie", + AnalyzerTypePostgres: "Postgres", + AnalyzerTypePostman: "Postman", + AnalyzerTypeSendgrid: "Sendgrid", + AnalyzerTypeShopify: "Shopify", + AnalyzerTypeSlack: "Slack", + AnalyzerTypeSourcegraph: "Sourcegraph", + AnalyzerTypeSquare: "Square", + AnalyzerTypeStripe: "Stripe", + AnalyzerTypeTwilio: "Twilio", + // Add new mappings here +} + +// String method to get the string representation of an AnalyzerType. +func (a AnalyzerType) String() string { + if str, ok := analyzerTypeStrings[a]; ok { + return str + } + return "Unknown" +} + +// GetSortedAnalyzerTypes returns a sorted slice of AnalyzerType strings, skipping "Invalid". +func AvailableAnalyzers() []string { + var analyzerStrings []string + + // Iterate through the map to collect all string values except "Invalid". + for typ, str := range analyzerTypeStrings { + if typ != AnalyzerTypeInvalid { + analyzerStrings = append(analyzerStrings, str) + } + } + + // Sort the slice alphabetically. + sort.Strings(analyzerStrings) + + return analyzerStrings } type PermissionStatus struct { diff --git a/pkg/analyzer/analyzers/asana/asana.go b/pkg/analyzer/analyzers/asana/asana.go index 2b6f9b3a6b41..0df9e9735728 100644 --- a/pkg/analyzer/analyzers/asana/asana.go +++ b/pkg/analyzer/analyzers/asana/asana.go @@ -14,7 +14,6 @@ import ( "github.com/jedib0t/go-pretty/table" "github.com/trufflesecurity/trufflehog/v3/pkg/analyzer/analyzers" "github.com/trufflesecurity/trufflehog/v3/pkg/analyzer/config" - "github.com/trufflesecurity/trufflehog/v3/pkg/analyzer/pb/analyzerpb" "github.com/trufflesecurity/trufflehog/v3/pkg/context" ) @@ -24,7 +23,7 @@ type Analyzer struct { Cfg *config.Config } -func (Analyzer) Type() analyzerpb.AnalyzerType { return analyzerpb.AnalyzerType_Asana } +func (Analyzer) Type() analyzers.AnalyzerType { return analyzers.AnalyzerTypeAsana } func (a Analyzer) Analyze(_ context.Context, credInfo map[string]string) (*analyzers.AnalyzerResult, error) { key, ok := credInfo["key"] diff --git a/pkg/analyzer/analyzers/bitbucket/bitbucket.go b/pkg/analyzer/analyzers/bitbucket/bitbucket.go index 7bc4c5cd533d..e146564c2fe6 100644 --- a/pkg/analyzer/analyzers/bitbucket/bitbucket.go +++ b/pkg/analyzer/analyzers/bitbucket/bitbucket.go @@ -13,7 +13,6 @@ import ( "github.com/jedib0t/go-pretty/table" "github.com/trufflesecurity/trufflehog/v3/pkg/analyzer/analyzers" "github.com/trufflesecurity/trufflehog/v3/pkg/analyzer/config" - "github.com/trufflesecurity/trufflehog/v3/pkg/analyzer/pb/analyzerpb" "github.com/trufflesecurity/trufflehog/v3/pkg/context" ) @@ -59,7 +58,7 @@ type Analyzer struct { Cfg *config.Config } -func (Analyzer) Type() analyzerpb.AnalyzerType { return analyzerpb.AnalyzerType_Bitbucket } +func (Analyzer) Type() analyzers.AnalyzerType { return analyzers.AnalyzerTypeBitbucket } func (a Analyzer) Analyze(_ context.Context, credInfo map[string]string) (*analyzers.AnalyzerResult, error) { key, ok := credInfo["key"] @@ -79,7 +78,7 @@ func secretInfoToAnalyzerResult(info *SecretInfo) *analyzers.AnalyzerResult { } result := analyzers.AnalyzerResult{ - AnalyzerType: analyzerpb.AnalyzerType_Bitbucket, + AnalyzerType: analyzers.AnalyzerTypeBitbucket, } // add unbounded resources diff --git a/pkg/analyzer/analyzers/github/github.go b/pkg/analyzer/analyzers/github/github.go index d8b3e9c3d8aa..40a4a7b5dd8b 100644 --- a/pkg/analyzer/analyzers/github/github.go +++ b/pkg/analyzer/analyzers/github/github.go @@ -13,7 +13,6 @@ import ( "github.com/trufflesecurity/trufflehog/v3/pkg/analyzer/analyzers/github/common" "github.com/trufflesecurity/trufflehog/v3/pkg/analyzer/analyzers/github/finegrained" "github.com/trufflesecurity/trufflehog/v3/pkg/analyzer/config" - "github.com/trufflesecurity/trufflehog/v3/pkg/analyzer/pb/analyzerpb" "github.com/trufflesecurity/trufflehog/v3/pkg/context" ) @@ -23,7 +22,7 @@ type Analyzer struct { Cfg *config.Config } -func (Analyzer) Type() analyzerpb.AnalyzerType { return analyzerpb.AnalyzerType_GitHub } +func (Analyzer) Type() analyzers.AnalyzerType { return analyzers.AnalyzerTypeGitHub } func (a Analyzer) Analyze(_ context.Context, credInfo map[string]string) (*analyzers.AnalyzerResult, error) { info, err := AnalyzePermissions(a.Cfg, credInfo["key"]) diff --git a/pkg/analyzer/analyzers/gitlab/gitlab.go b/pkg/analyzer/analyzers/gitlab/gitlab.go index d7563ad53d21..7975d232d64c 100644 --- a/pkg/analyzer/analyzers/gitlab/gitlab.go +++ b/pkg/analyzer/analyzers/gitlab/gitlab.go @@ -13,7 +13,6 @@ import ( "github.com/jedib0t/go-pretty/table" "github.com/trufflesecurity/trufflehog/v3/pkg/analyzer/analyzers" "github.com/trufflesecurity/trufflehog/v3/pkg/analyzer/config" - "github.com/trufflesecurity/trufflehog/v3/pkg/analyzer/pb/analyzerpb" "github.com/trufflesecurity/trufflehog/v3/pkg/context" ) @@ -23,7 +22,7 @@ type Analyzer struct { Cfg *config.Config } -func (Analyzer) Type() analyzerpb.AnalyzerType { return analyzerpb.AnalyzerType_GitLab } +func (Analyzer) Type() analyzers.AnalyzerType { return analyzers.AnalyzerTypeGitLab } func (a Analyzer) Analyze(_ context.Context, credInfo map[string]string) (*analyzers.AnalyzerResult, error) { _, err := AnalyzePermissions(a.Cfg, credInfo["key"]) diff --git a/pkg/analyzer/analyzers/huggingface/huggingface.go b/pkg/analyzer/analyzers/huggingface/huggingface.go index 6de5d70d2d7b..6cc06f9817d5 100644 --- a/pkg/analyzer/analyzers/huggingface/huggingface.go +++ b/pkg/analyzer/analyzers/huggingface/huggingface.go @@ -13,7 +13,6 @@ import ( "github.com/jedib0t/go-pretty/table" "github.com/trufflesecurity/trufflehog/v3/pkg/analyzer/analyzers" "github.com/trufflesecurity/trufflehog/v3/pkg/analyzer/config" - "github.com/trufflesecurity/trufflehog/v3/pkg/analyzer/pb/analyzerpb" "github.com/trufflesecurity/trufflehog/v3/pkg/context" ) @@ -29,7 +28,7 @@ type Analyzer struct { Cfg *config.Config } -func (Analyzer) Type() analyzerpb.AnalyzerType { return analyzerpb.AnalyzerType_HuggingFace } +func (Analyzer) Type() analyzers.AnalyzerType { return analyzers.AnalyzerTypeHuggingFace } func (a Analyzer) Analyze(_ context.Context, credInfo map[string]string) (*analyzers.AnalyzerResult, error) { key, ok := credInfo["key"] @@ -239,7 +238,7 @@ func secretInfoToAnalyzerResult(info *SecretInfo) *analyzers.AnalyzerResult { } result := analyzers.AnalyzerResult{ - AnalyzerType: analyzerpb.AnalyzerType_HuggingFace, + AnalyzerType: analyzers.AnalyzerTypeHuggingFace, Metadata: map[string]interface{}{ "username": info.Token.Username, "name": info.Token.Name, diff --git a/pkg/analyzer/analyzers/mailchimp/mailchimp.go b/pkg/analyzer/analyzers/mailchimp/mailchimp.go index bc13fc6ca243..390167fd6cfa 100644 --- a/pkg/analyzer/analyzers/mailchimp/mailchimp.go +++ b/pkg/analyzer/analyzers/mailchimp/mailchimp.go @@ -13,7 +13,6 @@ import ( "github.com/jedib0t/go-pretty/table" "github.com/trufflesecurity/trufflehog/v3/pkg/analyzer/analyzers" "github.com/trufflesecurity/trufflehog/v3/pkg/analyzer/config" - "github.com/trufflesecurity/trufflehog/v3/pkg/analyzer/pb/analyzerpb" "github.com/trufflesecurity/trufflehog/v3/pkg/context" ) @@ -25,7 +24,7 @@ type Analyzer struct { Cfg *config.Config } -func (Analyzer) Type() analyzerpb.AnalyzerType { return analyzerpb.AnalyzerType_Mailchimp } +func (Analyzer) Type() analyzers.AnalyzerType { return analyzers.AnalyzerTypeMailchimp } func (a Analyzer) Analyze(_ context.Context, credInfo map[string]string) (*analyzers.AnalyzerResult, error) { key, ok := credInfo["key"] @@ -45,7 +44,7 @@ func secretInfoToAnalyzerResult(info *SecretInfo) *analyzers.AnalyzerResult { return nil } result := analyzers.AnalyzerResult{ - AnalyzerType: analyzerpb.AnalyzerType_Mailchimp, + AnalyzerType: analyzers.AnalyzerTypeMailchimp, Bindings: make([]analyzers.Binding, 0, len(StringToPermission)), UnboundedResources: make([]analyzers.Resource, 0, len(info.Domains.Domains)), } diff --git a/pkg/analyzer/analyzers/mailgun/mailgun.go b/pkg/analyzer/analyzers/mailgun/mailgun.go index 62dcabf42438..2c499000fd60 100644 --- a/pkg/analyzer/analyzers/mailgun/mailgun.go +++ b/pkg/analyzer/analyzers/mailgun/mailgun.go @@ -13,7 +13,6 @@ import ( "github.com/jedib0t/go-pretty/table" "github.com/trufflesecurity/trufflehog/v3/pkg/analyzer/analyzers" "github.com/trufflesecurity/trufflehog/v3/pkg/analyzer/config" - "github.com/trufflesecurity/trufflehog/v3/pkg/analyzer/pb/analyzerpb" "github.com/trufflesecurity/trufflehog/v3/pkg/context" ) @@ -23,7 +22,7 @@ type Analyzer struct { Cfg *config.Config } -func (Analyzer) Type() analyzerpb.AnalyzerType { return analyzerpb.AnalyzerType_Mailgun } +func (Analyzer) Type() analyzers.AnalyzerType { return analyzers.AnalyzerTypeMailgun } func (a Analyzer) Analyze(_ context.Context, credInfo map[string]string) (*analyzers.AnalyzerResult, error) { key, ok := credInfo["key"] @@ -43,7 +42,7 @@ func secretInfoToAnalyzerResult(info *DomainsJSON) *analyzers.AnalyzerResult { return nil } result := analyzers.AnalyzerResult{ - AnalyzerType: analyzerpb.AnalyzerType_Mailgun, + AnalyzerType: analyzers.AnalyzerTypeMailgun, Bindings: make([]analyzers.Binding, len(info.Items)), } diff --git a/pkg/analyzer/analyzers/mysql/mysql.go b/pkg/analyzer/analyzers/mysql/mysql.go index 81870af0ace3..173cb4305ae1 100644 --- a/pkg/analyzer/analyzers/mysql/mysql.go +++ b/pkg/analyzer/analyzers/mysql/mysql.go @@ -19,7 +19,6 @@ import ( "github.com/trufflesecurity/trufflehog/v3/pkg/analyzer/analyzers" "github.com/trufflesecurity/trufflehog/v3/pkg/analyzer/config" - "github.com/trufflesecurity/trufflehog/v3/pkg/analyzer/pb/analyzerpb" "github.com/trufflesecurity/trufflehog/v3/pkg/context" ) @@ -29,7 +28,7 @@ type Analyzer struct { Cfg *config.Config } -func (Analyzer) Type() analyzerpb.AnalyzerType { return analyzerpb.AnalyzerType_MySQL } +func (Analyzer) Type() analyzers.AnalyzerType { return analyzers.AnalyzerTypeMySQL } func (a Analyzer) Analyze(_ context.Context, credInfo map[string]string) (*analyzers.AnalyzerResult, error) { uri, ok := credInfo["connection_string"] @@ -48,7 +47,7 @@ func secretInfoToAnalyzerResult(info *SecretInfo) *analyzers.AnalyzerResult { return nil } result := analyzers.AnalyzerResult{ - AnalyzerType: analyzerpb.AnalyzerType_MySQL, + AnalyzerType: analyzers.AnalyzerTypeMySQL, Metadata: nil, Bindings: []analyzers.Binding{}, } diff --git a/pkg/analyzer/analyzers/openai/openai.go b/pkg/analyzer/analyzers/openai/openai.go index 1cd40f2b52f5..041c2950fa34 100644 --- a/pkg/analyzer/analyzers/openai/openai.go +++ b/pkg/analyzer/analyzers/openai/openai.go @@ -16,7 +16,6 @@ import ( "github.com/trufflesecurity/trufflehog/v3/pkg/analyzer/analyzers" "github.com/trufflesecurity/trufflehog/v3/pkg/analyzer/config" - "github.com/trufflesecurity/trufflehog/v3/pkg/analyzer/pb/analyzerpb" "github.com/trufflesecurity/trufflehog/v3/pkg/context" ) @@ -26,7 +25,7 @@ type Analyzer struct { Cfg *config.Config } -func (Analyzer) Type() analyzerpb.AnalyzerType { return analyzerpb.AnalyzerType_OpenAI } +func (Analyzer) Type() analyzers.AnalyzerType { return analyzers.AnalyzerTypeOpenAI } func (a Analyzer) Analyze(_ context.Context, credInfo map[string]string) (*analyzers.AnalyzerResult, error) { info, err := AnalyzePermissions(a.Cfg, credInfo["key"]) diff --git a/pkg/analyzer/analyzers/opsgenie/opsgenie.go b/pkg/analyzer/analyzers/opsgenie/opsgenie.go index f308383ef81d..f63efd4408ce 100644 --- a/pkg/analyzer/analyzers/opsgenie/opsgenie.go +++ b/pkg/analyzer/analyzers/opsgenie/opsgenie.go @@ -16,7 +16,6 @@ import ( "github.com/jedib0t/go-pretty/table" "github.com/trufflesecurity/trufflehog/v3/pkg/analyzer/analyzers" "github.com/trufflesecurity/trufflehog/v3/pkg/analyzer/config" - "github.com/trufflesecurity/trufflehog/v3/pkg/analyzer/pb/analyzerpb" "github.com/trufflesecurity/trufflehog/v3/pkg/context" ) @@ -26,7 +25,7 @@ type Analyzer struct { Cfg *config.Config } -func (Analyzer) Type() analyzerpb.AnalyzerType { return analyzerpb.AnalyzerType_Opsgenie } +func (Analyzer) Type() analyzers.AnalyzerType { return analyzers.AnalyzerTypeOpsgenie } func (a Analyzer) Analyze(_ context.Context, credInfo map[string]string) (*analyzers.AnalyzerResult, error) { key, ok := credInfo["key"] @@ -45,7 +44,7 @@ func secretInfoToAnalyzerResult(info *SecretInfo) *analyzers.AnalyzerResult { return nil } result := analyzers.AnalyzerResult{ - AnalyzerType: analyzerpb.AnalyzerType_Opsgenie, + AnalyzerType: analyzers.AnalyzerTypeOpsgenie, Metadata: nil, Bindings: make([]analyzers.Binding, len(info.Permissions)), UnboundedResources: make([]analyzers.Resource, len(info.Users)), diff --git a/pkg/analyzer/analyzers/postgres/postgres.go b/pkg/analyzer/analyzers/postgres/postgres.go index 1eae6047d426..ca4a74e20357 100644 --- a/pkg/analyzer/analyzers/postgres/postgres.go +++ b/pkg/analyzer/analyzers/postgres/postgres.go @@ -16,7 +16,6 @@ import ( "github.com/trufflesecurity/trufflehog/v3/pkg/analyzer/analyzers" "github.com/trufflesecurity/trufflehog/v3/pkg/analyzer/config" - "github.com/trufflesecurity/trufflehog/v3/pkg/analyzer/pb/analyzerpb" "github.com/trufflesecurity/trufflehog/v3/pkg/context" ) @@ -26,7 +25,7 @@ type Analyzer struct { Cfg *config.Config } -func (Analyzer) Type() analyzerpb.AnalyzerType { return analyzerpb.AnalyzerType_Postgres } +func (Analyzer) Type() analyzers.AnalyzerType { return analyzers.AnalyzerTypePostgres } func (a Analyzer) Analyze(_ context.Context, credInfo map[string]string) (*analyzers.AnalyzerResult, error) { uri, ok := credInfo["connection_string"] @@ -46,7 +45,7 @@ func secretInfoToAnalyzerResult(info *SecretInfo) *analyzers.AnalyzerResult { return nil } result := analyzers.AnalyzerResult{ - AnalyzerType: analyzerpb.AnalyzerType_Postgres, + AnalyzerType: analyzers.AnalyzerTypePostgres, Metadata: nil, Bindings: []analyzers.Binding{}, } diff --git a/pkg/analyzer/analyzers/postman/postman.go b/pkg/analyzer/analyzers/postman/postman.go index 98d088e0f7ff..8eecd5a9b257 100644 --- a/pkg/analyzer/analyzers/postman/postman.go +++ b/pkg/analyzer/analyzers/postman/postman.go @@ -12,7 +12,6 @@ import ( "github.com/jedib0t/go-pretty/table" "github.com/trufflesecurity/trufflehog/v3/pkg/analyzer/analyzers" "github.com/trufflesecurity/trufflehog/v3/pkg/analyzer/config" - "github.com/trufflesecurity/trufflehog/v3/pkg/analyzer/pb/analyzerpb" "github.com/trufflesecurity/trufflehog/v3/pkg/context" ) @@ -22,7 +21,7 @@ type Analyzer struct { Cfg *config.Config } -func (Analyzer) Type() analyzerpb.AnalyzerType { return analyzerpb.AnalyzerType_Postman } +func (Analyzer) Type() analyzers.AnalyzerType { return analyzers.AnalyzerTypePostman } func (a Analyzer) Analyze(_ context.Context, credInfo map[string]string) (*analyzers.AnalyzerResult, error) { key, ok := credInfo["key"] @@ -42,7 +41,7 @@ func secretInfoToAnalyzerResult(info *SecretInfo) *analyzers.AnalyzerResult { } result := analyzers.AnalyzerResult{ - AnalyzerType: analyzerpb.AnalyzerType_Postman, + AnalyzerType: analyzers.AnalyzerTypePostman, Metadata: nil, UnboundedResources: []analyzers.Resource{}, } diff --git a/pkg/analyzer/analyzers/sendgrid/sendgrid.go b/pkg/analyzer/analyzers/sendgrid/sendgrid.go index f924d0d68e0b..01f53254e81e 100644 --- a/pkg/analyzer/analyzers/sendgrid/sendgrid.go +++ b/pkg/analyzer/analyzers/sendgrid/sendgrid.go @@ -15,7 +15,6 @@ import ( "github.com/trufflesecurity/trufflehog/v3/pkg/analyzer/analyzers" "github.com/trufflesecurity/trufflehog/v3/pkg/analyzer/config" - "github.com/trufflesecurity/trufflehog/v3/pkg/analyzer/pb/analyzerpb" "github.com/trufflesecurity/trufflehog/v3/pkg/context" ) @@ -25,7 +24,7 @@ type Analyzer struct { Cfg *config.Config } -func (Analyzer) Type() analyzerpb.AnalyzerType { return analyzerpb.AnalyzerType_Sendgrid } +func (Analyzer) Type() analyzers.AnalyzerType { return analyzers.AnalyzerTypeSendgrid } func (a Analyzer) Analyze(_ context.Context, credInfo map[string]string) (*analyzers.AnalyzerResult, error) { key, ok := credInfo["key"] @@ -54,7 +53,7 @@ func secretInfoToAnalyzerResult(info *SecretInfo) *analyzers.AnalyzerResult { } result := analyzers.AnalyzerResult{ - AnalyzerType: analyzerpb.AnalyzerType_Sendgrid, + AnalyzerType: analyzers.AnalyzerTypeSendgrid, Metadata: map[string]any{ "key_type": keyType, "2fa_required": slices.Contains(info.RawScopes, "2fa_required"), diff --git a/pkg/analyzer/analyzers/shopify/shopify.go b/pkg/analyzer/analyzers/shopify/shopify.go index 3711baae2bc6..b69569fe8df4 100644 --- a/pkg/analyzer/analyzers/shopify/shopify.go +++ b/pkg/analyzer/analyzers/shopify/shopify.go @@ -15,7 +15,6 @@ import ( "github.com/jedib0t/go-pretty/table" "github.com/trufflesecurity/trufflehog/v3/pkg/analyzer/analyzers" "github.com/trufflesecurity/trufflehog/v3/pkg/analyzer/config" - "github.com/trufflesecurity/trufflehog/v3/pkg/analyzer/pb/analyzerpb" "github.com/trufflesecurity/trufflehog/v3/pkg/context" ) @@ -30,7 +29,7 @@ var ( categoryOrder = []string{"Analytics", "Applications", "Assigned fulfillment orders", "Browsing behavior", "Custom pixels", "Customers", "Discounts", "Discovery", "Draft orders", "Files", "Fulfillment services", "Gift cards", "Inventory", "Legal policies", "Locations", "Marketing events", "Merchant-managed fulfillment orders", "Metaobject definitions", "Metaobject entries", "Online Store navigation", "Online Store pages", "Order editing", "Orders", "Packing slip management", "Payment customizations", "Payment terms", "Pixels", "Price rules", "Product feeds", "Product listings", "Products", "Publications", "Purchase options", "Reports", "Resource feedback", "Returns", "Sales channels", "Script tags", "Shipping", "Shop locales", "Shopify Markets", "Shopify Payments accounts", "Shopify Payments bank accounts", "Shopify Payments disputes", "Shopify Payments payouts", "Store content", "Store credit account transactions", "Store credit accounts", "Themes", "Third-party fulfillment orders", "Translations", "all_cart_transforms", "all_checkout_completion_target_customizations", "cart_transforms", "cash_tracking", "companies", "custom_fulfillment_services", "customer_data_erasure", "customer_merge", "delivery_customizations", "delivery_option_generators", "discounts_allocator_functions", "fulfillment_constraint_rules", "gates", "order_submission_rules", "privacy_settings", "shopify_payments_provider_accounts_sensitive", "validations"} ) -func (Analyzer) Type() analyzerpb.AnalyzerType { return analyzerpb.AnalyzerType_Shopify } +func (Analyzer) Type() analyzers.AnalyzerType { return analyzers.AnalyzerTypeShopify } func (a Analyzer) Analyze(_ context.Context, credInfo map[string]string) (*analyzers.AnalyzerResult, error) { key, ok := credInfo["key"] @@ -55,7 +54,7 @@ func secretInfoToAnalyzerResult(info *SecretInfo) *analyzers.AnalyzerResult { return nil } result := analyzers.AnalyzerResult{ - AnalyzerType: analyzerpb.AnalyzerType_Shopify, + AnalyzerType: analyzers.AnalyzerTypeShopify, Metadata: map[string]any{ "status_code": info.StatusCode, }, diff --git a/pkg/analyzer/analyzers/slack/slack.go b/pkg/analyzer/analyzers/slack/slack.go index 9190925b6bb1..46cde734ba2a 100644 --- a/pkg/analyzer/analyzers/slack/slack.go +++ b/pkg/analyzer/analyzers/slack/slack.go @@ -15,7 +15,6 @@ import ( "github.com/jedib0t/go-pretty/table" "github.com/trufflesecurity/trufflehog/v3/pkg/analyzer/analyzers" "github.com/trufflesecurity/trufflehog/v3/pkg/analyzer/config" - "github.com/trufflesecurity/trufflehog/v3/pkg/analyzer/pb/analyzerpb" "github.com/trufflesecurity/trufflehog/v3/pkg/context" ) @@ -25,7 +24,7 @@ type Analyzer struct { Cfg *config.Config } -func (Analyzer) Type() analyzerpb.AnalyzerType { return analyzerpb.AnalyzerType_Slack } +func (Analyzer) Type() analyzers.AnalyzerType { return analyzers.AnalyzerTypeSlack } func (a Analyzer) Analyze(_ context.Context, credInfo map[string]string) (*analyzers.AnalyzerResult, error) { key, ok := credInfo["key"] @@ -45,7 +44,7 @@ func secretInfoToAnalyzerResult(info *SecretInfo) *analyzers.AnalyzerResult { return nil } result := analyzers.AnalyzerResult{ - AnalyzerType: analyzerpb.AnalyzerType_Slack, + AnalyzerType: analyzers.AnalyzerTypeSlack, Metadata: nil, } diff --git a/pkg/analyzer/analyzers/sourcegraph/sourcegraph.go b/pkg/analyzer/analyzers/sourcegraph/sourcegraph.go index 71f3d05afd9d..d9e4f95b745a 100644 --- a/pkg/analyzer/analyzers/sourcegraph/sourcegraph.go +++ b/pkg/analyzer/analyzers/sourcegraph/sourcegraph.go @@ -12,7 +12,6 @@ import ( "github.com/fatih/color" "github.com/trufflesecurity/trufflehog/v3/pkg/analyzer/analyzers" "github.com/trufflesecurity/trufflehog/v3/pkg/analyzer/config" - "github.com/trufflesecurity/trufflehog/v3/pkg/analyzer/pb/analyzerpb" "github.com/trufflesecurity/trufflehog/v3/pkg/context" ) @@ -22,7 +21,7 @@ type Analyzer struct { Cfg *config.Config } -func (Analyzer) Type() analyzerpb.AnalyzerType { return analyzerpb.AnalyzerType_Sourcegraph } +func (Analyzer) Type() analyzers.AnalyzerType { return analyzers.AnalyzerTypeSourcegraph } func (a Analyzer) Analyze(_ context.Context, credInfo map[string]string) (*analyzers.AnalyzerResult, error) { key, ok := credInfo["key"] @@ -46,7 +45,7 @@ func secretInfoToAnalyzerResult(info *SecretInfo) *analyzers.AnalyzerResult { permission = PermissionStrings[SiteAdminFull] } result := analyzers.AnalyzerResult{ - AnalyzerType: analyzerpb.AnalyzerType_Sourcegraph, + AnalyzerType: analyzers.AnalyzerTypeSourcegraph, Metadata: nil, Bindings: []analyzers.Binding{ { diff --git a/pkg/analyzer/analyzers/square/square.go b/pkg/analyzer/analyzers/square/square.go index 1f72e1969477..8fc237e88f91 100644 --- a/pkg/analyzer/analyzers/square/square.go +++ b/pkg/analyzer/analyzers/square/square.go @@ -14,7 +14,6 @@ import ( "github.com/jedib0t/go-pretty/table" "github.com/trufflesecurity/trufflehog/v3/pkg/analyzer/analyzers" "github.com/trufflesecurity/trufflehog/v3/pkg/analyzer/config" - "github.com/trufflesecurity/trufflehog/v3/pkg/analyzer/pb/analyzerpb" "github.com/trufflesecurity/trufflehog/v3/pkg/context" ) @@ -24,7 +23,7 @@ type Analyzer struct { Cfg *config.Config } -func (Analyzer) Type() analyzerpb.AnalyzerType { return analyzerpb.AnalyzerType_Square } +func (Analyzer) Type() analyzers.AnalyzerType { return analyzers.AnalyzerTypeSquare } func (a Analyzer) Analyze(_ context.Context, credInfo map[string]string) (*analyzers.AnalyzerResult, error) { key, ok := credInfo["key"] @@ -43,7 +42,7 @@ func secretInfoToAnalyzerResult(info *SecretInfo) *analyzers.AnalyzerResult { return nil } result := analyzers.AnalyzerResult{ - AnalyzerType: analyzerpb.AnalyzerType_Square, + AnalyzerType: analyzers.AnalyzerTypeSquare, UnboundedResources: []analyzers.Resource{}, Metadata: map[string]any{ "expires_at": info.Permissions.ExpiresAt, diff --git a/pkg/analyzer/analyzers/stripe/stripe.go b/pkg/analyzer/analyzers/stripe/stripe.go index ba83dc49d68b..5fae0a64922c 100644 --- a/pkg/analyzer/analyzers/stripe/stripe.go +++ b/pkg/analyzer/analyzers/stripe/stripe.go @@ -18,7 +18,6 @@ import ( "github.com/jedib0t/go-pretty/table" "github.com/trufflesecurity/trufflehog/v3/pkg/analyzer/analyzers" "github.com/trufflesecurity/trufflehog/v3/pkg/analyzer/config" - "github.com/trufflesecurity/trufflehog/v3/pkg/analyzer/pb/analyzerpb" "github.com/trufflesecurity/trufflehog/v3/pkg/context" "gopkg.in/yaml.v2" ) @@ -29,7 +28,7 @@ type Analyzer struct { Cfg *config.Config } -func (Analyzer) Type() analyzerpb.AnalyzerType { return analyzerpb.AnalyzerType_Stripe } +func (Analyzer) Type() analyzers.AnalyzerType { return analyzers.AnalyzerTypeStripe } func (a Analyzer) Analyze(_ context.Context, credInfo map[string]string) (*analyzers.AnalyzerResult, error) { key, ok := credInfo["key"] @@ -49,7 +48,7 @@ func secretInfoToAnalyzerResult(info *SecretInfo) *analyzers.AnalyzerResult { return nil } result := &analyzers.AnalyzerResult{ - AnalyzerType: analyzerpb.AnalyzerType_Stripe, + AnalyzerType: analyzers.AnalyzerTypeStripe, Metadata: map[string]any{ "key_type": info.KeyType, "key_env": info.KeyEnv, diff --git a/pkg/analyzer/analyzers/twilio/twilio.go b/pkg/analyzer/analyzers/twilio/twilio.go index 4270b861d0f6..33a49cb14278 100644 --- a/pkg/analyzer/analyzers/twilio/twilio.go +++ b/pkg/analyzer/analyzers/twilio/twilio.go @@ -11,7 +11,6 @@ import ( "github.com/fatih/color" "github.com/trufflesecurity/trufflehog/v3/pkg/analyzer/analyzers" "github.com/trufflesecurity/trufflehog/v3/pkg/analyzer/config" - "github.com/trufflesecurity/trufflehog/v3/pkg/analyzer/pb/analyzerpb" "github.com/trufflesecurity/trufflehog/v3/pkg/context" ) @@ -19,8 +18,8 @@ type Analyzer struct { Cfg *config.Config } -func (a *Analyzer) Type() analyzerpb.AnalyzerType { - return analyzerpb.AnalyzerType_Twilio +func (a *Analyzer) Type() analyzers.AnalyzerType { + return analyzers.AnalyzerTypeTwilio } func (a *Analyzer) Analyze(ctx context.Context, credentialInfo map[string]string) (*analyzers.AnalyzerResult, error) { @@ -118,7 +117,7 @@ func (a *Analyzer) Analyze(ctx context.Context, credentialInfo map[string]string } return &analyzers.AnalyzerResult{ - AnalyzerType: analyzerpb.AnalyzerType_Twilio, + AnalyzerType: analyzers.AnalyzerTypeTwilio, Bindings: bindings, }, nil } diff --git a/pkg/analyzer/cli.go b/pkg/analyzer/cli.go index 677dbc6f1f47..d3f8004e4a47 100644 --- a/pkg/analyzer/cli.go +++ b/pkg/analyzer/cli.go @@ -40,11 +40,11 @@ func Command(app *kingpin.Application) *kingpin.CmdClause { keyTypeHelp := fmt.Sprintf( "Type of key to analyze. Omit to interactively choose. Available key types: %s", - strings.Join(analyzers.AvailableAnalyzers, ", "), + strings.Join(analyzers.AvailableAnalyzers(), ", "), ) // Lowercase the available analyzers. - availableAnalyzers := make([]string, len(analyzers.AvailableAnalyzers)) - for i, a := range analyzers.AvailableAnalyzers { + availableAnalyzers := make([]string, len(analyzers.AvailableAnalyzers())) + for i, a := range analyzers.AvailableAnalyzers() { availableAnalyzers[i] = strings.ToLower(a) } analyzeKeyType = cli.Arg("key-type", keyTypeHelp).Enum(availableAnalyzers...) diff --git a/pkg/analyzer/pb/analyzerpb/analyzer.pb.go b/pkg/analyzer/pb/analyzerpb/analyzer.pb.go deleted file mode 100644 index 3e73341be6eb..000000000000 --- a/pkg/analyzer/pb/analyzerpb/analyzer.pb.go +++ /dev/null @@ -1,203 +0,0 @@ -// Code generated by protoc-gen-go. DO NOT EDIT. -// versions: -// protoc-gen-go v1.33.0 -// protoc v4.25.3 -// source: analyzer.proto - -package analyzerpb - -import ( - protoreflect "google.golang.org/protobuf/reflect/protoreflect" - protoimpl "google.golang.org/protobuf/runtime/protoimpl" - reflect "reflect" - sync "sync" -) - -const ( - // Verify that this generated code is sufficiently up-to-date. - _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) - // Verify that runtime/protoimpl is sufficiently up-to-date. - _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) -) - -type AnalyzerType int32 - -const ( - AnalyzerType_Invalid AnalyzerType = 0 - AnalyzerType_Airbrake AnalyzerType = 1 - AnalyzerType_Asana AnalyzerType = 2 - AnalyzerType_Bitbucket AnalyzerType = 3 - AnalyzerType_GitHub AnalyzerType = 4 - AnalyzerType_GitLab AnalyzerType = 5 - AnalyzerType_HuggingFace AnalyzerType = 6 - AnalyzerType_Mailchimp AnalyzerType = 7 - AnalyzerType_Mailgun AnalyzerType = 8 - AnalyzerType_MySQL AnalyzerType = 9 - AnalyzerType_OpenAI AnalyzerType = 10 - AnalyzerType_Opsgenie AnalyzerType = 11 - AnalyzerType_Postgres AnalyzerType = 12 - AnalyzerType_Postman AnalyzerType = 13 - AnalyzerType_Sendgrid AnalyzerType = 14 - AnalyzerType_Shopify AnalyzerType = 15 - AnalyzerType_Slack AnalyzerType = 16 - AnalyzerType_Sourcegraph AnalyzerType = 17 - AnalyzerType_Square AnalyzerType = 18 - AnalyzerType_Stripe AnalyzerType = 19 - AnalyzerType_Twilio AnalyzerType = 20 -) - -// Enum value maps for AnalyzerType. -var ( - AnalyzerType_name = map[int32]string{ - 0: "Invalid", - 1: "Airbrake", - 2: "Asana", - 3: "Bitbucket", - 4: "GitHub", - 5: "GitLab", - 6: "HuggingFace", - 7: "Mailchimp", - 8: "Mailgun", - 9: "MySQL", - 10: "OpenAI", - 11: "Opsgenie", - 12: "Postgres", - 13: "Postman", - 14: "Sendgrid", - 15: "Shopify", - 16: "Slack", - 17: "Sourcegraph", - 18: "Square", - 19: "Stripe", - 20: "Twilio", - } - AnalyzerType_value = map[string]int32{ - "Invalid": 0, - "Airbrake": 1, - "Asana": 2, - "Bitbucket": 3, - "GitHub": 4, - "GitLab": 5, - "HuggingFace": 6, - "Mailchimp": 7, - "Mailgun": 8, - "MySQL": 9, - "OpenAI": 10, - "Opsgenie": 11, - "Postgres": 12, - "Postman": 13, - "Sendgrid": 14, - "Shopify": 15, - "Slack": 16, - "Sourcegraph": 17, - "Square": 18, - "Stripe": 19, - "Twilio": 20, - } -) - -func (x AnalyzerType) Enum() *AnalyzerType { - p := new(AnalyzerType) - *p = x - return p -} - -func (x AnalyzerType) String() string { - return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) -} - -func (AnalyzerType) Descriptor() protoreflect.EnumDescriptor { - return file_analyzer_proto_enumTypes[0].Descriptor() -} - -func (AnalyzerType) Type() protoreflect.EnumType { - return &file_analyzer_proto_enumTypes[0] -} - -func (x AnalyzerType) Number() protoreflect.EnumNumber { - return protoreflect.EnumNumber(x) -} - -// Deprecated: Use AnalyzerType.Descriptor instead. -func (AnalyzerType) EnumDescriptor() ([]byte, []int) { - return file_analyzer_proto_rawDescGZIP(), []int{0} -} - -var File_analyzer_proto protoreflect.FileDescriptor - -var file_analyzer_proto_rawDesc = []byte{ - 0x0a, 0x0e, 0x61, 0x6e, 0x61, 0x6c, 0x79, 0x7a, 0x65, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x12, 0x08, 0x61, 0x6e, 0x61, 0x6c, 0x79, 0x7a, 0x65, 0x72, 0x2a, 0xa3, 0x02, 0x0a, 0x0c, 0x41, - 0x6e, 0x61, 0x6c, 0x79, 0x7a, 0x65, 0x72, 0x54, 0x79, 0x70, 0x65, 0x12, 0x0b, 0x0a, 0x07, 0x49, - 0x6e, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x10, 0x00, 0x12, 0x0c, 0x0a, 0x08, 0x41, 0x69, 0x72, 0x62, - 0x72, 0x61, 0x6b, 0x65, 0x10, 0x01, 0x12, 0x09, 0x0a, 0x05, 0x41, 0x73, 0x61, 0x6e, 0x61, 0x10, - 0x02, 0x12, 0x0d, 0x0a, 0x09, 0x42, 0x69, 0x74, 0x62, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x10, 0x03, - 0x12, 0x0a, 0x0a, 0x06, 0x47, 0x69, 0x74, 0x48, 0x75, 0x62, 0x10, 0x04, 0x12, 0x0a, 0x0a, 0x06, - 0x47, 0x69, 0x74, 0x4c, 0x61, 0x62, 0x10, 0x05, 0x12, 0x0f, 0x0a, 0x0b, 0x48, 0x75, 0x67, 0x67, - 0x69, 0x6e, 0x67, 0x46, 0x61, 0x63, 0x65, 0x10, 0x06, 0x12, 0x0d, 0x0a, 0x09, 0x4d, 0x61, 0x69, - 0x6c, 0x63, 0x68, 0x69, 0x6d, 0x70, 0x10, 0x07, 0x12, 0x0b, 0x0a, 0x07, 0x4d, 0x61, 0x69, 0x6c, - 0x67, 0x75, 0x6e, 0x10, 0x08, 0x12, 0x09, 0x0a, 0x05, 0x4d, 0x79, 0x53, 0x51, 0x4c, 0x10, 0x09, - 0x12, 0x0a, 0x0a, 0x06, 0x4f, 0x70, 0x65, 0x6e, 0x41, 0x49, 0x10, 0x0a, 0x12, 0x0c, 0x0a, 0x08, - 0x4f, 0x70, 0x73, 0x67, 0x65, 0x6e, 0x69, 0x65, 0x10, 0x0b, 0x12, 0x0c, 0x0a, 0x08, 0x50, 0x6f, - 0x73, 0x74, 0x67, 0x72, 0x65, 0x73, 0x10, 0x0c, 0x12, 0x0b, 0x0a, 0x07, 0x50, 0x6f, 0x73, 0x74, - 0x6d, 0x61, 0x6e, 0x10, 0x0d, 0x12, 0x0c, 0x0a, 0x08, 0x53, 0x65, 0x6e, 0x64, 0x67, 0x72, 0x69, - 0x64, 0x10, 0x0e, 0x12, 0x0b, 0x0a, 0x07, 0x53, 0x68, 0x6f, 0x70, 0x69, 0x66, 0x79, 0x10, 0x0f, - 0x12, 0x09, 0x0a, 0x05, 0x53, 0x6c, 0x61, 0x63, 0x6b, 0x10, 0x10, 0x12, 0x0f, 0x0a, 0x0b, 0x53, - 0x6f, 0x75, 0x72, 0x63, 0x65, 0x67, 0x72, 0x61, 0x70, 0x68, 0x10, 0x11, 0x12, 0x0a, 0x0a, 0x06, - 0x53, 0x71, 0x75, 0x61, 0x72, 0x65, 0x10, 0x12, 0x12, 0x0a, 0x0a, 0x06, 0x53, 0x74, 0x72, 0x69, - 0x70, 0x65, 0x10, 0x13, 0x12, 0x0a, 0x0a, 0x06, 0x54, 0x77, 0x69, 0x6c, 0x69, 0x6f, 0x10, 0x14, - 0x42, 0x45, 0x5a, 0x43, 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, 0x61, 0x6e, 0x61, 0x6c, 0x79, 0x7a, 0x65, 0x72, 0x2f, 0x70, 0x62, 0x2f, 0x61, 0x6e, 0x61, - 0x6c, 0x79, 0x7a, 0x65, 0x72, 0x70, 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, -} - -var ( - file_analyzer_proto_rawDescOnce sync.Once - file_analyzer_proto_rawDescData = file_analyzer_proto_rawDesc -) - -func file_analyzer_proto_rawDescGZIP() []byte { - file_analyzer_proto_rawDescOnce.Do(func() { - file_analyzer_proto_rawDescData = protoimpl.X.CompressGZIP(file_analyzer_proto_rawDescData) - }) - return file_analyzer_proto_rawDescData -} - -var file_analyzer_proto_enumTypes = make([]protoimpl.EnumInfo, 1) -var file_analyzer_proto_goTypes = []interface{}{ - (AnalyzerType)(0), // 0: analyzer.AnalyzerType -} -var file_analyzer_proto_depIdxs = []int32{ - 0, // [0:0] is the sub-list for method output_type - 0, // [0:0] is the sub-list for method input_type - 0, // [0:0] is the sub-list for extension type_name - 0, // [0:0] is the sub-list for extension extendee - 0, // [0:0] is the sub-list for field type_name -} - -func init() { file_analyzer_proto_init() } -func file_analyzer_proto_init() { - if File_analyzer_proto != nil { - return - } - type x struct{} - out := protoimpl.TypeBuilder{ - File: protoimpl.DescBuilder{ - GoPackagePath: reflect.TypeOf(x{}).PkgPath(), - RawDescriptor: file_analyzer_proto_rawDesc, - NumEnums: 1, - NumMessages: 0, - NumExtensions: 0, - NumServices: 0, - }, - GoTypes: file_analyzer_proto_goTypes, - DependencyIndexes: file_analyzer_proto_depIdxs, - EnumInfos: file_analyzer_proto_enumTypes, - }.Build() - File_analyzer_proto = out.File - file_analyzer_proto_rawDesc = nil - file_analyzer_proto_goTypes = nil - file_analyzer_proto_depIdxs = nil -} diff --git a/pkg/analyzer/pb/analyzerpb/analyzer.pb.validate.go b/pkg/analyzer/pb/analyzerpb/analyzer.pb.validate.go deleted file mode 100644 index c0327c9fa488..000000000000 --- a/pkg/analyzer/pb/analyzerpb/analyzer.pb.validate.go +++ /dev/null @@ -1,36 +0,0 @@ -// Code generated by protoc-gen-validate. DO NOT EDIT. -// source: analyzer.proto - -package analyzerpb - -import ( - "bytes" - "errors" - "fmt" - "net" - "net/mail" - "net/url" - "regexp" - "sort" - "strings" - "time" - "unicode/utf8" - - "google.golang.org/protobuf/types/known/anypb" -) - -// ensure the imports are used -var ( - _ = bytes.MinRead - _ = errors.New("") - _ = fmt.Print - _ = utf8.UTFMax - _ = (*regexp.Regexp)(nil) - _ = (*strings.Reader)(nil) - _ = net.IPv4len - _ = time.Duration(0) - _ = (*url.URL)(nil) - _ = (*mail.Address)(nil) - _ = anypb.Any{} - _ = sort.Sort -) diff --git a/pkg/analyzer/proto/analyzer.proto b/pkg/analyzer/proto/analyzer.proto deleted file mode 100644 index 31e32c489338..000000000000 --- a/pkg/analyzer/proto/analyzer.proto +++ /dev/null @@ -1,29 +0,0 @@ -syntax = "proto3"; - -package analyzer; - -option go_package = "github.com/trufflesecurity/trufflehog/v3/pkg/analyzer/pb/analyzerpb"; - -enum AnalyzerType { - Invalid = 0; - Airbrake = 1; - Asana = 2; - Bitbucket = 3; - GitHub = 4; - GitLab = 5; - HuggingFace = 6; - Mailchimp = 7; - Mailgun = 8; - MySQL = 9; - OpenAI = 10; - Opsgenie = 11; - Postgres = 12; - Postman = 13; - Sendgrid = 14; - Shopify = 15; - Slack = 16; - Sourcegraph = 17; - Square = 18; - Stripe = 19; - Twilio = 20; -} diff --git a/pkg/analyzer/tui/form.go b/pkg/analyzer/tui/form.go index 0c71c4ffd202..d335e5c19b8e 100644 --- a/pkg/analyzer/tui/form.go +++ b/pkg/analyzer/tui/form.go @@ -112,7 +112,7 @@ func (ui FormPage) View() string { func (ui FormPage) PrevPage() (tea.Model, tea.Cmd) { page := NewKeyTypePage(ui.Common) // Select what was previously selected. - index, ok := slices.BinarySearch(analyzers.AvailableAnalyzers, ui.KeyType) + index, ok := slices.BinarySearch(analyzers.AvailableAnalyzers(), ui.KeyType) if !ok { // Should be impossible. index = 0 diff --git a/pkg/analyzer/tui/keytype.go b/pkg/analyzer/tui/keytype.go index daf840545d63..485df873496d 100644 --- a/pkg/analyzer/tui/keytype.go +++ b/pkg/analyzer/tui/keytype.go @@ -34,8 +34,8 @@ func (ui KeyTypePage) Init() tea.Cmd { } func NewKeyTypePage(c *common.Common) KeyTypePage { - items := make([]list.Item, len(analyzers.AvailableAnalyzers)) - for i, analyzerType := range analyzers.AvailableAnalyzers { + items := make([]list.Item, len(analyzers.AvailableAnalyzers())) + for i, analyzerType := range analyzers.AvailableAnalyzers() { items[i] = KeyTypeItem(analyzerType) } delegate := list.NewDefaultDelegate() diff --git a/pkg/analyzer/tui/tui.go b/pkg/analyzer/tui/tui.go index c06f6411ac92..66954124b14d 100644 --- a/pkg/analyzer/tui/tui.go +++ b/pkg/analyzer/tui/tui.go @@ -32,7 +32,7 @@ func Run(keyType string) (string, *SecretInfo, error) { // If a keyType is provided, make sure it's in the list of AvailableAnalyzers. if keyType != "" { var found bool - for _, a := range analyzers.AvailableAnalyzers { + for _, a := range analyzers.AvailableAnalyzers() { if strings.EqualFold(a, keyType) { keyType = a found = true From 2d1dc73c9eb29d1a533fec59687df1ddcfc8a4c5 Mon Sep 17 00:00:00 2001 From: ahrav Date: Mon, 21 Oct 2024 19:54:06 -0700 Subject: [PATCH 47/76] [fix] - Inadvertent s3 body close (#3491) * fix object retrival * update comment --- pkg/sources/s3/s3.go | 21 +++++++---------- pkg/sources/s3/s3_integration_test.go | 34 ++++++++++++++++++++++++++- 2 files changed, 41 insertions(+), 14 deletions(-) diff --git a/pkg/sources/s3/s3.go b/pkg/sources/s3/s3.go index b43d2500093c..f5df0fd3a0d1 100644 --- a/pkg/sources/s3/s3.go +++ b/pkg/sources/s3/s3.go @@ -342,21 +342,16 @@ func (s *Source) pageChunker( ctx.Logger().V(2).Info("Skipped due to excessive errors") return nil } - - // Use an anonymous function to retrieve the S3 object with a dedicated timeout context. + // Make sure we use a separate context for the GetObjectWithContext call. // This ensures that the timeout is isolated and does not affect any downstream operations. (e.g. HandleFile) - getObject := func() (*s3.GetObjectOutput, error) { - const getObjectTimeout = 30 * time.Second - objCtx, cancel := context.WithTimeout(ctx, getObjectTimeout) - defer cancel() - - return client.GetObjectWithContext(objCtx, &s3.GetObjectInput{ - Bucket: &bucket, - Key: obj.Key, - }) - } + const getObjectTimeout = 30 * time.Second + objCtx, cancel := context.WithTimeout(ctx, getObjectTimeout) + defer cancel() - res, err := getObject() + res, err := client.GetObjectWithContext(objCtx, &s3.GetObjectInput{ + Bucket: &bucket, + Key: obj.Key, + }) if err != nil { if !strings.Contains(err.Error(), "AccessDenied") { ctx.Logger().Error(err, "could not get S3 object") diff --git a/pkg/sources/s3/s3_integration_test.go b/pkg/sources/s3/s3_integration_test.go index fc160af9a62a..1832eeb30c9e 100644 --- a/pkg/sources/s3/s3_integration_test.go +++ b/pkg/sources/s3/s3_integration_test.go @@ -10,9 +10,10 @@ import ( "time" "github.com/stretchr/testify/assert" + "google.golang.org/protobuf/types/known/anypb" + "github.com/trufflesecurity/trufflehog/v3/pkg/common" "github.com/trufflesecurity/trufflehog/v3/pkg/pb/credentialspb" - "google.golang.org/protobuf/types/known/anypb" "github.com/trufflesecurity/trufflehog/v3/pkg/context" "github.com/trufflesecurity/trufflehog/v3/pkg/pb/sourcespb" @@ -50,6 +51,37 @@ func TestSource_ChunksCount(t *testing.T) { assert.Greater(t, got, wantChunkCount) } +func TestSource_ChunksLarge(t *testing.T) { + ctx, cancel := context.WithTimeout(context.Background(), time.Second*30) + defer cancel() + + s := Source{} + connection := &sourcespb.S3{ + Credential: &sourcespb.S3_Unauthenticated{}, + Buckets: []string{"trufflesec-ahrav-test"}, + } + conn, err := anypb.New(connection) + if err != nil { + t.Fatal(err) + } + + err = s.Init(ctx, "test name", 0, 0, false, conn, 1) + chunksCh := make(chan *sources.Chunk) + go func() { + defer close(chunksCh) + err = s.Chunks(ctx, chunksCh) + assert.Nil(t, err) + }() + + wantChunkCount := 9637 + got := 0 + + for range chunksCh { + got++ + } + assert.Equal(t, got, wantChunkCount) +} + func TestSource_Validate(t *testing.T) { ctx, cancel := context.WithTimeout(context.Background(), time.Second*15) defer cancel() From 0b64fa0805a628bc44db6890cd729cab4eed53a4 Mon Sep 17 00:00:00 2001 From: ahrav Date: Tue, 22 Oct 2024 07:54:55 -0700 Subject: [PATCH 48/76] update error messages (#3490) Co-authored-by: Abdul Basit --- pkg/handlers/archive.go | 8 ++++++-- pkg/handlers/handlers.go | 2 +- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/pkg/handlers/archive.go b/pkg/handlers/archive.go index f5777fa52b6c..98e31ba84fd8 100644 --- a/pkg/handlers/archive.go +++ b/pkg/handlers/archive.go @@ -127,7 +127,11 @@ func (h *archiveHandler) openArchive(ctx logContext.Context, depth int, reader f ctx.Logger().V(5).Info("empty reader, skipping file") return nil } - return fmt.Errorf("error creating custom reader: %w", err) + return fmt.Errorf( + "error creating reader for decompressor with format: %s %w", + reader.format.Name(), + err, + ) } defer rdr.Close() @@ -211,7 +215,7 @@ func (h *archiveHandler) extractorHandler(archiveChan chan []byte) func(context. lCtx.Logger().V(5).Info("empty reader, skipping file") return nil } - return fmt.Errorf("error creating custom reader: %w", err) + return fmt.Errorf("error creating reader for file %s: %w", file.Name(), err) } defer rdr.Close() diff --git a/pkg/handlers/handlers.go b/pkg/handlers/handlers.go index 1561d826d0d5..1b91a5ec2978 100644 --- a/pkg/handlers/handlers.go +++ b/pkg/handlers/handlers.go @@ -281,7 +281,7 @@ func HandleFile( ctx.Logger().V(5).Info("empty reader, skipping file") return nil } - return fmt.Errorf("error creating custom reader: %w", err) + return fmt.Errorf("failed to create file reader to handle file: %w", err) } defer func() { // Ensure all data is read to prevent broken pipe. From 3f9ba20a1c3c7eb93d2b808c581451ac223b922c Mon Sep 17 00:00:00 2001 From: Sahil Silare <32628578+sahil9001@users.noreply.github.com> Date: Tue, 22 Oct 2024 21:50:12 +0530 Subject: [PATCH 49/76] fix: fixed validation logic for `cannyio` (#3482) --- pkg/detectors/cannyio/cannyio.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/pkg/detectors/cannyio/cannyio.go b/pkg/detectors/cannyio/cannyio.go index bb5ad0063893..903426d10c06 100644 --- a/pkg/detectors/cannyio/cannyio.go +++ b/pkg/detectors/cannyio/cannyio.go @@ -2,10 +2,11 @@ package cannyio import ( "context" - regexp "github.com/wasilibs/go-re2" "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" @@ -20,7 +21,7 @@ var ( client = common.SaneHttpClient() // Make sure that your group is surrounded in boundary characters such as below to reduce false positives. - keyPat = regexp.MustCompile(detectors.PrefixRegex([]string{"canny"}) + `\b([a-z0-9]{8}-[a-z0-9]{4}-[a-z0-9]{4}-[0-9]{4}-[a-z0-9]{12})\b`) + keyPat = regexp.MustCompile(detectors.PrefixRegex([]string{"canny"}) + `\b([a-z0-9]{8}-[a-z0-9]{4}-[a-z0-9]{4}-[a-z0-9]{4}-[a-z0-9]{12})\b`) ) // Keywords are used for efficiently pre-filtering chunks. From d78239c9f5f293ff44d8501b83b16f580163c93e Mon Sep 17 00:00:00 2001 From: Sahil Silare <32628578+sahil9001@users.noreply.github.com> Date: Tue, 22 Oct 2024 22:01:32 +0530 Subject: [PATCH 50/76] feat: validation & verification fix for apiscience to apimetrics (#3475) --- .../apimetrics.go} | 19 +- .../apimetrics_test.go} | 20 +- pkg/engine/defaults.go | 4 +- pkg/pb/detectorspb/detectors.pb.go | 790 +++++++++--------- proto/detectors.proto | 3 +- 5 files changed, 422 insertions(+), 414 deletions(-) rename pkg/detectors/{apiscience/apiscience.go => apimetrics/apimetrics.go} (77%) rename pkg/detectors/{apiscience/apiscience_test.go => apimetrics/apimetrics_test.go} (81%) diff --git a/pkg/detectors/apiscience/apiscience.go b/pkg/detectors/apimetrics/apimetrics.go similarity index 77% rename from pkg/detectors/apiscience/apiscience.go rename to pkg/detectors/apimetrics/apimetrics.go index cdca9c5f56c5..7cd84d3666c8 100644 --- a/pkg/detectors/apiscience/apiscience.go +++ b/pkg/detectors/apimetrics/apimetrics.go @@ -1,12 +1,13 @@ -package apiscience +package apimetrics import ( "context" "fmt" - regexp "github.com/wasilibs/go-re2" "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" @@ -21,16 +22,16 @@ var ( client = common.SaneHttpClient() // Make sure that your group is surrounded in boundary characters such as below to reduce false positives. - keyPat = regexp.MustCompile(detectors.PrefixRegex([]string{"apiscience"}) + `\b([a-bA-Z0-9\S]{22})\b`) + keyPat = regexp.MustCompile(detectors.PrefixRegex([]string{"apimetrics"}) + `\b([a-bA-Z0-9\S]{32})\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{"apiscience"} + return []string{"apimetrics"} } -// FromData will find and optionally verify ApiScience secrets in a given set of bytes. +// FromData will find and optionally verify ApiMetrics 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) @@ -43,12 +44,12 @@ func (s Scanner) FromData(ctx context.Context, verify bool, data []byte) (result resMatch := strings.TrimSpace(match[1]) s1 := detectors.Result{ - DetectorType: detectorspb.DetectorType_ApiScience, + DetectorType: detectorspb.DetectorType_ApiMetrics, Raw: []byte(resMatch), } if verify { - req, err := http.NewRequestWithContext(ctx, "GET", "https://api.apiscience.com/v1/monitors", nil) + req, err := http.NewRequestWithContext(ctx, "GET", "https://client.apimetrics.io/api/2/calls/", nil) if err != nil { continue } @@ -69,9 +70,9 @@ func (s Scanner) FromData(ctx context.Context, verify bool, data []byte) (result } func (s Scanner) Type() detectorspb.DetectorType { - return detectorspb.DetectorType_ApiScience + return detectorspb.DetectorType_ApiMetrics } func (s Scanner) Description() string { - return "ApiScience is a tool for monitoring the performance of APIs. ApiScience keys can be used to access and manage API monitors." + return "ApiMetrics is a tool for monitoring the performance of APIs. ApiMetrics keys can be used to access and manage API monitors." } diff --git a/pkg/detectors/apiscience/apiscience_test.go b/pkg/detectors/apimetrics/apimetrics_test.go similarity index 81% rename from pkg/detectors/apiscience/apiscience_test.go rename to pkg/detectors/apimetrics/apimetrics_test.go index 857fcfabb945..a16dc409337a 100644 --- a/pkg/detectors/apiscience/apiscience_test.go +++ b/pkg/detectors/apimetrics/apimetrics_test.go @@ -1,7 +1,7 @@ //go:build detectors // +build detectors -package apiscience +package apimetrics import ( "context" @@ -16,15 +16,15 @@ import ( "github.com/trufflesecurity/trufflehog/v3/pkg/pb/detectorspb" ) -func TestApiScience_FromChunk(t *testing.T) { +func TestApiMetrics_FromChunk(t *testing.T) { ctx, cancel := context.WithTimeout(context.Background(), time.Second*5) defer cancel() testSecrets, err := common.GetSecret(ctx, "trufflehog-testing", "detectors2") if err != nil { t.Fatalf("could not get test secrets from GCP: %s", err) } - secret := testSecrets.MustGetField("APISCIENCE") - inactiveSecret := testSecrets.MustGetField("APISCIENCE_INACTIVE") + secret := testSecrets.MustGetField("APIMETRICS") + inactiveSecret := testSecrets.MustGetField("APIMETRICS_INACTIVE") type args struct { ctx context.Context @@ -43,12 +43,12 @@ func TestApiScience_FromChunk(t *testing.T) { s: Scanner{}, args: args{ ctx: context.Background(), - data: []byte(fmt.Sprintf("You can find a apiscience secret %s within", secret)), + data: []byte(fmt.Sprintf("You can find a apimetrics secret %s within", secret)), verify: true, }, want: []detectors.Result{ { - DetectorType: detectorspb.DetectorType_ApiScience, + DetectorType: detectorspb.DetectorType_ApiMetrics, Verified: true, }, }, @@ -59,12 +59,12 @@ func TestApiScience_FromChunk(t *testing.T) { s: Scanner{}, args: args{ ctx: context.Background(), - data: []byte(fmt.Sprintf("You can find a apiscience secret %s within but not valid", inactiveSecret)), // the secret would satisfy the regex but not pass validation + data: []byte(fmt.Sprintf("You can find a apimetrics secret %s within but not valid", inactiveSecret)), // the secret would satisfy the regex but not pass validation verify: true, }, want: []detectors.Result{ { - DetectorType: detectorspb.DetectorType_ApiScience, + DetectorType: detectorspb.DetectorType_ApiMetrics, Verified: false, }, }, @@ -87,7 +87,7 @@ func TestApiScience_FromChunk(t *testing.T) { s := Scanner{} got, err := s.FromData(tt.args.ctx, tt.args.verify, tt.args.data) if (err != nil) != tt.wantErr { - t.Errorf("ApiScience.FromData() error = %v, wantErr %v", err, tt.wantErr) + t.Errorf("ApiMetrics.FromData() error = %v, wantErr %v", err, tt.wantErr) return } for i := range got { @@ -97,7 +97,7 @@ func TestApiScience_FromChunk(t *testing.T) { got[i].Raw = nil } if diff := pretty.Compare(got, tt.want); diff != "" { - t.Errorf("ApiScience.FromData() %s diff: (-got +want)\n%s", tt.name, diff) + t.Errorf("ApiMetrics.FromData() %s diff: (-got +want)\n%s", tt.name, diff) } }) } diff --git a/pkg/engine/defaults.go b/pkg/engine/defaults.go index 96604628c3b5..e98f2d239ba5 100644 --- a/pkg/engine/defaults.go +++ b/pkg/engine/defaults.go @@ -36,7 +36,7 @@ import ( "github.com/trufflesecurity/trufflehog/v3/pkg/detectors/apify" "github.com/trufflesecurity/trufflehog/v3/pkg/detectors/apilayer" "github.com/trufflesecurity/trufflehog/v3/pkg/detectors/apimatic" - "github.com/trufflesecurity/trufflehog/v3/pkg/detectors/apiscience" + "github.com/trufflesecurity/trufflehog/v3/pkg/detectors/apimetrics" "github.com/trufflesecurity/trufflehog/v3/pkg/detectors/apitemplate" "github.com/trufflesecurity/trufflehog/v3/pkg/detectors/appcues" "github.com/trufflesecurity/trufflehog/v3/pkg/detectors/appfollow" @@ -1368,7 +1368,6 @@ func DefaultDetectors() []detectors.Detector { livestorm.Scanner{}, // manifest.Scanner{}, formbucket.Scanner{}, - apiscience.Scanner{}, dronahq.Scanner{}, webscraper.Scanner{}, versioneye.Scanner{}, @@ -1642,6 +1641,7 @@ func DefaultDetectors() []detectors.Detector { meraki.Scanner{}, saladcloudapikey.Scanner{}, boxoauth.Scanner{}, + apimetrics.Scanner{}, } // Automatically initialize all detectors that implement diff --git a/pkg/pb/detectorspb/detectors.pb.go b/pkg/pb/detectorspb/detectors.pb.go index fabebd5dbf29..a830ec4715ce 100644 --- a/pkg/pb/detectorspb/detectors.pb.go +++ b/pkg/pb/detectorspb/detectors.pb.go @@ -737,20 +737,21 @@ const ( DetectorType_Flightstats DetectorType = 642 DetectorType_ChecIO DetectorType = 643 DetectorType_Manifest DetectorType = 644 - DetectorType_ApiScience DetectorType = 645 - DetectorType_AppSynergy DetectorType = 646 - DetectorType_Caflou DetectorType = 647 - DetectorType_Caspio DetectorType = 648 - DetectorType_ChecklyHQ DetectorType = 649 - DetectorType_CloudElements DetectorType = 650 - DetectorType_DronaHQ DetectorType = 651 - DetectorType_Enablex DetectorType = 652 - DetectorType_Fmfw DetectorType = 653 - DetectorType_GoodDay DetectorType = 654 - DetectorType_Luno DetectorType = 655 - DetectorType_Meistertask DetectorType = 656 - DetectorType_Mindmeister DetectorType = 657 - DetectorType_PeopleDataLabs DetectorType = 658 + // Deprecated: Marked as deprecated in detectors.proto. + DetectorType_ApiScience DetectorType = 645 + DetectorType_AppSynergy DetectorType = 646 + DetectorType_Caflou DetectorType = 647 + DetectorType_Caspio DetectorType = 648 + DetectorType_ChecklyHQ DetectorType = 649 + DetectorType_CloudElements DetectorType = 650 + DetectorType_DronaHQ DetectorType = 651 + DetectorType_Enablex DetectorType = 652 + DetectorType_Fmfw DetectorType = 653 + DetectorType_GoodDay DetectorType = 654 + DetectorType_Luno DetectorType = 655 + DetectorType_Meistertask DetectorType = 656 + DetectorType_Mindmeister DetectorType = 657 + DetectorType_PeopleDataLabs DetectorType = 658 // Deprecated: Marked as deprecated in detectors.proto. DetectorType_ScraperSite DetectorType = 659 DetectorType_Scrapfly DetectorType = 660 @@ -1105,6 +1106,7 @@ const ( DetectorType_SaladCloudApiKey DetectorType = 1001 DetectorType_Box DetectorType = 1002 DetectorType_BoxOauth DetectorType = 1003 + DetectorType_ApiMetrics DetectorType = 1004 ) // Enum value maps for DetectorType. @@ -2110,6 +2112,7 @@ var ( 1001: "SaladCloudApiKey", 1002: "Box", 1003: "BoxOauth", + 1004: "ApiMetrics", } DetectorType_value = map[string]int32{ "Alibaba": 0, @@ -3112,6 +3115,7 @@ var ( "SaladCloudApiKey": 1001, "Box": 1002, "BoxOauth": 1003, + "ApiMetrics": 1004, } ) @@ -3565,7 +3569,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, 0x93, 0x80, 0x01, 0x0a, 0x0c, 0x44, 0x65, 0x74, 0x65, 0x63, 0x74, 0x6f, 0x72, + 0x10, 0x04, 0x2a, 0xa8, 0x80, 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, @@ -4218,383 +4222,385 @@ var file_detectors_proto_rawDesc = []byte{ 0x0e, 0x0a, 0x09, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x50, 0x44, 0x46, 0x10, 0x81, 0x05, 0x12, 0x10, 0x0a, 0x0b, 0x46, 0x6c, 0x69, 0x67, 0x68, 0x74, 0x73, 0x74, 0x61, 0x74, 0x73, 0x10, 0x82, 0x05, 0x12, 0x0b, 0x0a, 0x06, 0x43, 0x68, 0x65, 0x63, 0x49, 0x4f, 0x10, 0x83, 0x05, 0x12, 0x0d, - 0x0a, 0x08, 0x4d, 0x61, 0x6e, 0x69, 0x66, 0x65, 0x73, 0x74, 0x10, 0x84, 0x05, 0x12, 0x0f, 0x0a, - 0x0a, 0x41, 0x70, 0x69, 0x53, 0x63, 0x69, 0x65, 0x6e, 0x63, 0x65, 0x10, 0x85, 0x05, 0x12, 0x0f, - 0x0a, 0x0a, 0x41, 0x70, 0x70, 0x53, 0x79, 0x6e, 0x65, 0x72, 0x67, 0x79, 0x10, 0x86, 0x05, 0x12, - 0x0b, 0x0a, 0x06, 0x43, 0x61, 0x66, 0x6c, 0x6f, 0x75, 0x10, 0x87, 0x05, 0x12, 0x0b, 0x0a, 0x06, - 0x43, 0x61, 0x73, 0x70, 0x69, 0x6f, 0x10, 0x88, 0x05, 0x12, 0x0e, 0x0a, 0x09, 0x43, 0x68, 0x65, - 0x63, 0x6b, 0x6c, 0x79, 0x48, 0x51, 0x10, 0x89, 0x05, 0x12, 0x12, 0x0a, 0x0d, 0x43, 0x6c, 0x6f, - 0x75, 0x64, 0x45, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x10, 0x8a, 0x05, 0x12, 0x0c, 0x0a, - 0x07, 0x44, 0x72, 0x6f, 0x6e, 0x61, 0x48, 0x51, 0x10, 0x8b, 0x05, 0x12, 0x0c, 0x0a, 0x07, 0x45, - 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x78, 0x10, 0x8c, 0x05, 0x12, 0x09, 0x0a, 0x04, 0x46, 0x6d, 0x66, - 0x77, 0x10, 0x8d, 0x05, 0x12, 0x0c, 0x0a, 0x07, 0x47, 0x6f, 0x6f, 0x64, 0x44, 0x61, 0x79, 0x10, - 0x8e, 0x05, 0x12, 0x09, 0x0a, 0x04, 0x4c, 0x75, 0x6e, 0x6f, 0x10, 0x8f, 0x05, 0x12, 0x10, 0x0a, - 0x0b, 0x4d, 0x65, 0x69, 0x73, 0x74, 0x65, 0x72, 0x74, 0x61, 0x73, 0x6b, 0x10, 0x90, 0x05, 0x12, - 0x10, 0x0a, 0x0b, 0x4d, 0x69, 0x6e, 0x64, 0x6d, 0x65, 0x69, 0x73, 0x74, 0x65, 0x72, 0x10, 0x91, - 0x05, 0x12, 0x13, 0x0a, 0x0e, 0x50, 0x65, 0x6f, 0x70, 0x6c, 0x65, 0x44, 0x61, 0x74, 0x61, 0x4c, - 0x61, 0x62, 0x73, 0x10, 0x92, 0x05, 0x12, 0x14, 0x0a, 0x0b, 0x53, 0x63, 0x72, 0x61, 0x70, 0x65, - 0x72, 0x53, 0x69, 0x74, 0x65, 0x10, 0x93, 0x05, 0x1a, 0x02, 0x08, 0x01, 0x12, 0x0d, 0x0a, 0x08, - 0x53, 0x63, 0x72, 0x61, 0x70, 0x66, 0x6c, 0x79, 0x10, 0x94, 0x05, 0x12, 0x10, 0x0a, 0x0b, 0x53, - 0x69, 0x6d, 0x70, 0x6c, 0x79, 0x4e, 0x6f, 0x74, 0x65, 0x64, 0x10, 0x95, 0x05, 0x12, 0x12, 0x0a, - 0x0d, 0x54, 0x72, 0x61, 0x76, 0x65, 0x6c, 0x50, 0x61, 0x79, 0x6f, 0x75, 0x74, 0x73, 0x10, 0x96, - 0x05, 0x12, 0x0f, 0x0a, 0x0a, 0x57, 0x65, 0x62, 0x53, 0x63, 0x72, 0x61, 0x70, 0x65, 0x72, 0x10, - 0x97, 0x05, 0x12, 0x0c, 0x0a, 0x07, 0x43, 0x6f, 0x6e, 0x76, 0x69, 0x65, 0x72, 0x10, 0x98, 0x05, - 0x12, 0x0c, 0x0a, 0x07, 0x43, 0x6f, 0x75, 0x72, 0x69, 0x65, 0x72, 0x10, 0x99, 0x05, 0x12, 0x0a, - 0x0a, 0x05, 0x44, 0x69, 0x74, 0x74, 0x6f, 0x10, 0x9a, 0x05, 0x12, 0x0a, 0x0a, 0x05, 0x46, 0x69, - 0x6e, 0x64, 0x6c, 0x10, 0x9b, 0x05, 0x12, 0x0d, 0x0a, 0x08, 0x4c, 0x65, 0x6e, 0x64, 0x66, 0x6c, - 0x6f, 0x77, 0x10, 0x9c, 0x05, 0x12, 0x0f, 0x0a, 0x0a, 0x4d, 0x6f, 0x64, 0x65, 0x72, 0x61, 0x74, - 0x69, 0x6f, 0x6e, 0x10, 0x9d, 0x05, 0x12, 0x11, 0x0a, 0x0c, 0x4f, 0x70, 0x65, 0x6e, 0x64, 0x61, - 0x74, 0x61, 0x73, 0x6f, 0x66, 0x74, 0x10, 0x9e, 0x05, 0x12, 0x0a, 0x0a, 0x05, 0x50, 0x6f, 0x64, - 0x69, 0x6f, 0x10, 0x9f, 0x05, 0x12, 0x0c, 0x0a, 0x07, 0x52, 0x6f, 0x63, 0x6b, 0x73, 0x65, 0x74, - 0x10, 0xa0, 0x05, 0x12, 0x0a, 0x0a, 0x05, 0x52, 0x6f, 0x77, 0x6e, 0x64, 0x10, 0xa1, 0x05, 0x12, - 0x0e, 0x0a, 0x09, 0x53, 0x68, 0x6f, 0x74, 0x73, 0x74, 0x61, 0x63, 0x6b, 0x10, 0xa2, 0x05, 0x12, - 0x0d, 0x0a, 0x08, 0x53, 0x77, 0x69, 0x66, 0x74, 0x79, 0x70, 0x65, 0x10, 0xa3, 0x05, 0x12, 0x0c, - 0x0a, 0x07, 0x54, 0x77, 0x69, 0x74, 0x74, 0x65, 0x72, 0x10, 0xa4, 0x05, 0x12, 0x0a, 0x0a, 0x05, - 0x48, 0x6f, 0x6e, 0x65, 0x79, 0x10, 0xa5, 0x05, 0x12, 0x0e, 0x0a, 0x09, 0x46, 0x72, 0x65, 0x73, - 0x68, 0x64, 0x65, 0x73, 0x6b, 0x10, 0xa6, 0x05, 0x12, 0x0b, 0x0a, 0x06, 0x55, 0x70, 0x77, 0x61, - 0x76, 0x65, 0x10, 0xa7, 0x05, 0x12, 0x0d, 0x0a, 0x08, 0x46, 0x6f, 0x75, 0x6e, 0x74, 0x61, 0x69, - 0x6e, 0x10, 0xa8, 0x05, 0x12, 0x0f, 0x0a, 0x0a, 0x46, 0x72, 0x65, 0x73, 0x68, 0x62, 0x6f, 0x6f, - 0x6b, 0x73, 0x10, 0xa9, 0x05, 0x12, 0x09, 0x0a, 0x04, 0x4d, 0x69, 0x74, 0x65, 0x10, 0xaa, 0x05, - 0x12, 0x0b, 0x0a, 0x06, 0x44, 0x65, 0x70, 0x75, 0x74, 0x79, 0x10, 0xab, 0x05, 0x12, 0x0c, 0x0a, - 0x07, 0x42, 0x65, 0x65, 0x62, 0x6f, 0x6c, 0x65, 0x10, 0xac, 0x05, 0x12, 0x0e, 0x0a, 0x09, 0x43, - 0x61, 0x73, 0x68, 0x62, 0x6f, 0x61, 0x72, 0x64, 0x10, 0xad, 0x05, 0x12, 0x0b, 0x0a, 0x06, 0x4b, - 0x61, 0x6e, 0x62, 0x61, 0x6e, 0x10, 0xae, 0x05, 0x12, 0x0e, 0x0a, 0x09, 0x57, 0x6f, 0x72, 0x6b, - 0x73, 0x6e, 0x61, 0x70, 0x73, 0x10, 0xaf, 0x05, 0x12, 0x10, 0x0a, 0x0b, 0x4d, 0x79, 0x49, 0x6e, - 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x73, 0x10, 0xb0, 0x05, 0x12, 0x11, 0x0a, 0x0c, 0x49, 0x6e, - 0x76, 0x6f, 0x69, 0x63, 0x65, 0x4f, 0x63, 0x65, 0x61, 0x6e, 0x10, 0xb1, 0x05, 0x12, 0x0f, 0x0a, - 0x0a, 0x53, 0x68, 0x65, 0x72, 0x70, 0x61, 0x64, 0x65, 0x73, 0x6b, 0x10, 0xb2, 0x05, 0x12, 0x0f, - 0x0a, 0x0a, 0x4d, 0x72, 0x74, 0x69, 0x63, 0x6b, 0x74, 0x6f, 0x63, 0x6b, 0x10, 0xb3, 0x05, 0x12, - 0x0d, 0x0a, 0x08, 0x43, 0x68, 0x61, 0x74, 0x66, 0x75, 0x6c, 0x65, 0x10, 0xb4, 0x05, 0x12, 0x11, - 0x0a, 0x0c, 0x41, 0x65, 0x72, 0x6f, 0x77, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x10, 0xb5, - 0x05, 0x12, 0x11, 0x0a, 0x0c, 0x45, 0x6d, 0x61, 0x69, 0x6c, 0x6f, 0x63, 0x74, 0x6f, 0x70, 0x75, - 0x73, 0x10, 0xb6, 0x05, 0x12, 0x11, 0x0a, 0x08, 0x46, 0x75, 0x73, 0x65, 0x62, 0x69, 0x6c, 0x6c, - 0x10, 0xb7, 0x05, 0x1a, 0x02, 0x08, 0x01, 0x12, 0x0f, 0x0a, 0x0a, 0x47, 0x65, 0x63, 0x6b, 0x6f, - 0x62, 0x6f, 0x61, 0x72, 0x64, 0x10, 0xb8, 0x05, 0x12, 0x0e, 0x0a, 0x09, 0x47, 0x6f, 0x73, 0x71, - 0x75, 0x61, 0x72, 0x65, 0x64, 0x10, 0xb9, 0x05, 0x12, 0x0e, 0x0a, 0x09, 0x4d, 0x6f, 0x6f, 0x6e, - 0x63, 0x6c, 0x65, 0x72, 0x6b, 0x10, 0xba, 0x05, 0x12, 0x0d, 0x0a, 0x08, 0x50, 0x61, 0x79, 0x6d, - 0x6f, 0x61, 0x70, 0x70, 0x10, 0xbb, 0x05, 0x12, 0x0b, 0x0a, 0x06, 0x4d, 0x69, 0x78, 0x6d, 0x61, - 0x78, 0x10, 0xbc, 0x05, 0x12, 0x0e, 0x0a, 0x09, 0x50, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x73, - 0x74, 0x10, 0xbd, 0x05, 0x12, 0x10, 0x0a, 0x0b, 0x52, 0x65, 0x70, 0x61, 0x69, 0x72, 0x73, 0x68, - 0x6f, 0x70, 0x72, 0x10, 0xbe, 0x05, 0x12, 0x0d, 0x0a, 0x08, 0x47, 0x6f, 0x73, 0x68, 0x69, 0x70, - 0x70, 0x6f, 0x10, 0xbf, 0x05, 0x12, 0x0b, 0x0a, 0x06, 0x53, 0x69, 0x67, 0x6f, 0x70, 0x74, 0x10, - 0xc0, 0x05, 0x12, 0x0d, 0x0a, 0x08, 0x53, 0x75, 0x67, 0x65, 0x73, 0x74, 0x65, 0x72, 0x10, 0xc1, - 0x05, 0x12, 0x0c, 0x0a, 0x07, 0x56, 0x69, 0x65, 0x77, 0x6e, 0x65, 0x6f, 0x10, 0xc2, 0x05, 0x12, - 0x0e, 0x0a, 0x09, 0x42, 0x6f, 0x6f, 0x73, 0x74, 0x4e, 0x6f, 0x74, 0x65, 0x10, 0xc3, 0x05, 0x12, - 0x10, 0x0a, 0x0b, 0x43, 0x61, 0x70, 0x74, 0x61, 0x69, 0x6e, 0x44, 0x61, 0x74, 0x61, 0x10, 0xc4, - 0x05, 0x12, 0x0e, 0x0a, 0x09, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x76, 0x69, 0x73, 0x74, 0x10, 0xc5, - 0x05, 0x12, 0x0c, 0x0a, 0x07, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x67, 0x6f, 0x10, 0xc6, 0x05, 0x12, - 0x0a, 0x0a, 0x05, 0x43, 0x6c, 0x6f, 0x7a, 0x65, 0x10, 0xc7, 0x05, 0x12, 0x0b, 0x0a, 0x06, 0x46, - 0x6f, 0x72, 0x6d, 0x49, 0x4f, 0x10, 0xc8, 0x05, 0x12, 0x0f, 0x0a, 0x0a, 0x46, 0x6f, 0x72, 0x6d, - 0x42, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x10, 0xc9, 0x05, 0x12, 0x0d, 0x0a, 0x08, 0x47, 0x6f, 0x43, - 0x61, 0x6e, 0x76, 0x61, 0x73, 0x10, 0xca, 0x05, 0x12, 0x0c, 0x0a, 0x07, 0x4d, 0x61, 0x64, 0x4b, - 0x75, 0x64, 0x75, 0x10, 0xcb, 0x05, 0x12, 0x0f, 0x0a, 0x0a, 0x4e, 0x6f, 0x7a, 0x62, 0x65, 0x54, - 0x65, 0x61, 0x6d, 0x73, 0x10, 0xcc, 0x05, 0x12, 0x0b, 0x0a, 0x06, 0x50, 0x61, 0x70, 0x79, 0x72, - 0x73, 0x10, 0xcd, 0x05, 0x12, 0x12, 0x0a, 0x0d, 0x53, 0x75, 0x70, 0x65, 0x72, 0x4e, 0x6f, 0x74, - 0x65, 0x73, 0x41, 0x50, 0x49, 0x10, 0xce, 0x05, 0x12, 0x0c, 0x0a, 0x07, 0x54, 0x61, 0x6c, 0x6c, - 0x79, 0x66, 0x79, 0x10, 0xcf, 0x05, 0x12, 0x0e, 0x0a, 0x09, 0x5a, 0x65, 0x6e, 0x6b, 0x69, 0x74, - 0x41, 0x50, 0x49, 0x10, 0xd0, 0x05, 0x12, 0x0f, 0x0a, 0x0a, 0x43, 0x6c, 0x6f, 0x75, 0x64, 0x49, - 0x6d, 0x61, 0x67, 0x65, 0x10, 0xd1, 0x05, 0x12, 0x0f, 0x0a, 0x0a, 0x55, 0x70, 0x6c, 0x6f, 0x61, - 0x64, 0x43, 0x61, 0x72, 0x65, 0x10, 0xd2, 0x05, 0x12, 0x0d, 0x0a, 0x08, 0x42, 0x6f, 0x72, 0x67, - 0x62, 0x61, 0x73, 0x65, 0x10, 0xd3, 0x05, 0x12, 0x0e, 0x0a, 0x09, 0x50, 0x69, 0x70, 0x65, 0x64, - 0x72, 0x65, 0x61, 0x6d, 0x10, 0xd4, 0x05, 0x12, 0x09, 0x0a, 0x04, 0x53, 0x69, 0x72, 0x76, 0x10, - 0xd5, 0x05, 0x12, 0x0c, 0x0a, 0x07, 0x44, 0x69, 0x66, 0x66, 0x62, 0x6f, 0x74, 0x10, 0xd6, 0x05, - 0x12, 0x10, 0x0a, 0x0b, 0x45, 0x69, 0x67, 0x68, 0x74, 0x78, 0x45, 0x69, 0x67, 0x68, 0x74, 0x10, - 0xd7, 0x05, 0x12, 0x0c, 0x0a, 0x07, 0x53, 0x65, 0x6e, 0x64, 0x6f, 0x73, 0x6f, 0x10, 0xd8, 0x05, - 0x12, 0x11, 0x0a, 0x0c, 0x50, 0x72, 0x69, 0x6e, 0x74, 0x66, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, - 0x10, 0xd9, 0x05, 0x12, 0x0e, 0x0a, 0x09, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, - 0x10, 0xda, 0x05, 0x12, 0x0f, 0x0a, 0x0a, 0x50, 0x61, 0x6e, 0x64, 0x61, 0x53, 0x63, 0x6f, 0x72, - 0x65, 0x10, 0xdb, 0x05, 0x12, 0x0a, 0x0a, 0x05, 0x50, 0x61, 0x79, 0x6d, 0x6f, 0x10, 0xdc, 0x05, - 0x12, 0x1d, 0x0a, 0x18, 0x41, 0x76, 0x61, 0x7a, 0x61, 0x50, 0x65, 0x72, 0x73, 0x6f, 0x6e, 0x61, - 0x6c, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x10, 0xdd, 0x05, 0x12, - 0x14, 0x0a, 0x0f, 0x50, 0x6c, 0x61, 0x6e, 0x76, 0x69, 0x65, 0x77, 0x4c, 0x65, 0x61, 0x6e, 0x4b, - 0x69, 0x74, 0x10, 0xde, 0x05, 0x12, 0x0e, 0x0a, 0x09, 0x4c, 0x69, 0x76, 0x65, 0x73, 0x74, 0x6f, - 0x72, 0x6d, 0x10, 0xdf, 0x05, 0x12, 0x0b, 0x0a, 0x06, 0x4b, 0x75, 0x43, 0x6f, 0x69, 0x6e, 0x10, - 0xe0, 0x05, 0x12, 0x0c, 0x0a, 0x07, 0x4d, 0x65, 0x74, 0x61, 0x41, 0x50, 0x49, 0x10, 0xe1, 0x05, - 0x12, 0x0d, 0x0a, 0x08, 0x4e, 0x69, 0x63, 0x65, 0x48, 0x61, 0x73, 0x68, 0x10, 0xe2, 0x05, 0x12, - 0x0a, 0x0a, 0x05, 0x43, 0x65, 0x78, 0x49, 0x4f, 0x10, 0xe3, 0x05, 0x12, 0x0e, 0x0a, 0x09, 0x4b, - 0x6c, 0x69, 0x70, 0x66, 0x6f, 0x6c, 0x69, 0x6f, 0x10, 0xe4, 0x05, 0x12, 0x0e, 0x0a, 0x09, 0x44, - 0x79, 0x6e, 0x61, 0x74, 0x72, 0x61, 0x63, 0x65, 0x10, 0xe5, 0x05, 0x12, 0x11, 0x0a, 0x0c, 0x4d, - 0x6f, 0x6c, 0x6c, 0x69, 0x65, 0x41, 0x50, 0x49, 0x4b, 0x65, 0x79, 0x10, 0xe6, 0x05, 0x12, 0x16, - 0x0a, 0x11, 0x4d, 0x6f, 0x6c, 0x6c, 0x69, 0x65, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x54, 0x6f, - 0x6b, 0x65, 0x6e, 0x10, 0xe7, 0x05, 0x12, 0x10, 0x0a, 0x0b, 0x42, 0x61, 0x73, 0x69, 0x73, 0x54, - 0x68, 0x65, 0x6f, 0x72, 0x79, 0x10, 0xe8, 0x05, 0x12, 0x0d, 0x0a, 0x08, 0x4e, 0x6f, 0x72, 0x64, - 0x69, 0x67, 0x65, 0x6e, 0x10, 0xe9, 0x05, 0x12, 0x1c, 0x0a, 0x17, 0x46, 0x6c, 0x61, 0x67, 0x73, - 0x6d, 0x69, 0x74, 0x68, 0x45, 0x6e, 0x76, 0x69, 0x72, 0x6f, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x4b, - 0x65, 0x79, 0x10, 0xea, 0x05, 0x12, 0x13, 0x0a, 0x0e, 0x46, 0x6c, 0x61, 0x67, 0x73, 0x6d, 0x69, - 0x74, 0x68, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x10, 0xeb, 0x05, 0x12, 0x08, 0x0a, 0x03, 0x4d, 0x75, - 0x78, 0x10, 0xec, 0x05, 0x12, 0x0b, 0x0a, 0x06, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x10, 0xed, - 0x05, 0x12, 0x0d, 0x0a, 0x08, 0x53, 0x65, 0x6e, 0x64, 0x62, 0x69, 0x72, 0x64, 0x10, 0xee, 0x05, - 0x12, 0x1c, 0x0a, 0x17, 0x53, 0x65, 0x6e, 0x64, 0x62, 0x69, 0x72, 0x64, 0x4f, 0x72, 0x67, 0x61, - 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x41, 0x50, 0x49, 0x10, 0xef, 0x05, 0x12, 0x0b, - 0x0a, 0x06, 0x4d, 0x69, 0x64, 0x69, 0x73, 0x65, 0x10, 0xf0, 0x05, 0x12, 0x0d, 0x0a, 0x08, 0x4d, - 0x6f, 0x63, 0x6b, 0x61, 0x72, 0x6f, 0x6f, 0x10, 0xf1, 0x05, 0x12, 0x0b, 0x0a, 0x06, 0x49, 0x6d, - 0x61, 0x67, 0x65, 0x34, 0x10, 0xf2, 0x05, 0x12, 0x0b, 0x0a, 0x06, 0x50, 0x69, 0x6e, 0x61, 0x74, - 0x61, 0x10, 0xf3, 0x05, 0x12, 0x11, 0x0a, 0x0c, 0x42, 0x72, 0x6f, 0x77, 0x73, 0x65, 0x72, 0x53, - 0x74, 0x61, 0x63, 0x6b, 0x10, 0xf4, 0x05, 0x12, 0x1c, 0x0a, 0x13, 0x43, 0x72, 0x6f, 0x73, 0x73, - 0x42, 0x72, 0x6f, 0x77, 0x73, 0x65, 0x72, 0x54, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x10, 0xf5, - 0x05, 0x1a, 0x02, 0x08, 0x01, 0x12, 0x0d, 0x0a, 0x08, 0x4c, 0x6f, 0x61, 0x64, 0x6d, 0x69, 0x6c, - 0x6c, 0x10, 0xf6, 0x05, 0x12, 0x0f, 0x0a, 0x0a, 0x54, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x42, - 0x6f, 0x74, 0x10, 0xf7, 0x05, 0x12, 0x10, 0x0a, 0x0b, 0x4b, 0x6e, 0x61, 0x70, 0x73, 0x61, 0x63, - 0x6b, 0x50, 0x72, 0x6f, 0x10, 0xf8, 0x05, 0x12, 0x09, 0x0a, 0x04, 0x51, 0x61, 0x73, 0x65, 0x10, - 0xf9, 0x05, 0x12, 0x0e, 0x0a, 0x09, 0x44, 0x61, 0x72, 0x65, 0x62, 0x6f, 0x6f, 0x73, 0x74, 0x10, - 0xfa, 0x05, 0x12, 0x0d, 0x0a, 0x08, 0x47, 0x54, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x78, 0x10, 0xfb, - 0x05, 0x12, 0x0d, 0x0a, 0x08, 0x48, 0x6f, 0x6c, 0x69, 0x73, 0x74, 0x69, 0x63, 0x10, 0xfc, 0x05, - 0x12, 0x0c, 0x0a, 0x07, 0x50, 0x61, 0x72, 0x73, 0x65, 0x72, 0x73, 0x10, 0xfd, 0x05, 0x12, 0x12, - 0x0a, 0x0d, 0x53, 0x63, 0x72, 0x75, 0x74, 0x69, 0x6e, 0x69, 0x7a, 0x65, 0x72, 0x43, 0x69, 0x10, - 0xfe, 0x05, 0x12, 0x0f, 0x0a, 0x0a, 0x53, 0x6f, 0x6e, 0x61, 0x72, 0x43, 0x6c, 0x6f, 0x75, 0x64, - 0x10, 0xff, 0x05, 0x12, 0x10, 0x0a, 0x0b, 0x41, 0x50, 0x49, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, - 0x74, 0x65, 0x10, 0x80, 0x06, 0x12, 0x14, 0x0a, 0x0f, 0x43, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x73, - 0x69, 0x6f, 0x6e, 0x54, 0x6f, 0x6f, 0x6c, 0x73, 0x10, 0x81, 0x06, 0x12, 0x0f, 0x0a, 0x0a, 0x43, - 0x72, 0x61, 0x66, 0x74, 0x4d, 0x79, 0x50, 0x44, 0x46, 0x10, 0x82, 0x06, 0x12, 0x0e, 0x0a, 0x09, - 0x45, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x53, 0x44, 0x4b, 0x10, 0x83, 0x06, 0x12, 0x15, 0x0a, 0x0c, - 0x47, 0x6c, 0x69, 0x74, 0x74, 0x65, 0x72, 0x6c, 0x79, 0x41, 0x50, 0x49, 0x10, 0x84, 0x06, 0x1a, - 0x02, 0x08, 0x01, 0x12, 0x0d, 0x0a, 0x08, 0x48, 0x79, 0x62, 0x69, 0x73, 0x63, 0x75, 0x73, 0x10, - 0x85, 0x06, 0x12, 0x09, 0x0a, 0x04, 0x4d, 0x69, 0x72, 0x6f, 0x10, 0x86, 0x06, 0x12, 0x0f, 0x0a, - 0x0a, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x70, 0x61, 0x67, 0x65, 0x10, 0x87, 0x06, 0x12, 0x0e, - 0x0a, 0x09, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x70, 0x61, 0x6c, 0x10, 0x88, 0x06, 0x12, 0x0d, - 0x0a, 0x08, 0x54, 0x65, 0x6c, 0x65, 0x74, 0x79, 0x70, 0x65, 0x10, 0x89, 0x06, 0x12, 0x0d, 0x0a, - 0x08, 0x54, 0x69, 0x6d, 0x65, 0x43, 0x61, 0x6d, 0x70, 0x10, 0x8a, 0x06, 0x12, 0x0d, 0x0a, 0x08, - 0x55, 0x73, 0x65, 0x72, 0x66, 0x6c, 0x6f, 0x77, 0x10, 0x8b, 0x06, 0x12, 0x0b, 0x0a, 0x06, 0x57, - 0x69, 0x73, 0x74, 0x69, 0x61, 0x10, 0x8c, 0x06, 0x12, 0x13, 0x0a, 0x0a, 0x53, 0x70, 0x6f, 0x72, - 0x74, 0x52, 0x61, 0x64, 0x61, 0x72, 0x10, 0x8d, 0x06, 0x1a, 0x02, 0x08, 0x01, 0x12, 0x10, 0x0a, - 0x0b, 0x55, 0x70, 0x74, 0x69, 0x6d, 0x65, 0x52, 0x6f, 0x62, 0x6f, 0x74, 0x10, 0x8e, 0x06, 0x12, - 0x0e, 0x0a, 0x09, 0x43, 0x6f, 0x64, 0x65, 0x71, 0x75, 0x69, 0x72, 0x79, 0x10, 0x8f, 0x06, 0x12, - 0x11, 0x0a, 0x0c, 0x45, 0x78, 0x74, 0x72, 0x61, 0x63, 0x74, 0x6f, 0x72, 0x41, 0x50, 0x49, 0x10, - 0x90, 0x06, 0x12, 0x0d, 0x0a, 0x08, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x10, 0x91, - 0x06, 0x12, 0x0e, 0x0a, 0x09, 0x4d, 0x61, 0x67, 0x69, 0x63, 0x42, 0x65, 0x6c, 0x6c, 0x10, 0x92, - 0x06, 0x12, 0x0f, 0x0a, 0x0a, 0x53, 0x74, 0x6f, 0x72, 0x6d, 0x62, 0x6f, 0x61, 0x72, 0x64, 0x10, - 0x93, 0x06, 0x12, 0x0d, 0x0a, 0x08, 0x41, 0x70, 0x69, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x10, 0x94, - 0x06, 0x12, 0x0b, 0x0a, 0x06, 0x44, 0x69, 0x73, 0x71, 0x75, 0x73, 0x10, 0x95, 0x06, 0x12, 0x0b, - 0x0a, 0x06, 0x57, 0x6f, 0x6f, 0x70, 0x72, 0x61, 0x10, 0x96, 0x06, 0x12, 0x0e, 0x0a, 0x09, 0x50, - 0x61, 0x70, 0x65, 0x72, 0x66, 0x6f, 0x72, 0x6d, 0x10, 0x97, 0x06, 0x12, 0x0c, 0x0a, 0x07, 0x47, - 0x75, 0x6d, 0x72, 0x6f, 0x61, 0x64, 0x10, 0x98, 0x06, 0x12, 0x0f, 0x0a, 0x0a, 0x50, 0x61, 0x79, - 0x64, 0x69, 0x72, 0x74, 0x61, 0x70, 0x70, 0x10, 0x99, 0x06, 0x12, 0x0e, 0x0a, 0x09, 0x44, 0x65, - 0x74, 0x65, 0x63, 0x74, 0x69, 0x66, 0x79, 0x10, 0x9a, 0x06, 0x12, 0x0f, 0x0a, 0x0a, 0x53, 0x74, - 0x61, 0x74, 0x75, 0x73, 0x63, 0x61, 0x6b, 0x65, 0x10, 0x9b, 0x06, 0x12, 0x0f, 0x0a, 0x0a, 0x4a, - 0x75, 0x6d, 0x70, 0x73, 0x65, 0x6c, 0x6c, 0x65, 0x72, 0x10, 0x9c, 0x06, 0x12, 0x0f, 0x0a, 0x0a, - 0x4c, 0x75, 0x6e, 0x63, 0x68, 0x4d, 0x6f, 0x6e, 0x65, 0x79, 0x10, 0x9d, 0x06, 0x12, 0x0c, 0x0a, - 0x07, 0x52, 0x6f, 0x73, 0x65, 0x74, 0x74, 0x65, 0x10, 0x9e, 0x06, 0x12, 0x09, 0x0a, 0x04, 0x59, - 0x65, 0x6c, 0x70, 0x10, 0x9f, 0x06, 0x12, 0x0a, 0x0a, 0x05, 0x41, 0x74, 0x65, 0x72, 0x61, 0x10, - 0xa0, 0x06, 0x12, 0x12, 0x0a, 0x0d, 0x45, 0x63, 0x6f, 0x53, 0x74, 0x72, 0x75, 0x78, 0x75, 0x72, - 0x65, 0x49, 0x54, 0x10, 0xa1, 0x06, 0x12, 0x08, 0x0a, 0x03, 0x41, 0x68, 0x61, 0x10, 0xa2, 0x06, - 0x12, 0x0d, 0x0a, 0x08, 0x50, 0x61, 0x72, 0x73, 0x65, 0x68, 0x75, 0x62, 0x10, 0xa3, 0x06, 0x12, - 0x11, 0x0a, 0x0c, 0x50, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x43, 0x6c, 0x6f, 0x75, 0x64, 0x10, - 0xa4, 0x06, 0x12, 0x0f, 0x0a, 0x0a, 0x43, 0x6c, 0x6f, 0x75, 0x64, 0x73, 0x6d, 0x69, 0x74, 0x68, - 0x10, 0xa5, 0x06, 0x12, 0x11, 0x0a, 0x08, 0x46, 0x6c, 0x6f, 0x77, 0x64, 0x61, 0x73, 0x68, 0x10, - 0xa6, 0x06, 0x1a, 0x02, 0x08, 0x01, 0x12, 0x11, 0x0a, 0x08, 0x46, 0x6c, 0x6f, 0x77, 0x64, 0x6f, - 0x63, 0x6b, 0x10, 0xa7, 0x06, 0x1a, 0x02, 0x08, 0x01, 0x12, 0x0b, 0x0a, 0x06, 0x46, 0x69, 0x62, - 0x65, 0x72, 0x79, 0x10, 0xa8, 0x06, 0x12, 0x0d, 0x0a, 0x08, 0x54, 0x79, 0x70, 0x65, 0x74, 0x61, - 0x6c, 0x6b, 0x10, 0xa9, 0x06, 0x12, 0x0e, 0x0a, 0x09, 0x56, 0x6f, 0x6f, 0x64, 0x6f, 0x6f, 0x53, - 0x4d, 0x53, 0x10, 0xaa, 0x06, 0x12, 0x0e, 0x0a, 0x09, 0x5a, 0x75, 0x6c, 0x69, 0x70, 0x43, 0x68, - 0x61, 0x74, 0x10, 0xab, 0x06, 0x12, 0x0e, 0x0a, 0x09, 0x46, 0x6f, 0x72, 0x6d, 0x63, 0x72, 0x61, - 0x66, 0x74, 0x10, 0xac, 0x06, 0x12, 0x0c, 0x0a, 0x07, 0x49, 0x65, 0x78, 0x61, 0x70, 0x69, 0x73, - 0x10, 0xad, 0x06, 0x12, 0x0e, 0x0a, 0x09, 0x52, 0x65, 0x61, 0x63, 0x68, 0x6d, 0x61, 0x69, 0x6c, - 0x10, 0xae, 0x06, 0x12, 0x0f, 0x0a, 0x0a, 0x43, 0x68, 0x61, 0x72, 0x74, 0x6d, 0x6f, 0x67, 0x75, - 0x6c, 0x10, 0xaf, 0x06, 0x12, 0x0f, 0x0a, 0x0a, 0x41, 0x70, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x65, - 0x64, 0x64, 0x10, 0xb0, 0x06, 0x12, 0x08, 0x0a, 0x03, 0x57, 0x69, 0x74, 0x10, 0xb1, 0x06, 0x12, - 0x15, 0x0a, 0x10, 0x52, 0x65, 0x63, 0x68, 0x61, 0x72, 0x67, 0x65, 0x50, 0x61, 0x79, 0x6d, 0x65, - 0x6e, 0x74, 0x73, 0x10, 0xb2, 0x06, 0x12, 0x0f, 0x0a, 0x0a, 0x44, 0x69, 0x67, 0x67, 0x65, 0x72, - 0x6e, 0x61, 0x75, 0x74, 0x10, 0xb3, 0x06, 0x12, 0x10, 0x0a, 0x0b, 0x4d, 0x6f, 0x6e, 0x6b, 0x65, - 0x79, 0x4c, 0x65, 0x61, 0x72, 0x6e, 0x10, 0xb4, 0x06, 0x12, 0x0a, 0x0a, 0x05, 0x44, 0x75, 0x70, - 0x6c, 0x79, 0x10, 0xb5, 0x06, 0x12, 0x0e, 0x0a, 0x09, 0x50, 0x6f, 0x73, 0x74, 0x62, 0x61, 0x63, - 0x6b, 0x73, 0x10, 0xb6, 0x06, 0x12, 0x0d, 0x0a, 0x08, 0x43, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, - 0x32, 0x10, 0xb7, 0x06, 0x12, 0x0c, 0x0a, 0x07, 0x5a, 0x65, 0x6e, 0x52, 0x6f, 0x77, 0x73, 0x10, - 0xb8, 0x06, 0x12, 0x10, 0x0a, 0x0b, 0x5a, 0x69, 0x70, 0x63, 0x6f, 0x64, 0x65, 0x62, 0x61, 0x73, - 0x65, 0x10, 0xb9, 0x06, 0x12, 0x0b, 0x0a, 0x06, 0x54, 0x65, 0x66, 0x74, 0x65, 0x72, 0x10, 0xba, - 0x06, 0x12, 0x0a, 0x0a, 0x05, 0x54, 0x77, 0x69, 0x73, 0x74, 0x10, 0xbb, 0x06, 0x12, 0x16, 0x0a, - 0x11, 0x42, 0x72, 0x61, 0x69, 0x6e, 0x74, 0x72, 0x65, 0x65, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, - 0x74, 0x73, 0x10, 0xbc, 0x06, 0x12, 0x11, 0x0a, 0x0c, 0x43, 0x6c, 0x6f, 0x75, 0x64, 0x43, 0x6f, - 0x6e, 0x76, 0x65, 0x72, 0x74, 0x10, 0xbd, 0x06, 0x12, 0x0c, 0x0a, 0x07, 0x47, 0x72, 0x61, 0x66, - 0x61, 0x6e, 0x61, 0x10, 0xbe, 0x06, 0x12, 0x0f, 0x0a, 0x0a, 0x43, 0x6f, 0x6e, 0x76, 0x65, 0x72, - 0x74, 0x41, 0x70, 0x69, 0x10, 0xbf, 0x06, 0x12, 0x11, 0x0a, 0x0c, 0x54, 0x72, 0x61, 0x6e, 0x73, - 0x66, 0x65, 0x72, 0x77, 0x69, 0x73, 0x65, 0x10, 0xc0, 0x06, 0x12, 0x0c, 0x0a, 0x07, 0x42, 0x75, - 0x6c, 0x6b, 0x73, 0x6d, 0x73, 0x10, 0xc1, 0x06, 0x12, 0x0c, 0x0a, 0x07, 0x44, 0x61, 0x74, 0x61, - 0x62, 0x6f, 0x78, 0x10, 0xc2, 0x06, 0x12, 0x0e, 0x0a, 0x09, 0x4f, 0x6e, 0x65, 0x73, 0x69, 0x67, - 0x6e, 0x61, 0x6c, 0x10, 0xc3, 0x06, 0x12, 0x0c, 0x0a, 0x07, 0x52, 0x65, 0x6e, 0x74, 0x6d, 0x61, - 0x6e, 0x10, 0xc4, 0x06, 0x12, 0x0c, 0x0a, 0x07, 0x50, 0x61, 0x72, 0x73, 0x65, 0x75, 0x72, 0x10, - 0xc5, 0x06, 0x12, 0x0e, 0x0a, 0x09, 0x44, 0x6f, 0x63, 0x70, 0x61, 0x72, 0x73, 0x65, 0x72, 0x10, - 0xc6, 0x06, 0x12, 0x0d, 0x0a, 0x08, 0x46, 0x6f, 0x72, 0x6d, 0x73, 0x69, 0x74, 0x65, 0x10, 0xc7, - 0x06, 0x12, 0x11, 0x0a, 0x0c, 0x54, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x74, 0x61, 0x69, 0x6c, 0x6f, - 0x72, 0x10, 0xc8, 0x06, 0x12, 0x0c, 0x0a, 0x07, 0x4c, 0x65, 0x6d, 0x6c, 0x69, 0x73, 0x74, 0x10, - 0xc9, 0x06, 0x12, 0x0c, 0x0a, 0x07, 0x50, 0x72, 0x6f, 0x64, 0x70, 0x61, 0x64, 0x10, 0xca, 0x06, - 0x12, 0x0e, 0x0a, 0x09, 0x46, 0x6f, 0x72, 0x6d, 0x73, 0x74, 0x61, 0x63, 0x6b, 0x10, 0xcb, 0x06, - 0x12, 0x10, 0x0a, 0x0b, 0x43, 0x6f, 0x64, 0x65, 0x63, 0x6c, 0x69, 0x6d, 0x61, 0x74, 0x65, 0x10, - 0xcc, 0x06, 0x12, 0x0e, 0x0a, 0x09, 0x43, 0x6f, 0x64, 0x65, 0x6d, 0x61, 0x67, 0x69, 0x63, 0x10, - 0xcd, 0x06, 0x12, 0x0a, 0x0a, 0x05, 0x56, 0x62, 0x6f, 0x75, 0x74, 0x10, 0xce, 0x06, 0x12, 0x0e, - 0x0a, 0x09, 0x4e, 0x69, 0x67, 0x68, 0x74, 0x66, 0x61, 0x6c, 0x6c, 0x10, 0xcf, 0x06, 0x12, 0x0f, - 0x0a, 0x0a, 0x46, 0x6c, 0x69, 0x67, 0x68, 0x74, 0x4c, 0x61, 0x62, 0x73, 0x10, 0xd0, 0x06, 0x12, - 0x11, 0x0a, 0x0c, 0x53, 0x70, 0x65, 0x65, 0x63, 0x68, 0x54, 0x65, 0x78, 0x74, 0x41, 0x49, 0x10, - 0xd1, 0x06, 0x12, 0x0d, 0x0a, 0x08, 0x50, 0x6f, 0x6c, 0x6c, 0x73, 0x41, 0x50, 0x49, 0x10, 0xd2, - 0x06, 0x12, 0x0b, 0x0a, 0x06, 0x53, 0x69, 0x6d, 0x46, 0x69, 0x6e, 0x10, 0xd3, 0x06, 0x12, 0x0a, - 0x0a, 0x05, 0x53, 0x63, 0x61, 0x6c, 0x72, 0x10, 0xd4, 0x06, 0x12, 0x0f, 0x0a, 0x0a, 0x4b, 0x61, - 0x6e, 0x62, 0x61, 0x6e, 0x74, 0x6f, 0x6f, 0x6c, 0x10, 0xd5, 0x06, 0x12, 0x10, 0x0a, 0x0b, 0x42, - 0x72, 0x69, 0x67, 0x68, 0x74, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x10, 0xd6, 0x06, 0x12, 0x0c, 0x0a, - 0x07, 0x48, 0x6f, 0x74, 0x77, 0x69, 0x72, 0x65, 0x10, 0xd7, 0x06, 0x12, 0x0d, 0x0a, 0x08, 0x49, - 0x6e, 0x73, 0x74, 0x61, 0x62, 0x6f, 0x74, 0x10, 0xd8, 0x06, 0x12, 0x0c, 0x0a, 0x07, 0x54, 0x69, - 0x6d, 0x65, 0x6b, 0x69, 0x74, 0x10, 0xd9, 0x06, 0x12, 0x10, 0x0a, 0x0b, 0x49, 0x6e, 0x74, 0x65, - 0x72, 0x73, 0x65, 0x6c, 0x6c, 0x65, 0x72, 0x10, 0xda, 0x06, 0x12, 0x11, 0x0a, 0x0c, 0x4d, 0x6f, - 0x6a, 0x6f, 0x68, 0x65, 0x6c, 0x70, 0x64, 0x65, 0x73, 0x6b, 0x10, 0xdb, 0x06, 0x12, 0x0f, 0x0a, - 0x0a, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x73, 0x65, 0x6e, 0x64, 0x10, 0xdc, 0x06, 0x12, 0x10, - 0x0a, 0x0b, 0x47, 0x65, 0x74, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x10, 0xdd, 0x06, - 0x12, 0x0c, 0x0a, 0x07, 0x44, 0x79, 0x6e, 0x61, 0x64, 0x6f, 0x74, 0x10, 0xde, 0x06, 0x12, 0x0a, - 0x0a, 0x05, 0x44, 0x65, 0x6d, 0x69, 0x6f, 0x10, 0xdf, 0x06, 0x12, 0x0b, 0x0a, 0x06, 0x54, 0x6f, - 0x6b, 0x65, 0x65, 0x74, 0x10, 0xe0, 0x06, 0x12, 0x11, 0x0a, 0x0c, 0x4d, 0x79, 0x65, 0x78, 0x70, - 0x65, 0x72, 0x69, 0x6d, 0x65, 0x6e, 0x74, 0x10, 0xe1, 0x06, 0x12, 0x0e, 0x0a, 0x09, 0x43, 0x6f, - 0x70, 0x79, 0x73, 0x63, 0x61, 0x70, 0x65, 0x10, 0xe2, 0x06, 0x12, 0x0d, 0x0a, 0x08, 0x42, 0x65, - 0x73, 0x6e, 0x61, 0x70, 0x70, 0x79, 0x10, 0xe3, 0x06, 0x12, 0x0e, 0x0a, 0x09, 0x53, 0x61, 0x6c, - 0x65, 0x73, 0x6d, 0x61, 0x74, 0x65, 0x10, 0xe4, 0x06, 0x12, 0x13, 0x0a, 0x0a, 0x48, 0x65, 0x61, - 0x74, 0x6d, 0x61, 0x70, 0x61, 0x70, 0x69, 0x10, 0xe5, 0x06, 0x1a, 0x02, 0x08, 0x01, 0x12, 0x11, - 0x0a, 0x0c, 0x57, 0x65, 0x62, 0x73, 0x69, 0x74, 0x65, 0x70, 0x75, 0x6c, 0x73, 0x65, 0x10, 0xe6, - 0x06, 0x12, 0x0e, 0x0a, 0x09, 0x55, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x69, 0x66, 0x79, 0x10, 0xe7, - 0x06, 0x12, 0x0c, 0x0a, 0x07, 0x43, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x74, 0x10, 0xe8, 0x06, 0x12, - 0x0d, 0x0a, 0x08, 0x50, 0x44, 0x46, 0x6d, 0x79, 0x55, 0x52, 0x4c, 0x10, 0xe9, 0x06, 0x12, 0x10, - 0x0a, 0x0b, 0x41, 0x70, 0x69, 0x32, 0x43, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x74, 0x10, 0xea, 0x06, - 0x12, 0x0d, 0x0a, 0x08, 0x4f, 0x70, 0x73, 0x67, 0x65, 0x6e, 0x69, 0x65, 0x10, 0xeb, 0x06, 0x12, - 0x0b, 0x0a, 0x06, 0x47, 0x65, 0x6d, 0x69, 0x6e, 0x69, 0x10, 0xec, 0x06, 0x12, 0x0e, 0x0a, 0x09, - 0x48, 0x6f, 0x6e, 0x65, 0x79, 0x63, 0x6f, 0x6d, 0x62, 0x10, 0xed, 0x06, 0x12, 0x14, 0x0a, 0x0f, - 0x4b, 0x61, 0x6c, 0x74, 0x75, 0x72, 0x61, 0x41, 0x70, 0x70, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x10, - 0xee, 0x06, 0x12, 0x13, 0x0a, 0x0e, 0x4b, 0x61, 0x6c, 0x74, 0x75, 0x72, 0x61, 0x53, 0x65, 0x73, - 0x73, 0x69, 0x6f, 0x6e, 0x10, 0xef, 0x06, 0x12, 0x0a, 0x0a, 0x05, 0x42, 0x69, 0x74, 0x47, 0x6f, - 0x10, 0xf0, 0x06, 0x12, 0x0d, 0x0a, 0x08, 0x4f, 0x70, 0x74, 0x69, 0x64, 0x61, 0x73, 0x68, 0x10, - 0xf1, 0x06, 0x12, 0x0a, 0x0a, 0x05, 0x49, 0x6d, 0x67, 0x69, 0x78, 0x10, 0xf2, 0x06, 0x12, 0x10, - 0x0a, 0x0b, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x54, 0x6f, 0x54, 0x65, 0x78, 0x74, 0x10, 0xf3, 0x06, - 0x12, 0x10, 0x0a, 0x0b, 0x50, 0x61, 0x67, 0x65, 0x32, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x73, 0x10, - 0xf4, 0x06, 0x12, 0x0e, 0x0a, 0x09, 0x51, 0x75, 0x69, 0x63, 0x6b, 0x62, 0x61, 0x73, 0x65, 0x10, - 0xf5, 0x06, 0x12, 0x0d, 0x0a, 0x08, 0x52, 0x65, 0x64, 0x62, 0x6f, 0x6f, 0x74, 0x68, 0x10, 0xf6, - 0x06, 0x12, 0x0b, 0x0a, 0x06, 0x4e, 0x75, 0x62, 0x65, 0x6c, 0x61, 0x10, 0xf7, 0x06, 0x12, 0x0c, - 0x0a, 0x07, 0x49, 0x6e, 0x66, 0x6f, 0x62, 0x69, 0x70, 0x10, 0xf8, 0x06, 0x12, 0x0a, 0x0a, 0x05, - 0x55, 0x70, 0x72, 0x6f, 0x63, 0x10, 0xf9, 0x06, 0x12, 0x0f, 0x0a, 0x0a, 0x53, 0x75, 0x70, 0x70, - 0x6f, 0x72, 0x74, 0x62, 0x65, 0x65, 0x10, 0xfa, 0x06, 0x12, 0x0e, 0x0a, 0x09, 0x41, 0x66, 0x74, - 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x10, 0xfb, 0x06, 0x12, 0x0c, 0x0a, 0x07, 0x45, 0x64, 0x75, - 0x73, 0x69, 0x67, 0x6e, 0x10, 0xfc, 0x06, 0x12, 0x0b, 0x0a, 0x06, 0x54, 0x65, 0x61, 0x6d, 0x75, - 0x70, 0x10, 0xfd, 0x06, 0x12, 0x0c, 0x0a, 0x07, 0x57, 0x6f, 0x72, 0x6b, 0x64, 0x61, 0x79, 0x10, - 0xfe, 0x06, 0x12, 0x0c, 0x0a, 0x07, 0x4d, 0x6f, 0x6e, 0x67, 0x6f, 0x44, 0x42, 0x10, 0xff, 0x06, - 0x12, 0x08, 0x0a, 0x03, 0x4e, 0x47, 0x43, 0x10, 0x80, 0x07, 0x12, 0x13, 0x0a, 0x0e, 0x44, 0x69, - 0x67, 0x69, 0x74, 0x61, 0x6c, 0x4f, 0x63, 0x65, 0x61, 0x6e, 0x56, 0x32, 0x10, 0x81, 0x07, 0x12, - 0x0e, 0x0a, 0x09, 0x53, 0x51, 0x4c, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x10, 0x82, 0x07, 0x12, - 0x08, 0x0a, 0x03, 0x46, 0x54, 0x50, 0x10, 0x83, 0x07, 0x12, 0x0a, 0x0a, 0x05, 0x52, 0x65, 0x64, - 0x69, 0x73, 0x10, 0x84, 0x07, 0x12, 0x09, 0x0a, 0x04, 0x4c, 0x44, 0x41, 0x50, 0x10, 0x85, 0x07, - 0x12, 0x0c, 0x0a, 0x07, 0x53, 0x68, 0x6f, 0x70, 0x69, 0x66, 0x79, 0x10, 0x86, 0x07, 0x12, 0x0d, - 0x0a, 0x08, 0x52, 0x61, 0x62, 0x62, 0x69, 0x74, 0x4d, 0x51, 0x10, 0x87, 0x07, 0x12, 0x10, 0x0a, - 0x0b, 0x43, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x52, 0x65, 0x67, 0x65, 0x78, 0x10, 0x88, 0x07, 0x12, - 0x0e, 0x0a, 0x09, 0x45, 0x74, 0x68, 0x65, 0x72, 0x73, 0x63, 0x61, 0x6e, 0x10, 0x89, 0x07, 0x12, - 0x0b, 0x0a, 0x06, 0x49, 0x6e, 0x66, 0x75, 0x72, 0x61, 0x10, 0x8a, 0x07, 0x12, 0x0c, 0x0a, 0x07, - 0x41, 0x6c, 0x63, 0x68, 0x65, 0x6d, 0x79, 0x10, 0x8b, 0x07, 0x12, 0x10, 0x0a, 0x0b, 0x42, 0x6c, - 0x6f, 0x63, 0x6b, 0x4e, 0x61, 0x74, 0x69, 0x76, 0x65, 0x10, 0x8c, 0x07, 0x12, 0x0c, 0x0a, 0x07, - 0x4d, 0x6f, 0x72, 0x61, 0x6c, 0x69, 0x73, 0x10, 0x8d, 0x07, 0x12, 0x0c, 0x0a, 0x07, 0x42, 0x73, - 0x63, 0x53, 0x63, 0x61, 0x6e, 0x10, 0x8e, 0x07, 0x12, 0x16, 0x0a, 0x0d, 0x43, 0x6f, 0x69, 0x6e, - 0x4d, 0x61, 0x72, 0x6b, 0x65, 0x74, 0x43, 0x61, 0x70, 0x10, 0x8f, 0x07, 0x1a, 0x02, 0x08, 0x01, - 0x12, 0x0a, 0x0a, 0x05, 0x50, 0x65, 0x72, 0x63, 0x79, 0x10, 0x90, 0x07, 0x12, 0x11, 0x0a, 0x0c, - 0x54, 0x69, 0x6e, 0x65, 0x73, 0x57, 0x65, 0x62, 0x68, 0x6f, 0x6f, 0x6b, 0x10, 0x91, 0x07, 0x12, - 0x0b, 0x0a, 0x06, 0x50, 0x75, 0x6c, 0x75, 0x6d, 0x69, 0x10, 0x92, 0x07, 0x12, 0x12, 0x0a, 0x0d, - 0x53, 0x75, 0x70, 0x61, 0x62, 0x61, 0x73, 0x65, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x10, 0x93, 0x07, - 0x12, 0x10, 0x0a, 0x0b, 0x4e, 0x75, 0x47, 0x65, 0x74, 0x41, 0x70, 0x69, 0x4b, 0x65, 0x79, 0x10, - 0x94, 0x07, 0x12, 0x0a, 0x0a, 0x05, 0x41, 0x69, 0x76, 0x65, 0x6e, 0x10, 0x95, 0x07, 0x12, 0x0c, - 0x0a, 0x07, 0x50, 0x72, 0x65, 0x66, 0x65, 0x63, 0x74, 0x10, 0x96, 0x07, 0x12, 0x0d, 0x0a, 0x08, - 0x44, 0x6f, 0x63, 0x75, 0x73, 0x69, 0x67, 0x6e, 0x10, 0x97, 0x07, 0x12, 0x0e, 0x0a, 0x09, 0x43, - 0x6f, 0x75, 0x63, 0x68, 0x62, 0x61, 0x73, 0x65, 0x10, 0x98, 0x07, 0x12, 0x0e, 0x0a, 0x09, 0x44, - 0x6f, 0x63, 0x6b, 0x65, 0x72, 0x68, 0x75, 0x62, 0x10, 0x99, 0x07, 0x12, 0x19, 0x0a, 0x14, 0x54, - 0x72, 0x75, 0x66, 0x66, 0x6c, 0x65, 0x68, 0x6f, 0x67, 0x45, 0x6e, 0x74, 0x65, 0x72, 0x70, 0x72, - 0x69, 0x73, 0x65, 0x10, 0x9a, 0x07, 0x12, 0x10, 0x0a, 0x0b, 0x45, 0x6e, 0x76, 0x6f, 0x79, 0x41, - 0x70, 0x69, 0x4b, 0x65, 0x79, 0x10, 0x9b, 0x07, 0x12, 0x11, 0x0a, 0x0c, 0x47, 0x69, 0x74, 0x48, - 0x75, 0x62, 0x4f, 0x61, 0x75, 0x74, 0x68, 0x32, 0x10, 0x9c, 0x07, 0x12, 0x0f, 0x0a, 0x0a, 0x53, - 0x61, 0x6c, 0x65, 0x73, 0x66, 0x6f, 0x72, 0x63, 0x65, 0x10, 0x9d, 0x07, 0x12, 0x10, 0x0a, 0x0b, - 0x48, 0x75, 0x67, 0x67, 0x69, 0x6e, 0x67, 0x46, 0x61, 0x63, 0x65, 0x10, 0x9e, 0x07, 0x12, 0x0e, - 0x0a, 0x09, 0x53, 0x6e, 0x6f, 0x77, 0x66, 0x6c, 0x61, 0x6b, 0x65, 0x10, 0x9f, 0x07, 0x12, 0x10, - 0x0a, 0x0b, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x67, 0x72, 0x61, 0x70, 0x68, 0x10, 0xa0, 0x07, - 0x12, 0x0e, 0x0a, 0x09, 0x54, 0x61, 0x69, 0x6c, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x10, 0xa1, 0x07, - 0x12, 0x10, 0x0a, 0x0b, 0x57, 0x65, 0x62, 0x33, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x10, - 0xa2, 0x07, 0x12, 0x11, 0x0a, 0x0c, 0x41, 0x7a, 0x75, 0x72, 0x65, 0x53, 0x74, 0x6f, 0x72, 0x61, - 0x67, 0x65, 0x10, 0xa3, 0x07, 0x12, 0x12, 0x0a, 0x0d, 0x50, 0x6c, 0x61, 0x6e, 0x65, 0x74, 0x53, - 0x63, 0x61, 0x6c, 0x65, 0x44, 0x62, 0x10, 0xa4, 0x07, 0x12, 0x0e, 0x0a, 0x09, 0x41, 0x6e, 0x74, - 0x68, 0x72, 0x6f, 0x70, 0x69, 0x63, 0x10, 0xa5, 0x07, 0x12, 0x09, 0x0a, 0x04, 0x52, 0x61, 0x6d, - 0x70, 0x10, 0xa6, 0x07, 0x12, 0x0c, 0x0a, 0x07, 0x4b, 0x6c, 0x61, 0x76, 0x69, 0x79, 0x6f, 0x10, - 0xa7, 0x07, 0x12, 0x14, 0x0a, 0x0f, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x67, 0x72, 0x61, 0x70, - 0x68, 0x43, 0x6f, 0x64, 0x79, 0x10, 0xa8, 0x07, 0x12, 0x0e, 0x0a, 0x09, 0x56, 0x6f, 0x69, 0x63, - 0x65, 0x66, 0x6c, 0x6f, 0x77, 0x10, 0xa9, 0x07, 0x12, 0x0c, 0x0a, 0x07, 0x50, 0x72, 0x69, 0x76, - 0x61, 0x63, 0x79, 0x10, 0xaa, 0x07, 0x12, 0x0b, 0x0a, 0x06, 0x49, 0x50, 0x49, 0x6e, 0x66, 0x6f, - 0x10, 0xab, 0x07, 0x12, 0x10, 0x0a, 0x0b, 0x49, 0x70, 0x32, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, - 0x6f, 0x6e, 0x10, 0xac, 0x07, 0x12, 0x0e, 0x0a, 0x09, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6d, 0x6f, - 0x6a, 0x6f, 0x10, 0xad, 0x07, 0x12, 0x0e, 0x0a, 0x09, 0x50, 0x6f, 0x72, 0x74, 0x61, 0x69, 0x6e, - 0x65, 0x72, 0x10, 0xae, 0x07, 0x12, 0x13, 0x0a, 0x0e, 0x50, 0x6f, 0x72, 0x74, 0x61, 0x69, 0x6e, - 0x65, 0x72, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x10, 0xaf, 0x07, 0x12, 0x0b, 0x0a, 0x06, 0x4c, 0x6f, - 0x67, 0x67, 0x6c, 0x79, 0x10, 0xb0, 0x07, 0x12, 0x0c, 0x0a, 0x07, 0x4f, 0x70, 0x65, 0x6e, 0x56, - 0x70, 0x6e, 0x10, 0xb1, 0x07, 0x12, 0x1e, 0x0a, 0x19, 0x56, 0x61, 0x67, 0x72, 0x61, 0x6e, 0x74, - 0x43, 0x6c, 0x6f, 0x75, 0x64, 0x50, 0x65, 0x72, 0x73, 0x6f, 0x6e, 0x61, 0x6c, 0x54, 0x6f, 0x6b, - 0x65, 0x6e, 0x10, 0xb2, 0x07, 0x12, 0x10, 0x0a, 0x0b, 0x42, 0x65, 0x74, 0x74, 0x65, 0x72, 0x53, - 0x74, 0x61, 0x63, 0x6b, 0x10, 0xb3, 0x07, 0x12, 0x0d, 0x0a, 0x08, 0x5a, 0x65, 0x72, 0x6f, 0x54, - 0x69, 0x65, 0x72, 0x10, 0xb4, 0x07, 0x12, 0x0e, 0x0a, 0x09, 0x41, 0x70, 0x70, 0x4f, 0x70, 0x74, - 0x69, 0x63, 0x73, 0x10, 0xb5, 0x07, 0x12, 0x0d, 0x0a, 0x08, 0x4d, 0x65, 0x74, 0x61, 0x62, 0x61, - 0x73, 0x65, 0x10, 0xb6, 0x07, 0x12, 0x11, 0x0a, 0x0c, 0x43, 0x6f, 0x69, 0x6e, 0x62, 0x61, 0x73, - 0x65, 0x57, 0x61, 0x61, 0x53, 0x10, 0xb7, 0x07, 0x12, 0x11, 0x0a, 0x0c, 0x4c, 0x65, 0x6d, 0x6f, - 0x6e, 0x53, 0x71, 0x75, 0x65, 0x65, 0x7a, 0x79, 0x10, 0xb8, 0x07, 0x12, 0x0d, 0x0a, 0x08, 0x42, - 0x75, 0x64, 0x69, 0x62, 0x61, 0x73, 0x65, 0x10, 0xb9, 0x07, 0x12, 0x0f, 0x0a, 0x0a, 0x44, 0x65, - 0x6e, 0x6f, 0x44, 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x10, 0xba, 0x07, 0x12, 0x0b, 0x0a, 0x06, 0x53, - 0x74, 0x72, 0x69, 0x70, 0x6f, 0x10, 0xbb, 0x07, 0x12, 0x0c, 0x0a, 0x07, 0x52, 0x65, 0x70, 0x6c, - 0x79, 0x49, 0x4f, 0x10, 0xbc, 0x07, 0x12, 0x0f, 0x0a, 0x0a, 0x41, 0x7a, 0x75, 0x72, 0x65, 0x42, - 0x61, 0x74, 0x63, 0x68, 0x10, 0xbd, 0x07, 0x12, 0x1b, 0x0a, 0x16, 0x41, 0x7a, 0x75, 0x72, 0x65, - 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, - 0x79, 0x10, 0xbe, 0x07, 0x12, 0x12, 0x0a, 0x0d, 0x41, 0x57, 0x53, 0x53, 0x65, 0x73, 0x73, 0x69, - 0x6f, 0x6e, 0x4b, 0x65, 0x79, 0x10, 0xbf, 0x07, 0x12, 0x09, 0x0a, 0x04, 0x43, 0x6f, 0x64, 0x61, - 0x10, 0xc0, 0x07, 0x12, 0x0b, 0x0a, 0x06, 0x4c, 0x6f, 0x67, 0x7a, 0x49, 0x4f, 0x10, 0xc1, 0x07, - 0x12, 0x0f, 0x0a, 0x0a, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x62, 0x72, 0x69, 0x74, 0x65, 0x10, 0xc2, - 0x07, 0x12, 0x1a, 0x0a, 0x15, 0x47, 0x72, 0x61, 0x66, 0x61, 0x6e, 0x61, 0x53, 0x65, 0x72, 0x76, - 0x69, 0x63, 0x65, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x10, 0xc3, 0x07, 0x12, 0x13, 0x0a, - 0x0e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x46, 0x69, 0x6e, 0x61, 0x6e, 0x63, 0x65, 0x10, - 0xc4, 0x07, 0x12, 0x0d, 0x0a, 0x08, 0x4f, 0x76, 0x65, 0x72, 0x6c, 0x6f, 0x6f, 0x70, 0x10, 0xc5, - 0x07, 0x12, 0x0a, 0x0a, 0x05, 0x4e, 0x67, 0x72, 0x6f, 0x6b, 0x10, 0xc6, 0x07, 0x12, 0x0e, 0x0a, - 0x09, 0x52, 0x65, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x65, 0x10, 0xc7, 0x07, 0x12, 0x0d, 0x0a, - 0x08, 0x50, 0x6f, 0x73, 0x74, 0x67, 0x72, 0x65, 0x73, 0x10, 0xc8, 0x07, 0x12, 0x2a, 0x0a, 0x25, - 0x41, 0x7a, 0x75, 0x72, 0x65, 0x41, 0x63, 0x74, 0x69, 0x76, 0x65, 0x44, 0x69, 0x72, 0x65, 0x63, - 0x74, 0x6f, 0x72, 0x79, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, - 0x65, 0x63, 0x72, 0x65, 0x74, 0x10, 0xc9, 0x07, 0x12, 0x20, 0x0a, 0x1b, 0x41, 0x7a, 0x75, 0x72, - 0x65, 0x43, 0x61, 0x63, 0x68, 0x65, 0x46, 0x6f, 0x72, 0x52, 0x65, 0x64, 0x69, 0x73, 0x41, 0x63, - 0x63, 0x65, 0x73, 0x73, 0x4b, 0x65, 0x79, 0x10, 0xca, 0x07, 0x12, 0x21, 0x0a, 0x1c, 0x41, 0x7a, - 0x75, 0x72, 0x65, 0x43, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x44, 0x42, 0x4b, 0x65, 0x79, 0x49, 0x64, - 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x61, 0x62, 0x6c, 0x65, 0x10, 0xcb, 0x07, 0x12, 0x23, 0x0a, - 0x1e, 0x41, 0x7a, 0x75, 0x72, 0x65, 0x44, 0x65, 0x76, 0x6f, 0x70, 0x73, 0x50, 0x65, 0x72, 0x73, - 0x6f, 0x6e, 0x61, 0x6c, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x10, - 0xcc, 0x07, 0x12, 0x15, 0x0a, 0x10, 0x41, 0x7a, 0x75, 0x72, 0x65, 0x46, 0x75, 0x6e, 0x63, 0x74, - 0x69, 0x6f, 0x6e, 0x4b, 0x65, 0x79, 0x10, 0xcd, 0x07, 0x12, 0x2c, 0x0a, 0x27, 0x41, 0x7a, 0x75, - 0x72, 0x65, 0x4d, 0x4c, 0x57, 0x65, 0x62, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x43, 0x6c, - 0x61, 0x73, 0x73, 0x69, 0x63, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x61, 0x62, 0x6c, - 0x65, 0x4b, 0x65, 0x79, 0x10, 0xce, 0x07, 0x12, 0x12, 0x0a, 0x0d, 0x41, 0x7a, 0x75, 0x72, 0x65, - 0x53, 0x61, 0x73, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x10, 0xcf, 0x07, 0x12, 0x18, 0x0a, 0x13, 0x41, - 0x7a, 0x75, 0x72, 0x65, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x41, 0x64, 0x6d, 0x69, 0x6e, 0x4b, - 0x65, 0x79, 0x10, 0xd0, 0x07, 0x12, 0x18, 0x0a, 0x13, 0x41, 0x7a, 0x75, 0x72, 0x65, 0x53, 0x65, - 0x61, 0x72, 0x63, 0x68, 0x51, 0x75, 0x65, 0x72, 0x79, 0x4b, 0x65, 0x79, 0x10, 0xd1, 0x07, 0x12, - 0x1f, 0x0a, 0x1a, 0x41, 0x7a, 0x75, 0x72, 0x65, 0x4d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, - 0x6e, 0x74, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x10, 0xd2, 0x07, - 0x12, 0x0d, 0x0a, 0x08, 0x41, 0x7a, 0x75, 0x72, 0x65, 0x53, 0x51, 0x4c, 0x10, 0xd3, 0x07, 0x12, - 0x0a, 0x0a, 0x05, 0x46, 0x6c, 0x79, 0x49, 0x4f, 0x10, 0xd4, 0x07, 0x12, 0x0e, 0x0a, 0x09, 0x42, - 0x75, 0x69, 0x6c, 0x74, 0x57, 0x69, 0x74, 0x68, 0x10, 0xd5, 0x07, 0x12, 0x0f, 0x0a, 0x0a, 0x4a, - 0x75, 0x70, 0x69, 0x74, 0x65, 0x72, 0x4f, 0x6e, 0x65, 0x10, 0xd6, 0x07, 0x12, 0x25, 0x0a, 0x20, - 0x47, 0x43, 0x50, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x44, 0x65, - 0x66, 0x61, 0x75, 0x6c, 0x74, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x73, - 0x10, 0xd7, 0x07, 0x12, 0x08, 0x0a, 0x03, 0x57, 0x69, 0x7a, 0x10, 0xd8, 0x07, 0x12, 0x0c, 0x0a, - 0x07, 0x50, 0x61, 0x67, 0x61, 0x72, 0x6d, 0x65, 0x10, 0xd9, 0x07, 0x12, 0x0c, 0x0a, 0x07, 0x4f, - 0x6e, 0x66, 0x6c, 0x65, 0x65, 0x74, 0x10, 0xda, 0x07, 0x12, 0x0c, 0x0a, 0x07, 0x49, 0x6e, 0x74, - 0x72, 0x61, 0x34, 0x32, 0x10, 0xdb, 0x07, 0x12, 0x09, 0x0a, 0x04, 0x47, 0x72, 0x6f, 0x71, 0x10, - 0xdc, 0x07, 0x12, 0x17, 0x0a, 0x12, 0x54, 0x77, 0x69, 0x74, 0x74, 0x65, 0x72, 0x43, 0x6f, 0x6e, - 0x73, 0x75, 0x6d, 0x65, 0x72, 0x6b, 0x65, 0x79, 0x10, 0xdd, 0x07, 0x12, 0x0b, 0x0a, 0x06, 0x45, - 0x72, 0x61, 0x73, 0x65, 0x72, 0x10, 0xde, 0x07, 0x12, 0x0e, 0x0a, 0x09, 0x4c, 0x61, 0x72, 0x6b, - 0x53, 0x75, 0x69, 0x74, 0x65, 0x10, 0xdf, 0x07, 0x12, 0x14, 0x0a, 0x0f, 0x4c, 0x61, 0x72, 0x6b, - 0x53, 0x75, 0x69, 0x74, 0x65, 0x41, 0x70, 0x69, 0x4b, 0x65, 0x79, 0x10, 0xe0, 0x07, 0x12, 0x0e, - 0x0a, 0x09, 0x45, 0x6e, 0x64, 0x6f, 0x72, 0x4c, 0x61, 0x62, 0x73, 0x10, 0xe1, 0x07, 0x12, 0x0f, - 0x0a, 0x0a, 0x45, 0x6c, 0x65, 0x76, 0x65, 0x6e, 0x4c, 0x61, 0x62, 0x73, 0x10, 0xe2, 0x07, 0x12, - 0x0d, 0x0a, 0x08, 0x4e, 0x65, 0x74, 0x73, 0x75, 0x69, 0x74, 0x65, 0x10, 0xe3, 0x07, 0x12, 0x14, - 0x0a, 0x0f, 0x52, 0x6f, 0x62, 0x69, 0x6e, 0x68, 0x6f, 0x6f, 0x64, 0x43, 0x72, 0x79, 0x70, 0x74, - 0x6f, 0x10, 0xe4, 0x07, 0x12, 0x0a, 0x0a, 0x05, 0x4e, 0x56, 0x41, 0x50, 0x49, 0x10, 0xe5, 0x07, - 0x12, 0x09, 0x0a, 0x04, 0x50, 0x79, 0x50, 0x49, 0x10, 0xe6, 0x07, 0x12, 0x0f, 0x0a, 0x0a, 0x52, - 0x61, 0x69, 0x6c, 0x77, 0x61, 0x79, 0x41, 0x70, 0x70, 0x10, 0xe7, 0x07, 0x12, 0x0b, 0x0a, 0x06, - 0x4d, 0x65, 0x72, 0x61, 0x6b, 0x69, 0x10, 0xe8, 0x07, 0x12, 0x15, 0x0a, 0x10, 0x53, 0x61, 0x6c, - 0x61, 0x64, 0x43, 0x6c, 0x6f, 0x75, 0x64, 0x41, 0x70, 0x69, 0x4b, 0x65, 0x79, 0x10, 0xe9, 0x07, - 0x12, 0x08, 0x0a, 0x03, 0x42, 0x6f, 0x78, 0x10, 0xea, 0x07, 0x12, 0x0d, 0x0a, 0x08, 0x42, 0x6f, - 0x78, 0x4f, 0x61, 0x75, 0x74, 0x68, 0x10, 0xeb, 0x07, 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, + 0x0a, 0x08, 0x4d, 0x61, 0x6e, 0x69, 0x66, 0x65, 0x73, 0x74, 0x10, 0x84, 0x05, 0x12, 0x13, 0x0a, + 0x0a, 0x41, 0x70, 0x69, 0x53, 0x63, 0x69, 0x65, 0x6e, 0x63, 0x65, 0x10, 0x85, 0x05, 0x1a, 0x02, + 0x08, 0x01, 0x12, 0x0f, 0x0a, 0x0a, 0x41, 0x70, 0x70, 0x53, 0x79, 0x6e, 0x65, 0x72, 0x67, 0x79, + 0x10, 0x86, 0x05, 0x12, 0x0b, 0x0a, 0x06, 0x43, 0x61, 0x66, 0x6c, 0x6f, 0x75, 0x10, 0x87, 0x05, + 0x12, 0x0b, 0x0a, 0x06, 0x43, 0x61, 0x73, 0x70, 0x69, 0x6f, 0x10, 0x88, 0x05, 0x12, 0x0e, 0x0a, + 0x09, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x6c, 0x79, 0x48, 0x51, 0x10, 0x89, 0x05, 0x12, 0x12, 0x0a, + 0x0d, 0x43, 0x6c, 0x6f, 0x75, 0x64, 0x45, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x10, 0x8a, + 0x05, 0x12, 0x0c, 0x0a, 0x07, 0x44, 0x72, 0x6f, 0x6e, 0x61, 0x48, 0x51, 0x10, 0x8b, 0x05, 0x12, + 0x0c, 0x0a, 0x07, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x78, 0x10, 0x8c, 0x05, 0x12, 0x09, 0x0a, + 0x04, 0x46, 0x6d, 0x66, 0x77, 0x10, 0x8d, 0x05, 0x12, 0x0c, 0x0a, 0x07, 0x47, 0x6f, 0x6f, 0x64, + 0x44, 0x61, 0x79, 0x10, 0x8e, 0x05, 0x12, 0x09, 0x0a, 0x04, 0x4c, 0x75, 0x6e, 0x6f, 0x10, 0x8f, + 0x05, 0x12, 0x10, 0x0a, 0x0b, 0x4d, 0x65, 0x69, 0x73, 0x74, 0x65, 0x72, 0x74, 0x61, 0x73, 0x6b, + 0x10, 0x90, 0x05, 0x12, 0x10, 0x0a, 0x0b, 0x4d, 0x69, 0x6e, 0x64, 0x6d, 0x65, 0x69, 0x73, 0x74, + 0x65, 0x72, 0x10, 0x91, 0x05, 0x12, 0x13, 0x0a, 0x0e, 0x50, 0x65, 0x6f, 0x70, 0x6c, 0x65, 0x44, + 0x61, 0x74, 0x61, 0x4c, 0x61, 0x62, 0x73, 0x10, 0x92, 0x05, 0x12, 0x14, 0x0a, 0x0b, 0x53, 0x63, + 0x72, 0x61, 0x70, 0x65, 0x72, 0x53, 0x69, 0x74, 0x65, 0x10, 0x93, 0x05, 0x1a, 0x02, 0x08, 0x01, + 0x12, 0x0d, 0x0a, 0x08, 0x53, 0x63, 0x72, 0x61, 0x70, 0x66, 0x6c, 0x79, 0x10, 0x94, 0x05, 0x12, + 0x10, 0x0a, 0x0b, 0x53, 0x69, 0x6d, 0x70, 0x6c, 0x79, 0x4e, 0x6f, 0x74, 0x65, 0x64, 0x10, 0x95, + 0x05, 0x12, 0x12, 0x0a, 0x0d, 0x54, 0x72, 0x61, 0x76, 0x65, 0x6c, 0x50, 0x61, 0x79, 0x6f, 0x75, + 0x74, 0x73, 0x10, 0x96, 0x05, 0x12, 0x0f, 0x0a, 0x0a, 0x57, 0x65, 0x62, 0x53, 0x63, 0x72, 0x61, + 0x70, 0x65, 0x72, 0x10, 0x97, 0x05, 0x12, 0x0c, 0x0a, 0x07, 0x43, 0x6f, 0x6e, 0x76, 0x69, 0x65, + 0x72, 0x10, 0x98, 0x05, 0x12, 0x0c, 0x0a, 0x07, 0x43, 0x6f, 0x75, 0x72, 0x69, 0x65, 0x72, 0x10, + 0x99, 0x05, 0x12, 0x0a, 0x0a, 0x05, 0x44, 0x69, 0x74, 0x74, 0x6f, 0x10, 0x9a, 0x05, 0x12, 0x0a, + 0x0a, 0x05, 0x46, 0x69, 0x6e, 0x64, 0x6c, 0x10, 0x9b, 0x05, 0x12, 0x0d, 0x0a, 0x08, 0x4c, 0x65, + 0x6e, 0x64, 0x66, 0x6c, 0x6f, 0x77, 0x10, 0x9c, 0x05, 0x12, 0x0f, 0x0a, 0x0a, 0x4d, 0x6f, 0x64, + 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x10, 0x9d, 0x05, 0x12, 0x11, 0x0a, 0x0c, 0x4f, 0x70, + 0x65, 0x6e, 0x64, 0x61, 0x74, 0x61, 0x73, 0x6f, 0x66, 0x74, 0x10, 0x9e, 0x05, 0x12, 0x0a, 0x0a, + 0x05, 0x50, 0x6f, 0x64, 0x69, 0x6f, 0x10, 0x9f, 0x05, 0x12, 0x0c, 0x0a, 0x07, 0x52, 0x6f, 0x63, + 0x6b, 0x73, 0x65, 0x74, 0x10, 0xa0, 0x05, 0x12, 0x0a, 0x0a, 0x05, 0x52, 0x6f, 0x77, 0x6e, 0x64, + 0x10, 0xa1, 0x05, 0x12, 0x0e, 0x0a, 0x09, 0x53, 0x68, 0x6f, 0x74, 0x73, 0x74, 0x61, 0x63, 0x6b, + 0x10, 0xa2, 0x05, 0x12, 0x0d, 0x0a, 0x08, 0x53, 0x77, 0x69, 0x66, 0x74, 0x79, 0x70, 0x65, 0x10, + 0xa3, 0x05, 0x12, 0x0c, 0x0a, 0x07, 0x54, 0x77, 0x69, 0x74, 0x74, 0x65, 0x72, 0x10, 0xa4, 0x05, + 0x12, 0x0a, 0x0a, 0x05, 0x48, 0x6f, 0x6e, 0x65, 0x79, 0x10, 0xa5, 0x05, 0x12, 0x0e, 0x0a, 0x09, + 0x46, 0x72, 0x65, 0x73, 0x68, 0x64, 0x65, 0x73, 0x6b, 0x10, 0xa6, 0x05, 0x12, 0x0b, 0x0a, 0x06, + 0x55, 0x70, 0x77, 0x61, 0x76, 0x65, 0x10, 0xa7, 0x05, 0x12, 0x0d, 0x0a, 0x08, 0x46, 0x6f, 0x75, + 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x10, 0xa8, 0x05, 0x12, 0x0f, 0x0a, 0x0a, 0x46, 0x72, 0x65, 0x73, + 0x68, 0x62, 0x6f, 0x6f, 0x6b, 0x73, 0x10, 0xa9, 0x05, 0x12, 0x09, 0x0a, 0x04, 0x4d, 0x69, 0x74, + 0x65, 0x10, 0xaa, 0x05, 0x12, 0x0b, 0x0a, 0x06, 0x44, 0x65, 0x70, 0x75, 0x74, 0x79, 0x10, 0xab, + 0x05, 0x12, 0x0c, 0x0a, 0x07, 0x42, 0x65, 0x65, 0x62, 0x6f, 0x6c, 0x65, 0x10, 0xac, 0x05, 0x12, + 0x0e, 0x0a, 0x09, 0x43, 0x61, 0x73, 0x68, 0x62, 0x6f, 0x61, 0x72, 0x64, 0x10, 0xad, 0x05, 0x12, + 0x0b, 0x0a, 0x06, 0x4b, 0x61, 0x6e, 0x62, 0x61, 0x6e, 0x10, 0xae, 0x05, 0x12, 0x0e, 0x0a, 0x09, + 0x57, 0x6f, 0x72, 0x6b, 0x73, 0x6e, 0x61, 0x70, 0x73, 0x10, 0xaf, 0x05, 0x12, 0x10, 0x0a, 0x0b, + 0x4d, 0x79, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x73, 0x10, 0xb0, 0x05, 0x12, 0x11, + 0x0a, 0x0c, 0x49, 0x6e, 0x76, 0x6f, 0x69, 0x63, 0x65, 0x4f, 0x63, 0x65, 0x61, 0x6e, 0x10, 0xb1, + 0x05, 0x12, 0x0f, 0x0a, 0x0a, 0x53, 0x68, 0x65, 0x72, 0x70, 0x61, 0x64, 0x65, 0x73, 0x6b, 0x10, + 0xb2, 0x05, 0x12, 0x0f, 0x0a, 0x0a, 0x4d, 0x72, 0x74, 0x69, 0x63, 0x6b, 0x74, 0x6f, 0x63, 0x6b, + 0x10, 0xb3, 0x05, 0x12, 0x0d, 0x0a, 0x08, 0x43, 0x68, 0x61, 0x74, 0x66, 0x75, 0x6c, 0x65, 0x10, + 0xb4, 0x05, 0x12, 0x11, 0x0a, 0x0c, 0x41, 0x65, 0x72, 0x6f, 0x77, 0x6f, 0x72, 0x6b, 0x66, 0x6c, + 0x6f, 0x77, 0x10, 0xb5, 0x05, 0x12, 0x11, 0x0a, 0x0c, 0x45, 0x6d, 0x61, 0x69, 0x6c, 0x6f, 0x63, + 0x74, 0x6f, 0x70, 0x75, 0x73, 0x10, 0xb6, 0x05, 0x12, 0x11, 0x0a, 0x08, 0x46, 0x75, 0x73, 0x65, + 0x62, 0x69, 0x6c, 0x6c, 0x10, 0xb7, 0x05, 0x1a, 0x02, 0x08, 0x01, 0x12, 0x0f, 0x0a, 0x0a, 0x47, + 0x65, 0x63, 0x6b, 0x6f, 0x62, 0x6f, 0x61, 0x72, 0x64, 0x10, 0xb8, 0x05, 0x12, 0x0e, 0x0a, 0x09, + 0x47, 0x6f, 0x73, 0x71, 0x75, 0x61, 0x72, 0x65, 0x64, 0x10, 0xb9, 0x05, 0x12, 0x0e, 0x0a, 0x09, + 0x4d, 0x6f, 0x6f, 0x6e, 0x63, 0x6c, 0x65, 0x72, 0x6b, 0x10, 0xba, 0x05, 0x12, 0x0d, 0x0a, 0x08, + 0x50, 0x61, 0x79, 0x6d, 0x6f, 0x61, 0x70, 0x70, 0x10, 0xbb, 0x05, 0x12, 0x0b, 0x0a, 0x06, 0x4d, + 0x69, 0x78, 0x6d, 0x61, 0x78, 0x10, 0xbc, 0x05, 0x12, 0x0e, 0x0a, 0x09, 0x50, 0x72, 0x6f, 0x63, + 0x65, 0x73, 0x73, 0x73, 0x74, 0x10, 0xbd, 0x05, 0x12, 0x10, 0x0a, 0x0b, 0x52, 0x65, 0x70, 0x61, + 0x69, 0x72, 0x73, 0x68, 0x6f, 0x70, 0x72, 0x10, 0xbe, 0x05, 0x12, 0x0d, 0x0a, 0x08, 0x47, 0x6f, + 0x73, 0x68, 0x69, 0x70, 0x70, 0x6f, 0x10, 0xbf, 0x05, 0x12, 0x0b, 0x0a, 0x06, 0x53, 0x69, 0x67, + 0x6f, 0x70, 0x74, 0x10, 0xc0, 0x05, 0x12, 0x0d, 0x0a, 0x08, 0x53, 0x75, 0x67, 0x65, 0x73, 0x74, + 0x65, 0x72, 0x10, 0xc1, 0x05, 0x12, 0x0c, 0x0a, 0x07, 0x56, 0x69, 0x65, 0x77, 0x6e, 0x65, 0x6f, + 0x10, 0xc2, 0x05, 0x12, 0x0e, 0x0a, 0x09, 0x42, 0x6f, 0x6f, 0x73, 0x74, 0x4e, 0x6f, 0x74, 0x65, + 0x10, 0xc3, 0x05, 0x12, 0x10, 0x0a, 0x0b, 0x43, 0x61, 0x70, 0x74, 0x61, 0x69, 0x6e, 0x44, 0x61, + 0x74, 0x61, 0x10, 0xc4, 0x05, 0x12, 0x0e, 0x0a, 0x09, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x76, 0x69, + 0x73, 0x74, 0x10, 0xc5, 0x05, 0x12, 0x0c, 0x0a, 0x07, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x67, 0x6f, + 0x10, 0xc6, 0x05, 0x12, 0x0a, 0x0a, 0x05, 0x43, 0x6c, 0x6f, 0x7a, 0x65, 0x10, 0xc7, 0x05, 0x12, + 0x0b, 0x0a, 0x06, 0x46, 0x6f, 0x72, 0x6d, 0x49, 0x4f, 0x10, 0xc8, 0x05, 0x12, 0x0f, 0x0a, 0x0a, + 0x46, 0x6f, 0x72, 0x6d, 0x42, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x10, 0xc9, 0x05, 0x12, 0x0d, 0x0a, + 0x08, 0x47, 0x6f, 0x43, 0x61, 0x6e, 0x76, 0x61, 0x73, 0x10, 0xca, 0x05, 0x12, 0x0c, 0x0a, 0x07, + 0x4d, 0x61, 0x64, 0x4b, 0x75, 0x64, 0x75, 0x10, 0xcb, 0x05, 0x12, 0x0f, 0x0a, 0x0a, 0x4e, 0x6f, + 0x7a, 0x62, 0x65, 0x54, 0x65, 0x61, 0x6d, 0x73, 0x10, 0xcc, 0x05, 0x12, 0x0b, 0x0a, 0x06, 0x50, + 0x61, 0x70, 0x79, 0x72, 0x73, 0x10, 0xcd, 0x05, 0x12, 0x12, 0x0a, 0x0d, 0x53, 0x75, 0x70, 0x65, + 0x72, 0x4e, 0x6f, 0x74, 0x65, 0x73, 0x41, 0x50, 0x49, 0x10, 0xce, 0x05, 0x12, 0x0c, 0x0a, 0x07, + 0x54, 0x61, 0x6c, 0x6c, 0x79, 0x66, 0x79, 0x10, 0xcf, 0x05, 0x12, 0x0e, 0x0a, 0x09, 0x5a, 0x65, + 0x6e, 0x6b, 0x69, 0x74, 0x41, 0x50, 0x49, 0x10, 0xd0, 0x05, 0x12, 0x0f, 0x0a, 0x0a, 0x43, 0x6c, + 0x6f, 0x75, 0x64, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x10, 0xd1, 0x05, 0x12, 0x0f, 0x0a, 0x0a, 0x55, + 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x43, 0x61, 0x72, 0x65, 0x10, 0xd2, 0x05, 0x12, 0x0d, 0x0a, 0x08, + 0x42, 0x6f, 0x72, 0x67, 0x62, 0x61, 0x73, 0x65, 0x10, 0xd3, 0x05, 0x12, 0x0e, 0x0a, 0x09, 0x50, + 0x69, 0x70, 0x65, 0x64, 0x72, 0x65, 0x61, 0x6d, 0x10, 0xd4, 0x05, 0x12, 0x09, 0x0a, 0x04, 0x53, + 0x69, 0x72, 0x76, 0x10, 0xd5, 0x05, 0x12, 0x0c, 0x0a, 0x07, 0x44, 0x69, 0x66, 0x66, 0x62, 0x6f, + 0x74, 0x10, 0xd6, 0x05, 0x12, 0x10, 0x0a, 0x0b, 0x45, 0x69, 0x67, 0x68, 0x74, 0x78, 0x45, 0x69, + 0x67, 0x68, 0x74, 0x10, 0xd7, 0x05, 0x12, 0x0c, 0x0a, 0x07, 0x53, 0x65, 0x6e, 0x64, 0x6f, 0x73, + 0x6f, 0x10, 0xd8, 0x05, 0x12, 0x11, 0x0a, 0x0c, 0x50, 0x72, 0x69, 0x6e, 0x74, 0x66, 0x65, 0x63, + 0x74, 0x69, 0x6f, 0x6e, 0x10, 0xd9, 0x05, 0x12, 0x0e, 0x0a, 0x09, 0x41, 0x75, 0x74, 0x68, 0x6f, + 0x72, 0x69, 0x7a, 0x65, 0x10, 0xda, 0x05, 0x12, 0x0f, 0x0a, 0x0a, 0x50, 0x61, 0x6e, 0x64, 0x61, + 0x53, 0x63, 0x6f, 0x72, 0x65, 0x10, 0xdb, 0x05, 0x12, 0x0a, 0x0a, 0x05, 0x50, 0x61, 0x79, 0x6d, + 0x6f, 0x10, 0xdc, 0x05, 0x12, 0x1d, 0x0a, 0x18, 0x41, 0x76, 0x61, 0x7a, 0x61, 0x50, 0x65, 0x72, + 0x73, 0x6f, 0x6e, 0x61, 0x6c, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x54, 0x6f, 0x6b, 0x65, 0x6e, + 0x10, 0xdd, 0x05, 0x12, 0x14, 0x0a, 0x0f, 0x50, 0x6c, 0x61, 0x6e, 0x76, 0x69, 0x65, 0x77, 0x4c, + 0x65, 0x61, 0x6e, 0x4b, 0x69, 0x74, 0x10, 0xde, 0x05, 0x12, 0x0e, 0x0a, 0x09, 0x4c, 0x69, 0x76, + 0x65, 0x73, 0x74, 0x6f, 0x72, 0x6d, 0x10, 0xdf, 0x05, 0x12, 0x0b, 0x0a, 0x06, 0x4b, 0x75, 0x43, + 0x6f, 0x69, 0x6e, 0x10, 0xe0, 0x05, 0x12, 0x0c, 0x0a, 0x07, 0x4d, 0x65, 0x74, 0x61, 0x41, 0x50, + 0x49, 0x10, 0xe1, 0x05, 0x12, 0x0d, 0x0a, 0x08, 0x4e, 0x69, 0x63, 0x65, 0x48, 0x61, 0x73, 0x68, + 0x10, 0xe2, 0x05, 0x12, 0x0a, 0x0a, 0x05, 0x43, 0x65, 0x78, 0x49, 0x4f, 0x10, 0xe3, 0x05, 0x12, + 0x0e, 0x0a, 0x09, 0x4b, 0x6c, 0x69, 0x70, 0x66, 0x6f, 0x6c, 0x69, 0x6f, 0x10, 0xe4, 0x05, 0x12, + 0x0e, 0x0a, 0x09, 0x44, 0x79, 0x6e, 0x61, 0x74, 0x72, 0x61, 0x63, 0x65, 0x10, 0xe5, 0x05, 0x12, + 0x11, 0x0a, 0x0c, 0x4d, 0x6f, 0x6c, 0x6c, 0x69, 0x65, 0x41, 0x50, 0x49, 0x4b, 0x65, 0x79, 0x10, + 0xe6, 0x05, 0x12, 0x16, 0x0a, 0x11, 0x4d, 0x6f, 0x6c, 0x6c, 0x69, 0x65, 0x41, 0x63, 0x63, 0x65, + 0x73, 0x73, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x10, 0xe7, 0x05, 0x12, 0x10, 0x0a, 0x0b, 0x42, 0x61, + 0x73, 0x69, 0x73, 0x54, 0x68, 0x65, 0x6f, 0x72, 0x79, 0x10, 0xe8, 0x05, 0x12, 0x0d, 0x0a, 0x08, + 0x4e, 0x6f, 0x72, 0x64, 0x69, 0x67, 0x65, 0x6e, 0x10, 0xe9, 0x05, 0x12, 0x1c, 0x0a, 0x17, 0x46, + 0x6c, 0x61, 0x67, 0x73, 0x6d, 0x69, 0x74, 0x68, 0x45, 0x6e, 0x76, 0x69, 0x72, 0x6f, 0x6e, 0x6d, + 0x65, 0x6e, 0x74, 0x4b, 0x65, 0x79, 0x10, 0xea, 0x05, 0x12, 0x13, 0x0a, 0x0e, 0x46, 0x6c, 0x61, + 0x67, 0x73, 0x6d, 0x69, 0x74, 0x68, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x10, 0xeb, 0x05, 0x12, 0x08, + 0x0a, 0x03, 0x4d, 0x75, 0x78, 0x10, 0xec, 0x05, 0x12, 0x0b, 0x0a, 0x06, 0x43, 0x6f, 0x6c, 0x75, + 0x6d, 0x6e, 0x10, 0xed, 0x05, 0x12, 0x0d, 0x0a, 0x08, 0x53, 0x65, 0x6e, 0x64, 0x62, 0x69, 0x72, + 0x64, 0x10, 0xee, 0x05, 0x12, 0x1c, 0x0a, 0x17, 0x53, 0x65, 0x6e, 0x64, 0x62, 0x69, 0x72, 0x64, + 0x4f, 0x72, 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x41, 0x50, 0x49, 0x10, + 0xef, 0x05, 0x12, 0x0b, 0x0a, 0x06, 0x4d, 0x69, 0x64, 0x69, 0x73, 0x65, 0x10, 0xf0, 0x05, 0x12, + 0x0d, 0x0a, 0x08, 0x4d, 0x6f, 0x63, 0x6b, 0x61, 0x72, 0x6f, 0x6f, 0x10, 0xf1, 0x05, 0x12, 0x0b, + 0x0a, 0x06, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x34, 0x10, 0xf2, 0x05, 0x12, 0x0b, 0x0a, 0x06, 0x50, + 0x69, 0x6e, 0x61, 0x74, 0x61, 0x10, 0xf3, 0x05, 0x12, 0x11, 0x0a, 0x0c, 0x42, 0x72, 0x6f, 0x77, + 0x73, 0x65, 0x72, 0x53, 0x74, 0x61, 0x63, 0x6b, 0x10, 0xf4, 0x05, 0x12, 0x1c, 0x0a, 0x13, 0x43, + 0x72, 0x6f, 0x73, 0x73, 0x42, 0x72, 0x6f, 0x77, 0x73, 0x65, 0x72, 0x54, 0x65, 0x73, 0x74, 0x69, + 0x6e, 0x67, 0x10, 0xf5, 0x05, 0x1a, 0x02, 0x08, 0x01, 0x12, 0x0d, 0x0a, 0x08, 0x4c, 0x6f, 0x61, + 0x64, 0x6d, 0x69, 0x6c, 0x6c, 0x10, 0xf6, 0x05, 0x12, 0x0f, 0x0a, 0x0a, 0x54, 0x65, 0x73, 0x74, + 0x69, 0x6e, 0x67, 0x42, 0x6f, 0x74, 0x10, 0xf7, 0x05, 0x12, 0x10, 0x0a, 0x0b, 0x4b, 0x6e, 0x61, + 0x70, 0x73, 0x61, 0x63, 0x6b, 0x50, 0x72, 0x6f, 0x10, 0xf8, 0x05, 0x12, 0x09, 0x0a, 0x04, 0x51, + 0x61, 0x73, 0x65, 0x10, 0xf9, 0x05, 0x12, 0x0e, 0x0a, 0x09, 0x44, 0x61, 0x72, 0x65, 0x62, 0x6f, + 0x6f, 0x73, 0x74, 0x10, 0xfa, 0x05, 0x12, 0x0d, 0x0a, 0x08, 0x47, 0x54, 0x4d, 0x65, 0x74, 0x72, + 0x69, 0x78, 0x10, 0xfb, 0x05, 0x12, 0x0d, 0x0a, 0x08, 0x48, 0x6f, 0x6c, 0x69, 0x73, 0x74, 0x69, + 0x63, 0x10, 0xfc, 0x05, 0x12, 0x0c, 0x0a, 0x07, 0x50, 0x61, 0x72, 0x73, 0x65, 0x72, 0x73, 0x10, + 0xfd, 0x05, 0x12, 0x12, 0x0a, 0x0d, 0x53, 0x63, 0x72, 0x75, 0x74, 0x69, 0x6e, 0x69, 0x7a, 0x65, + 0x72, 0x43, 0x69, 0x10, 0xfe, 0x05, 0x12, 0x0f, 0x0a, 0x0a, 0x53, 0x6f, 0x6e, 0x61, 0x72, 0x43, + 0x6c, 0x6f, 0x75, 0x64, 0x10, 0xff, 0x05, 0x12, 0x10, 0x0a, 0x0b, 0x41, 0x50, 0x49, 0x54, 0x65, + 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x10, 0x80, 0x06, 0x12, 0x14, 0x0a, 0x0f, 0x43, 0x6f, 0x6e, + 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x54, 0x6f, 0x6f, 0x6c, 0x73, 0x10, 0x81, 0x06, 0x12, + 0x0f, 0x0a, 0x0a, 0x43, 0x72, 0x61, 0x66, 0x74, 0x4d, 0x79, 0x50, 0x44, 0x46, 0x10, 0x82, 0x06, + 0x12, 0x0e, 0x0a, 0x09, 0x45, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x53, 0x44, 0x4b, 0x10, 0x83, 0x06, + 0x12, 0x15, 0x0a, 0x0c, 0x47, 0x6c, 0x69, 0x74, 0x74, 0x65, 0x72, 0x6c, 0x79, 0x41, 0x50, 0x49, + 0x10, 0x84, 0x06, 0x1a, 0x02, 0x08, 0x01, 0x12, 0x0d, 0x0a, 0x08, 0x48, 0x79, 0x62, 0x69, 0x73, + 0x63, 0x75, 0x73, 0x10, 0x85, 0x06, 0x12, 0x09, 0x0a, 0x04, 0x4d, 0x69, 0x72, 0x6f, 0x10, 0x86, + 0x06, 0x12, 0x0f, 0x0a, 0x0a, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x70, 0x61, 0x67, 0x65, 0x10, + 0x87, 0x06, 0x12, 0x0e, 0x0a, 0x09, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x70, 0x61, 0x6c, 0x10, + 0x88, 0x06, 0x12, 0x0d, 0x0a, 0x08, 0x54, 0x65, 0x6c, 0x65, 0x74, 0x79, 0x70, 0x65, 0x10, 0x89, + 0x06, 0x12, 0x0d, 0x0a, 0x08, 0x54, 0x69, 0x6d, 0x65, 0x43, 0x61, 0x6d, 0x70, 0x10, 0x8a, 0x06, + 0x12, 0x0d, 0x0a, 0x08, 0x55, 0x73, 0x65, 0x72, 0x66, 0x6c, 0x6f, 0x77, 0x10, 0x8b, 0x06, 0x12, + 0x0b, 0x0a, 0x06, 0x57, 0x69, 0x73, 0x74, 0x69, 0x61, 0x10, 0x8c, 0x06, 0x12, 0x13, 0x0a, 0x0a, + 0x53, 0x70, 0x6f, 0x72, 0x74, 0x52, 0x61, 0x64, 0x61, 0x72, 0x10, 0x8d, 0x06, 0x1a, 0x02, 0x08, + 0x01, 0x12, 0x10, 0x0a, 0x0b, 0x55, 0x70, 0x74, 0x69, 0x6d, 0x65, 0x52, 0x6f, 0x62, 0x6f, 0x74, + 0x10, 0x8e, 0x06, 0x12, 0x0e, 0x0a, 0x09, 0x43, 0x6f, 0x64, 0x65, 0x71, 0x75, 0x69, 0x72, 0x79, + 0x10, 0x8f, 0x06, 0x12, 0x11, 0x0a, 0x0c, 0x45, 0x78, 0x74, 0x72, 0x61, 0x63, 0x74, 0x6f, 0x72, + 0x41, 0x50, 0x49, 0x10, 0x90, 0x06, 0x12, 0x0d, 0x0a, 0x08, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x62, + 0x6c, 0x65, 0x10, 0x91, 0x06, 0x12, 0x0e, 0x0a, 0x09, 0x4d, 0x61, 0x67, 0x69, 0x63, 0x42, 0x65, + 0x6c, 0x6c, 0x10, 0x92, 0x06, 0x12, 0x0f, 0x0a, 0x0a, 0x53, 0x74, 0x6f, 0x72, 0x6d, 0x62, 0x6f, + 0x61, 0x72, 0x64, 0x10, 0x93, 0x06, 0x12, 0x0d, 0x0a, 0x08, 0x41, 0x70, 0x69, 0x6c, 0x61, 0x79, + 0x65, 0x72, 0x10, 0x94, 0x06, 0x12, 0x0b, 0x0a, 0x06, 0x44, 0x69, 0x73, 0x71, 0x75, 0x73, 0x10, + 0x95, 0x06, 0x12, 0x0b, 0x0a, 0x06, 0x57, 0x6f, 0x6f, 0x70, 0x72, 0x61, 0x10, 0x96, 0x06, 0x12, + 0x0e, 0x0a, 0x09, 0x50, 0x61, 0x70, 0x65, 0x72, 0x66, 0x6f, 0x72, 0x6d, 0x10, 0x97, 0x06, 0x12, + 0x0c, 0x0a, 0x07, 0x47, 0x75, 0x6d, 0x72, 0x6f, 0x61, 0x64, 0x10, 0x98, 0x06, 0x12, 0x0f, 0x0a, + 0x0a, 0x50, 0x61, 0x79, 0x64, 0x69, 0x72, 0x74, 0x61, 0x70, 0x70, 0x10, 0x99, 0x06, 0x12, 0x0e, + 0x0a, 0x09, 0x44, 0x65, 0x74, 0x65, 0x63, 0x74, 0x69, 0x66, 0x79, 0x10, 0x9a, 0x06, 0x12, 0x0f, + 0x0a, 0x0a, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x63, 0x61, 0x6b, 0x65, 0x10, 0x9b, 0x06, 0x12, + 0x0f, 0x0a, 0x0a, 0x4a, 0x75, 0x6d, 0x70, 0x73, 0x65, 0x6c, 0x6c, 0x65, 0x72, 0x10, 0x9c, 0x06, + 0x12, 0x0f, 0x0a, 0x0a, 0x4c, 0x75, 0x6e, 0x63, 0x68, 0x4d, 0x6f, 0x6e, 0x65, 0x79, 0x10, 0x9d, + 0x06, 0x12, 0x0c, 0x0a, 0x07, 0x52, 0x6f, 0x73, 0x65, 0x74, 0x74, 0x65, 0x10, 0x9e, 0x06, 0x12, + 0x09, 0x0a, 0x04, 0x59, 0x65, 0x6c, 0x70, 0x10, 0x9f, 0x06, 0x12, 0x0a, 0x0a, 0x05, 0x41, 0x74, + 0x65, 0x72, 0x61, 0x10, 0xa0, 0x06, 0x12, 0x12, 0x0a, 0x0d, 0x45, 0x63, 0x6f, 0x53, 0x74, 0x72, + 0x75, 0x78, 0x75, 0x72, 0x65, 0x49, 0x54, 0x10, 0xa1, 0x06, 0x12, 0x08, 0x0a, 0x03, 0x41, 0x68, + 0x61, 0x10, 0xa2, 0x06, 0x12, 0x0d, 0x0a, 0x08, 0x50, 0x61, 0x72, 0x73, 0x65, 0x68, 0x75, 0x62, + 0x10, 0xa3, 0x06, 0x12, 0x11, 0x0a, 0x0c, 0x50, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x43, 0x6c, + 0x6f, 0x75, 0x64, 0x10, 0xa4, 0x06, 0x12, 0x0f, 0x0a, 0x0a, 0x43, 0x6c, 0x6f, 0x75, 0x64, 0x73, + 0x6d, 0x69, 0x74, 0x68, 0x10, 0xa5, 0x06, 0x12, 0x11, 0x0a, 0x08, 0x46, 0x6c, 0x6f, 0x77, 0x64, + 0x61, 0x73, 0x68, 0x10, 0xa6, 0x06, 0x1a, 0x02, 0x08, 0x01, 0x12, 0x11, 0x0a, 0x08, 0x46, 0x6c, + 0x6f, 0x77, 0x64, 0x6f, 0x63, 0x6b, 0x10, 0xa7, 0x06, 0x1a, 0x02, 0x08, 0x01, 0x12, 0x0b, 0x0a, + 0x06, 0x46, 0x69, 0x62, 0x65, 0x72, 0x79, 0x10, 0xa8, 0x06, 0x12, 0x0d, 0x0a, 0x08, 0x54, 0x79, + 0x70, 0x65, 0x74, 0x61, 0x6c, 0x6b, 0x10, 0xa9, 0x06, 0x12, 0x0e, 0x0a, 0x09, 0x56, 0x6f, 0x6f, + 0x64, 0x6f, 0x6f, 0x53, 0x4d, 0x53, 0x10, 0xaa, 0x06, 0x12, 0x0e, 0x0a, 0x09, 0x5a, 0x75, 0x6c, + 0x69, 0x70, 0x43, 0x68, 0x61, 0x74, 0x10, 0xab, 0x06, 0x12, 0x0e, 0x0a, 0x09, 0x46, 0x6f, 0x72, + 0x6d, 0x63, 0x72, 0x61, 0x66, 0x74, 0x10, 0xac, 0x06, 0x12, 0x0c, 0x0a, 0x07, 0x49, 0x65, 0x78, + 0x61, 0x70, 0x69, 0x73, 0x10, 0xad, 0x06, 0x12, 0x0e, 0x0a, 0x09, 0x52, 0x65, 0x61, 0x63, 0x68, + 0x6d, 0x61, 0x69, 0x6c, 0x10, 0xae, 0x06, 0x12, 0x0f, 0x0a, 0x0a, 0x43, 0x68, 0x61, 0x72, 0x74, + 0x6d, 0x6f, 0x67, 0x75, 0x6c, 0x10, 0xaf, 0x06, 0x12, 0x0f, 0x0a, 0x0a, 0x41, 0x70, 0x70, 0x6f, + 0x69, 0x6e, 0x74, 0x65, 0x64, 0x64, 0x10, 0xb0, 0x06, 0x12, 0x08, 0x0a, 0x03, 0x57, 0x69, 0x74, + 0x10, 0xb1, 0x06, 0x12, 0x15, 0x0a, 0x10, 0x52, 0x65, 0x63, 0x68, 0x61, 0x72, 0x67, 0x65, 0x50, + 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x10, 0xb2, 0x06, 0x12, 0x0f, 0x0a, 0x0a, 0x44, 0x69, + 0x67, 0x67, 0x65, 0x72, 0x6e, 0x61, 0x75, 0x74, 0x10, 0xb3, 0x06, 0x12, 0x10, 0x0a, 0x0b, 0x4d, + 0x6f, 0x6e, 0x6b, 0x65, 0x79, 0x4c, 0x65, 0x61, 0x72, 0x6e, 0x10, 0xb4, 0x06, 0x12, 0x0a, 0x0a, + 0x05, 0x44, 0x75, 0x70, 0x6c, 0x79, 0x10, 0xb5, 0x06, 0x12, 0x0e, 0x0a, 0x09, 0x50, 0x6f, 0x73, + 0x74, 0x62, 0x61, 0x63, 0x6b, 0x73, 0x10, 0xb6, 0x06, 0x12, 0x0d, 0x0a, 0x08, 0x43, 0x6f, 0x6c, + 0x6c, 0x65, 0x63, 0x74, 0x32, 0x10, 0xb7, 0x06, 0x12, 0x0c, 0x0a, 0x07, 0x5a, 0x65, 0x6e, 0x52, + 0x6f, 0x77, 0x73, 0x10, 0xb8, 0x06, 0x12, 0x10, 0x0a, 0x0b, 0x5a, 0x69, 0x70, 0x63, 0x6f, 0x64, + 0x65, 0x62, 0x61, 0x73, 0x65, 0x10, 0xb9, 0x06, 0x12, 0x0b, 0x0a, 0x06, 0x54, 0x65, 0x66, 0x74, + 0x65, 0x72, 0x10, 0xba, 0x06, 0x12, 0x0a, 0x0a, 0x05, 0x54, 0x77, 0x69, 0x73, 0x74, 0x10, 0xbb, + 0x06, 0x12, 0x16, 0x0a, 0x11, 0x42, 0x72, 0x61, 0x69, 0x6e, 0x74, 0x72, 0x65, 0x65, 0x50, 0x61, + 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x10, 0xbc, 0x06, 0x12, 0x11, 0x0a, 0x0c, 0x43, 0x6c, 0x6f, + 0x75, 0x64, 0x43, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x74, 0x10, 0xbd, 0x06, 0x12, 0x0c, 0x0a, 0x07, + 0x47, 0x72, 0x61, 0x66, 0x61, 0x6e, 0x61, 0x10, 0xbe, 0x06, 0x12, 0x0f, 0x0a, 0x0a, 0x43, 0x6f, + 0x6e, 0x76, 0x65, 0x72, 0x74, 0x41, 0x70, 0x69, 0x10, 0xbf, 0x06, 0x12, 0x11, 0x0a, 0x0c, 0x54, + 0x72, 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, 0x77, 0x69, 0x73, 0x65, 0x10, 0xc0, 0x06, 0x12, 0x0c, + 0x0a, 0x07, 0x42, 0x75, 0x6c, 0x6b, 0x73, 0x6d, 0x73, 0x10, 0xc1, 0x06, 0x12, 0x0c, 0x0a, 0x07, + 0x44, 0x61, 0x74, 0x61, 0x62, 0x6f, 0x78, 0x10, 0xc2, 0x06, 0x12, 0x0e, 0x0a, 0x09, 0x4f, 0x6e, + 0x65, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x10, 0xc3, 0x06, 0x12, 0x0c, 0x0a, 0x07, 0x52, 0x65, + 0x6e, 0x74, 0x6d, 0x61, 0x6e, 0x10, 0xc4, 0x06, 0x12, 0x0c, 0x0a, 0x07, 0x50, 0x61, 0x72, 0x73, + 0x65, 0x75, 0x72, 0x10, 0xc5, 0x06, 0x12, 0x0e, 0x0a, 0x09, 0x44, 0x6f, 0x63, 0x70, 0x61, 0x72, + 0x73, 0x65, 0x72, 0x10, 0xc6, 0x06, 0x12, 0x0d, 0x0a, 0x08, 0x46, 0x6f, 0x72, 0x6d, 0x73, 0x69, + 0x74, 0x65, 0x10, 0xc7, 0x06, 0x12, 0x11, 0x0a, 0x0c, 0x54, 0x69, 0x63, 0x6b, 0x65, 0x74, 0x74, + 0x61, 0x69, 0x6c, 0x6f, 0x72, 0x10, 0xc8, 0x06, 0x12, 0x0c, 0x0a, 0x07, 0x4c, 0x65, 0x6d, 0x6c, + 0x69, 0x73, 0x74, 0x10, 0xc9, 0x06, 0x12, 0x0c, 0x0a, 0x07, 0x50, 0x72, 0x6f, 0x64, 0x70, 0x61, + 0x64, 0x10, 0xca, 0x06, 0x12, 0x0e, 0x0a, 0x09, 0x46, 0x6f, 0x72, 0x6d, 0x73, 0x74, 0x61, 0x63, + 0x6b, 0x10, 0xcb, 0x06, 0x12, 0x10, 0x0a, 0x0b, 0x43, 0x6f, 0x64, 0x65, 0x63, 0x6c, 0x69, 0x6d, + 0x61, 0x74, 0x65, 0x10, 0xcc, 0x06, 0x12, 0x0e, 0x0a, 0x09, 0x43, 0x6f, 0x64, 0x65, 0x6d, 0x61, + 0x67, 0x69, 0x63, 0x10, 0xcd, 0x06, 0x12, 0x0a, 0x0a, 0x05, 0x56, 0x62, 0x6f, 0x75, 0x74, 0x10, + 0xce, 0x06, 0x12, 0x0e, 0x0a, 0x09, 0x4e, 0x69, 0x67, 0x68, 0x74, 0x66, 0x61, 0x6c, 0x6c, 0x10, + 0xcf, 0x06, 0x12, 0x0f, 0x0a, 0x0a, 0x46, 0x6c, 0x69, 0x67, 0x68, 0x74, 0x4c, 0x61, 0x62, 0x73, + 0x10, 0xd0, 0x06, 0x12, 0x11, 0x0a, 0x0c, 0x53, 0x70, 0x65, 0x65, 0x63, 0x68, 0x54, 0x65, 0x78, + 0x74, 0x41, 0x49, 0x10, 0xd1, 0x06, 0x12, 0x0d, 0x0a, 0x08, 0x50, 0x6f, 0x6c, 0x6c, 0x73, 0x41, + 0x50, 0x49, 0x10, 0xd2, 0x06, 0x12, 0x0b, 0x0a, 0x06, 0x53, 0x69, 0x6d, 0x46, 0x69, 0x6e, 0x10, + 0xd3, 0x06, 0x12, 0x0a, 0x0a, 0x05, 0x53, 0x63, 0x61, 0x6c, 0x72, 0x10, 0xd4, 0x06, 0x12, 0x0f, + 0x0a, 0x0a, 0x4b, 0x61, 0x6e, 0x62, 0x61, 0x6e, 0x74, 0x6f, 0x6f, 0x6c, 0x10, 0xd5, 0x06, 0x12, + 0x10, 0x0a, 0x0b, 0x42, 0x72, 0x69, 0x67, 0x68, 0x74, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x10, 0xd6, + 0x06, 0x12, 0x0c, 0x0a, 0x07, 0x48, 0x6f, 0x74, 0x77, 0x69, 0x72, 0x65, 0x10, 0xd7, 0x06, 0x12, + 0x0d, 0x0a, 0x08, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x62, 0x6f, 0x74, 0x10, 0xd8, 0x06, 0x12, 0x0c, + 0x0a, 0x07, 0x54, 0x69, 0x6d, 0x65, 0x6b, 0x69, 0x74, 0x10, 0xd9, 0x06, 0x12, 0x10, 0x0a, 0x0b, + 0x49, 0x6e, 0x74, 0x65, 0x72, 0x73, 0x65, 0x6c, 0x6c, 0x65, 0x72, 0x10, 0xda, 0x06, 0x12, 0x11, + 0x0a, 0x0c, 0x4d, 0x6f, 0x6a, 0x6f, 0x68, 0x65, 0x6c, 0x70, 0x64, 0x65, 0x73, 0x6b, 0x10, 0xdb, + 0x06, 0x12, 0x0f, 0x0a, 0x0a, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x73, 0x65, 0x6e, 0x64, 0x10, + 0xdc, 0x06, 0x12, 0x10, 0x0a, 0x0b, 0x47, 0x65, 0x74, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x10, 0xdd, 0x06, 0x12, 0x0c, 0x0a, 0x07, 0x44, 0x79, 0x6e, 0x61, 0x64, 0x6f, 0x74, 0x10, + 0xde, 0x06, 0x12, 0x0a, 0x0a, 0x05, 0x44, 0x65, 0x6d, 0x69, 0x6f, 0x10, 0xdf, 0x06, 0x12, 0x0b, + 0x0a, 0x06, 0x54, 0x6f, 0x6b, 0x65, 0x65, 0x74, 0x10, 0xe0, 0x06, 0x12, 0x11, 0x0a, 0x0c, 0x4d, + 0x79, 0x65, 0x78, 0x70, 0x65, 0x72, 0x69, 0x6d, 0x65, 0x6e, 0x74, 0x10, 0xe1, 0x06, 0x12, 0x0e, + 0x0a, 0x09, 0x43, 0x6f, 0x70, 0x79, 0x73, 0x63, 0x61, 0x70, 0x65, 0x10, 0xe2, 0x06, 0x12, 0x0d, + 0x0a, 0x08, 0x42, 0x65, 0x73, 0x6e, 0x61, 0x70, 0x70, 0x79, 0x10, 0xe3, 0x06, 0x12, 0x0e, 0x0a, + 0x09, 0x53, 0x61, 0x6c, 0x65, 0x73, 0x6d, 0x61, 0x74, 0x65, 0x10, 0xe4, 0x06, 0x12, 0x13, 0x0a, + 0x0a, 0x48, 0x65, 0x61, 0x74, 0x6d, 0x61, 0x70, 0x61, 0x70, 0x69, 0x10, 0xe5, 0x06, 0x1a, 0x02, + 0x08, 0x01, 0x12, 0x11, 0x0a, 0x0c, 0x57, 0x65, 0x62, 0x73, 0x69, 0x74, 0x65, 0x70, 0x75, 0x6c, + 0x73, 0x65, 0x10, 0xe6, 0x06, 0x12, 0x0e, 0x0a, 0x09, 0x55, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x69, + 0x66, 0x79, 0x10, 0xe7, 0x06, 0x12, 0x0c, 0x0a, 0x07, 0x43, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x74, + 0x10, 0xe8, 0x06, 0x12, 0x0d, 0x0a, 0x08, 0x50, 0x44, 0x46, 0x6d, 0x79, 0x55, 0x52, 0x4c, 0x10, + 0xe9, 0x06, 0x12, 0x10, 0x0a, 0x0b, 0x41, 0x70, 0x69, 0x32, 0x43, 0x6f, 0x6e, 0x76, 0x65, 0x72, + 0x74, 0x10, 0xea, 0x06, 0x12, 0x0d, 0x0a, 0x08, 0x4f, 0x70, 0x73, 0x67, 0x65, 0x6e, 0x69, 0x65, + 0x10, 0xeb, 0x06, 0x12, 0x0b, 0x0a, 0x06, 0x47, 0x65, 0x6d, 0x69, 0x6e, 0x69, 0x10, 0xec, 0x06, + 0x12, 0x0e, 0x0a, 0x09, 0x48, 0x6f, 0x6e, 0x65, 0x79, 0x63, 0x6f, 0x6d, 0x62, 0x10, 0xed, 0x06, + 0x12, 0x14, 0x0a, 0x0f, 0x4b, 0x61, 0x6c, 0x74, 0x75, 0x72, 0x61, 0x41, 0x70, 0x70, 0x54, 0x6f, + 0x6b, 0x65, 0x6e, 0x10, 0xee, 0x06, 0x12, 0x13, 0x0a, 0x0e, 0x4b, 0x61, 0x6c, 0x74, 0x75, 0x72, + 0x61, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x10, 0xef, 0x06, 0x12, 0x0a, 0x0a, 0x05, 0x42, + 0x69, 0x74, 0x47, 0x6f, 0x10, 0xf0, 0x06, 0x12, 0x0d, 0x0a, 0x08, 0x4f, 0x70, 0x74, 0x69, 0x64, + 0x61, 0x73, 0x68, 0x10, 0xf1, 0x06, 0x12, 0x0a, 0x0a, 0x05, 0x49, 0x6d, 0x67, 0x69, 0x78, 0x10, + 0xf2, 0x06, 0x12, 0x10, 0x0a, 0x0b, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x54, 0x6f, 0x54, 0x65, 0x78, + 0x74, 0x10, 0xf3, 0x06, 0x12, 0x10, 0x0a, 0x0b, 0x50, 0x61, 0x67, 0x65, 0x32, 0x49, 0x6d, 0x61, + 0x67, 0x65, 0x73, 0x10, 0xf4, 0x06, 0x12, 0x0e, 0x0a, 0x09, 0x51, 0x75, 0x69, 0x63, 0x6b, 0x62, + 0x61, 0x73, 0x65, 0x10, 0xf5, 0x06, 0x12, 0x0d, 0x0a, 0x08, 0x52, 0x65, 0x64, 0x62, 0x6f, 0x6f, + 0x74, 0x68, 0x10, 0xf6, 0x06, 0x12, 0x0b, 0x0a, 0x06, 0x4e, 0x75, 0x62, 0x65, 0x6c, 0x61, 0x10, + 0xf7, 0x06, 0x12, 0x0c, 0x0a, 0x07, 0x49, 0x6e, 0x66, 0x6f, 0x62, 0x69, 0x70, 0x10, 0xf8, 0x06, + 0x12, 0x0a, 0x0a, 0x05, 0x55, 0x70, 0x72, 0x6f, 0x63, 0x10, 0xf9, 0x06, 0x12, 0x0f, 0x0a, 0x0a, + 0x53, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x62, 0x65, 0x65, 0x10, 0xfa, 0x06, 0x12, 0x0e, 0x0a, + 0x09, 0x41, 0x66, 0x74, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x10, 0xfb, 0x06, 0x12, 0x0c, 0x0a, + 0x07, 0x45, 0x64, 0x75, 0x73, 0x69, 0x67, 0x6e, 0x10, 0xfc, 0x06, 0x12, 0x0b, 0x0a, 0x06, 0x54, + 0x65, 0x61, 0x6d, 0x75, 0x70, 0x10, 0xfd, 0x06, 0x12, 0x0c, 0x0a, 0x07, 0x57, 0x6f, 0x72, 0x6b, + 0x64, 0x61, 0x79, 0x10, 0xfe, 0x06, 0x12, 0x0c, 0x0a, 0x07, 0x4d, 0x6f, 0x6e, 0x67, 0x6f, 0x44, + 0x42, 0x10, 0xff, 0x06, 0x12, 0x08, 0x0a, 0x03, 0x4e, 0x47, 0x43, 0x10, 0x80, 0x07, 0x12, 0x13, + 0x0a, 0x0e, 0x44, 0x69, 0x67, 0x69, 0x74, 0x61, 0x6c, 0x4f, 0x63, 0x65, 0x61, 0x6e, 0x56, 0x32, + 0x10, 0x81, 0x07, 0x12, 0x0e, 0x0a, 0x09, 0x53, 0x51, 0x4c, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, + 0x10, 0x82, 0x07, 0x12, 0x08, 0x0a, 0x03, 0x46, 0x54, 0x50, 0x10, 0x83, 0x07, 0x12, 0x0a, 0x0a, + 0x05, 0x52, 0x65, 0x64, 0x69, 0x73, 0x10, 0x84, 0x07, 0x12, 0x09, 0x0a, 0x04, 0x4c, 0x44, 0x41, + 0x50, 0x10, 0x85, 0x07, 0x12, 0x0c, 0x0a, 0x07, 0x53, 0x68, 0x6f, 0x70, 0x69, 0x66, 0x79, 0x10, + 0x86, 0x07, 0x12, 0x0d, 0x0a, 0x08, 0x52, 0x61, 0x62, 0x62, 0x69, 0x74, 0x4d, 0x51, 0x10, 0x87, + 0x07, 0x12, 0x10, 0x0a, 0x0b, 0x43, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x52, 0x65, 0x67, 0x65, 0x78, + 0x10, 0x88, 0x07, 0x12, 0x0e, 0x0a, 0x09, 0x45, 0x74, 0x68, 0x65, 0x72, 0x73, 0x63, 0x61, 0x6e, + 0x10, 0x89, 0x07, 0x12, 0x0b, 0x0a, 0x06, 0x49, 0x6e, 0x66, 0x75, 0x72, 0x61, 0x10, 0x8a, 0x07, + 0x12, 0x0c, 0x0a, 0x07, 0x41, 0x6c, 0x63, 0x68, 0x65, 0x6d, 0x79, 0x10, 0x8b, 0x07, 0x12, 0x10, + 0x0a, 0x0b, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x4e, 0x61, 0x74, 0x69, 0x76, 0x65, 0x10, 0x8c, 0x07, + 0x12, 0x0c, 0x0a, 0x07, 0x4d, 0x6f, 0x72, 0x61, 0x6c, 0x69, 0x73, 0x10, 0x8d, 0x07, 0x12, 0x0c, + 0x0a, 0x07, 0x42, 0x73, 0x63, 0x53, 0x63, 0x61, 0x6e, 0x10, 0x8e, 0x07, 0x12, 0x16, 0x0a, 0x0d, + 0x43, 0x6f, 0x69, 0x6e, 0x4d, 0x61, 0x72, 0x6b, 0x65, 0x74, 0x43, 0x61, 0x70, 0x10, 0x8f, 0x07, + 0x1a, 0x02, 0x08, 0x01, 0x12, 0x0a, 0x0a, 0x05, 0x50, 0x65, 0x72, 0x63, 0x79, 0x10, 0x90, 0x07, + 0x12, 0x11, 0x0a, 0x0c, 0x54, 0x69, 0x6e, 0x65, 0x73, 0x57, 0x65, 0x62, 0x68, 0x6f, 0x6f, 0x6b, + 0x10, 0x91, 0x07, 0x12, 0x0b, 0x0a, 0x06, 0x50, 0x75, 0x6c, 0x75, 0x6d, 0x69, 0x10, 0x92, 0x07, + 0x12, 0x12, 0x0a, 0x0d, 0x53, 0x75, 0x70, 0x61, 0x62, 0x61, 0x73, 0x65, 0x54, 0x6f, 0x6b, 0x65, + 0x6e, 0x10, 0x93, 0x07, 0x12, 0x10, 0x0a, 0x0b, 0x4e, 0x75, 0x47, 0x65, 0x74, 0x41, 0x70, 0x69, + 0x4b, 0x65, 0x79, 0x10, 0x94, 0x07, 0x12, 0x0a, 0x0a, 0x05, 0x41, 0x69, 0x76, 0x65, 0x6e, 0x10, + 0x95, 0x07, 0x12, 0x0c, 0x0a, 0x07, 0x50, 0x72, 0x65, 0x66, 0x65, 0x63, 0x74, 0x10, 0x96, 0x07, + 0x12, 0x0d, 0x0a, 0x08, 0x44, 0x6f, 0x63, 0x75, 0x73, 0x69, 0x67, 0x6e, 0x10, 0x97, 0x07, 0x12, + 0x0e, 0x0a, 0x09, 0x43, 0x6f, 0x75, 0x63, 0x68, 0x62, 0x61, 0x73, 0x65, 0x10, 0x98, 0x07, 0x12, + 0x0e, 0x0a, 0x09, 0x44, 0x6f, 0x63, 0x6b, 0x65, 0x72, 0x68, 0x75, 0x62, 0x10, 0x99, 0x07, 0x12, + 0x19, 0x0a, 0x14, 0x54, 0x72, 0x75, 0x66, 0x66, 0x6c, 0x65, 0x68, 0x6f, 0x67, 0x45, 0x6e, 0x74, + 0x65, 0x72, 0x70, 0x72, 0x69, 0x73, 0x65, 0x10, 0x9a, 0x07, 0x12, 0x10, 0x0a, 0x0b, 0x45, 0x6e, + 0x76, 0x6f, 0x79, 0x41, 0x70, 0x69, 0x4b, 0x65, 0x79, 0x10, 0x9b, 0x07, 0x12, 0x11, 0x0a, 0x0c, + 0x47, 0x69, 0x74, 0x48, 0x75, 0x62, 0x4f, 0x61, 0x75, 0x74, 0x68, 0x32, 0x10, 0x9c, 0x07, 0x12, + 0x0f, 0x0a, 0x0a, 0x53, 0x61, 0x6c, 0x65, 0x73, 0x66, 0x6f, 0x72, 0x63, 0x65, 0x10, 0x9d, 0x07, + 0x12, 0x10, 0x0a, 0x0b, 0x48, 0x75, 0x67, 0x67, 0x69, 0x6e, 0x67, 0x46, 0x61, 0x63, 0x65, 0x10, + 0x9e, 0x07, 0x12, 0x0e, 0x0a, 0x09, 0x53, 0x6e, 0x6f, 0x77, 0x66, 0x6c, 0x61, 0x6b, 0x65, 0x10, + 0x9f, 0x07, 0x12, 0x10, 0x0a, 0x0b, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x67, 0x72, 0x61, 0x70, + 0x68, 0x10, 0xa0, 0x07, 0x12, 0x0e, 0x0a, 0x09, 0x54, 0x61, 0x69, 0x6c, 0x73, 0x63, 0x61, 0x6c, + 0x65, 0x10, 0xa1, 0x07, 0x12, 0x10, 0x0a, 0x0b, 0x57, 0x65, 0x62, 0x33, 0x53, 0x74, 0x6f, 0x72, + 0x61, 0x67, 0x65, 0x10, 0xa2, 0x07, 0x12, 0x11, 0x0a, 0x0c, 0x41, 0x7a, 0x75, 0x72, 0x65, 0x53, + 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x10, 0xa3, 0x07, 0x12, 0x12, 0x0a, 0x0d, 0x50, 0x6c, 0x61, + 0x6e, 0x65, 0x74, 0x53, 0x63, 0x61, 0x6c, 0x65, 0x44, 0x62, 0x10, 0xa4, 0x07, 0x12, 0x0e, 0x0a, + 0x09, 0x41, 0x6e, 0x74, 0x68, 0x72, 0x6f, 0x70, 0x69, 0x63, 0x10, 0xa5, 0x07, 0x12, 0x09, 0x0a, + 0x04, 0x52, 0x61, 0x6d, 0x70, 0x10, 0xa6, 0x07, 0x12, 0x0c, 0x0a, 0x07, 0x4b, 0x6c, 0x61, 0x76, + 0x69, 0x79, 0x6f, 0x10, 0xa7, 0x07, 0x12, 0x14, 0x0a, 0x0f, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, + 0x67, 0x72, 0x61, 0x70, 0x68, 0x43, 0x6f, 0x64, 0x79, 0x10, 0xa8, 0x07, 0x12, 0x0e, 0x0a, 0x09, + 0x56, 0x6f, 0x69, 0x63, 0x65, 0x66, 0x6c, 0x6f, 0x77, 0x10, 0xa9, 0x07, 0x12, 0x0c, 0x0a, 0x07, + 0x50, 0x72, 0x69, 0x76, 0x61, 0x63, 0x79, 0x10, 0xaa, 0x07, 0x12, 0x0b, 0x0a, 0x06, 0x49, 0x50, + 0x49, 0x6e, 0x66, 0x6f, 0x10, 0xab, 0x07, 0x12, 0x10, 0x0a, 0x0b, 0x49, 0x70, 0x32, 0x6c, 0x6f, + 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x10, 0xac, 0x07, 0x12, 0x0e, 0x0a, 0x09, 0x49, 0x6e, 0x73, + 0x74, 0x61, 0x6d, 0x6f, 0x6a, 0x6f, 0x10, 0xad, 0x07, 0x12, 0x0e, 0x0a, 0x09, 0x50, 0x6f, 0x72, + 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x10, 0xae, 0x07, 0x12, 0x13, 0x0a, 0x0e, 0x50, 0x6f, 0x72, + 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x10, 0xaf, 0x07, 0x12, 0x0b, + 0x0a, 0x06, 0x4c, 0x6f, 0x67, 0x67, 0x6c, 0x79, 0x10, 0xb0, 0x07, 0x12, 0x0c, 0x0a, 0x07, 0x4f, + 0x70, 0x65, 0x6e, 0x56, 0x70, 0x6e, 0x10, 0xb1, 0x07, 0x12, 0x1e, 0x0a, 0x19, 0x56, 0x61, 0x67, + 0x72, 0x61, 0x6e, 0x74, 0x43, 0x6c, 0x6f, 0x75, 0x64, 0x50, 0x65, 0x72, 0x73, 0x6f, 0x6e, 0x61, + 0x6c, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x10, 0xb2, 0x07, 0x12, 0x10, 0x0a, 0x0b, 0x42, 0x65, 0x74, + 0x74, 0x65, 0x72, 0x53, 0x74, 0x61, 0x63, 0x6b, 0x10, 0xb3, 0x07, 0x12, 0x0d, 0x0a, 0x08, 0x5a, + 0x65, 0x72, 0x6f, 0x54, 0x69, 0x65, 0x72, 0x10, 0xb4, 0x07, 0x12, 0x0e, 0x0a, 0x09, 0x41, 0x70, + 0x70, 0x4f, 0x70, 0x74, 0x69, 0x63, 0x73, 0x10, 0xb5, 0x07, 0x12, 0x0d, 0x0a, 0x08, 0x4d, 0x65, + 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x10, 0xb6, 0x07, 0x12, 0x11, 0x0a, 0x0c, 0x43, 0x6f, 0x69, + 0x6e, 0x62, 0x61, 0x73, 0x65, 0x57, 0x61, 0x61, 0x53, 0x10, 0xb7, 0x07, 0x12, 0x11, 0x0a, 0x0c, + 0x4c, 0x65, 0x6d, 0x6f, 0x6e, 0x53, 0x71, 0x75, 0x65, 0x65, 0x7a, 0x79, 0x10, 0xb8, 0x07, 0x12, + 0x0d, 0x0a, 0x08, 0x42, 0x75, 0x64, 0x69, 0x62, 0x61, 0x73, 0x65, 0x10, 0xb9, 0x07, 0x12, 0x0f, + 0x0a, 0x0a, 0x44, 0x65, 0x6e, 0x6f, 0x44, 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x10, 0xba, 0x07, 0x12, + 0x0b, 0x0a, 0x06, 0x53, 0x74, 0x72, 0x69, 0x70, 0x6f, 0x10, 0xbb, 0x07, 0x12, 0x0c, 0x0a, 0x07, + 0x52, 0x65, 0x70, 0x6c, 0x79, 0x49, 0x4f, 0x10, 0xbc, 0x07, 0x12, 0x0f, 0x0a, 0x0a, 0x41, 0x7a, + 0x75, 0x72, 0x65, 0x42, 0x61, 0x74, 0x63, 0x68, 0x10, 0xbd, 0x07, 0x12, 0x1b, 0x0a, 0x16, 0x41, + 0x7a, 0x75, 0x72, 0x65, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x52, 0x65, 0x67, + 0x69, 0x73, 0x74, 0x72, 0x79, 0x10, 0xbe, 0x07, 0x12, 0x12, 0x0a, 0x0d, 0x41, 0x57, 0x53, 0x53, + 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x4b, 0x65, 0x79, 0x10, 0xbf, 0x07, 0x12, 0x09, 0x0a, 0x04, + 0x43, 0x6f, 0x64, 0x61, 0x10, 0xc0, 0x07, 0x12, 0x0b, 0x0a, 0x06, 0x4c, 0x6f, 0x67, 0x7a, 0x49, + 0x4f, 0x10, 0xc1, 0x07, 0x12, 0x0f, 0x0a, 0x0a, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x62, 0x72, 0x69, + 0x74, 0x65, 0x10, 0xc2, 0x07, 0x12, 0x1a, 0x0a, 0x15, 0x47, 0x72, 0x61, 0x66, 0x61, 0x6e, 0x61, + 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x10, 0xc3, + 0x07, 0x12, 0x13, 0x0a, 0x0e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x46, 0x69, 0x6e, 0x61, + 0x6e, 0x63, 0x65, 0x10, 0xc4, 0x07, 0x12, 0x0d, 0x0a, 0x08, 0x4f, 0x76, 0x65, 0x72, 0x6c, 0x6f, + 0x6f, 0x70, 0x10, 0xc5, 0x07, 0x12, 0x0a, 0x0a, 0x05, 0x4e, 0x67, 0x72, 0x6f, 0x6b, 0x10, 0xc6, + 0x07, 0x12, 0x0e, 0x0a, 0x09, 0x52, 0x65, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x65, 0x10, 0xc7, + 0x07, 0x12, 0x0d, 0x0a, 0x08, 0x50, 0x6f, 0x73, 0x74, 0x67, 0x72, 0x65, 0x73, 0x10, 0xc8, 0x07, + 0x12, 0x2a, 0x0a, 0x25, 0x41, 0x7a, 0x75, 0x72, 0x65, 0x41, 0x63, 0x74, 0x69, 0x76, 0x65, 0x44, + 0x69, 0x72, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x79, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x10, 0xc9, 0x07, 0x12, 0x20, 0x0a, 0x1b, + 0x41, 0x7a, 0x75, 0x72, 0x65, 0x43, 0x61, 0x63, 0x68, 0x65, 0x46, 0x6f, 0x72, 0x52, 0x65, 0x64, + 0x69, 0x73, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x4b, 0x65, 0x79, 0x10, 0xca, 0x07, 0x12, 0x21, + 0x0a, 0x1c, 0x41, 0x7a, 0x75, 0x72, 0x65, 0x43, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x44, 0x42, 0x4b, + 0x65, 0x79, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x61, 0x62, 0x6c, 0x65, 0x10, 0xcb, + 0x07, 0x12, 0x23, 0x0a, 0x1e, 0x41, 0x7a, 0x75, 0x72, 0x65, 0x44, 0x65, 0x76, 0x6f, 0x70, 0x73, + 0x50, 0x65, 0x72, 0x73, 0x6f, 0x6e, 0x61, 0x6c, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x54, 0x6f, + 0x6b, 0x65, 0x6e, 0x10, 0xcc, 0x07, 0x12, 0x15, 0x0a, 0x10, 0x41, 0x7a, 0x75, 0x72, 0x65, 0x46, + 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x4b, 0x65, 0x79, 0x10, 0xcd, 0x07, 0x12, 0x2c, 0x0a, + 0x27, 0x41, 0x7a, 0x75, 0x72, 0x65, 0x4d, 0x4c, 0x57, 0x65, 0x62, 0x53, 0x65, 0x72, 0x76, 0x69, + 0x63, 0x65, 0x43, 0x6c, 0x61, 0x73, 0x73, 0x69, 0x63, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, + 0x69, 0x61, 0x62, 0x6c, 0x65, 0x4b, 0x65, 0x79, 0x10, 0xce, 0x07, 0x12, 0x12, 0x0a, 0x0d, 0x41, + 0x7a, 0x75, 0x72, 0x65, 0x53, 0x61, 0x73, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x10, 0xcf, 0x07, 0x12, + 0x18, 0x0a, 0x13, 0x41, 0x7a, 0x75, 0x72, 0x65, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x41, 0x64, + 0x6d, 0x69, 0x6e, 0x4b, 0x65, 0x79, 0x10, 0xd0, 0x07, 0x12, 0x18, 0x0a, 0x13, 0x41, 0x7a, 0x75, + 0x72, 0x65, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x51, 0x75, 0x65, 0x72, 0x79, 0x4b, 0x65, 0x79, + 0x10, 0xd1, 0x07, 0x12, 0x1f, 0x0a, 0x1a, 0x41, 0x7a, 0x75, 0x72, 0x65, 0x4d, 0x61, 0x6e, 0x61, + 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, + 0x65, 0x10, 0xd2, 0x07, 0x12, 0x0d, 0x0a, 0x08, 0x41, 0x7a, 0x75, 0x72, 0x65, 0x53, 0x51, 0x4c, + 0x10, 0xd3, 0x07, 0x12, 0x0a, 0x0a, 0x05, 0x46, 0x6c, 0x79, 0x49, 0x4f, 0x10, 0xd4, 0x07, 0x12, + 0x0e, 0x0a, 0x09, 0x42, 0x75, 0x69, 0x6c, 0x74, 0x57, 0x69, 0x74, 0x68, 0x10, 0xd5, 0x07, 0x12, + 0x0f, 0x0a, 0x0a, 0x4a, 0x75, 0x70, 0x69, 0x74, 0x65, 0x72, 0x4f, 0x6e, 0x65, 0x10, 0xd6, 0x07, + 0x12, 0x25, 0x0a, 0x20, 0x47, 0x43, 0x50, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, + 0x69, 0x61, 0x6c, 0x73, 0x10, 0xd7, 0x07, 0x12, 0x08, 0x0a, 0x03, 0x57, 0x69, 0x7a, 0x10, 0xd8, + 0x07, 0x12, 0x0c, 0x0a, 0x07, 0x50, 0x61, 0x67, 0x61, 0x72, 0x6d, 0x65, 0x10, 0xd9, 0x07, 0x12, + 0x0c, 0x0a, 0x07, 0x4f, 0x6e, 0x66, 0x6c, 0x65, 0x65, 0x74, 0x10, 0xda, 0x07, 0x12, 0x0c, 0x0a, + 0x07, 0x49, 0x6e, 0x74, 0x72, 0x61, 0x34, 0x32, 0x10, 0xdb, 0x07, 0x12, 0x09, 0x0a, 0x04, 0x47, + 0x72, 0x6f, 0x71, 0x10, 0xdc, 0x07, 0x12, 0x17, 0x0a, 0x12, 0x54, 0x77, 0x69, 0x74, 0x74, 0x65, + 0x72, 0x43, 0x6f, 0x6e, 0x73, 0x75, 0x6d, 0x65, 0x72, 0x6b, 0x65, 0x79, 0x10, 0xdd, 0x07, 0x12, + 0x0b, 0x0a, 0x06, 0x45, 0x72, 0x61, 0x73, 0x65, 0x72, 0x10, 0xde, 0x07, 0x12, 0x0e, 0x0a, 0x09, + 0x4c, 0x61, 0x72, 0x6b, 0x53, 0x75, 0x69, 0x74, 0x65, 0x10, 0xdf, 0x07, 0x12, 0x14, 0x0a, 0x0f, + 0x4c, 0x61, 0x72, 0x6b, 0x53, 0x75, 0x69, 0x74, 0x65, 0x41, 0x70, 0x69, 0x4b, 0x65, 0x79, 0x10, + 0xe0, 0x07, 0x12, 0x0e, 0x0a, 0x09, 0x45, 0x6e, 0x64, 0x6f, 0x72, 0x4c, 0x61, 0x62, 0x73, 0x10, + 0xe1, 0x07, 0x12, 0x0f, 0x0a, 0x0a, 0x45, 0x6c, 0x65, 0x76, 0x65, 0x6e, 0x4c, 0x61, 0x62, 0x73, + 0x10, 0xe2, 0x07, 0x12, 0x0d, 0x0a, 0x08, 0x4e, 0x65, 0x74, 0x73, 0x75, 0x69, 0x74, 0x65, 0x10, + 0xe3, 0x07, 0x12, 0x14, 0x0a, 0x0f, 0x52, 0x6f, 0x62, 0x69, 0x6e, 0x68, 0x6f, 0x6f, 0x64, 0x43, + 0x72, 0x79, 0x70, 0x74, 0x6f, 0x10, 0xe4, 0x07, 0x12, 0x0a, 0x0a, 0x05, 0x4e, 0x56, 0x41, 0x50, + 0x49, 0x10, 0xe5, 0x07, 0x12, 0x09, 0x0a, 0x04, 0x50, 0x79, 0x50, 0x49, 0x10, 0xe6, 0x07, 0x12, + 0x0f, 0x0a, 0x0a, 0x52, 0x61, 0x69, 0x6c, 0x77, 0x61, 0x79, 0x41, 0x70, 0x70, 0x10, 0xe7, 0x07, + 0x12, 0x0b, 0x0a, 0x06, 0x4d, 0x65, 0x72, 0x61, 0x6b, 0x69, 0x10, 0xe8, 0x07, 0x12, 0x15, 0x0a, + 0x10, 0x53, 0x61, 0x6c, 0x61, 0x64, 0x43, 0x6c, 0x6f, 0x75, 0x64, 0x41, 0x70, 0x69, 0x4b, 0x65, + 0x79, 0x10, 0xe9, 0x07, 0x12, 0x08, 0x0a, 0x03, 0x42, 0x6f, 0x78, 0x10, 0xea, 0x07, 0x12, 0x0d, + 0x0a, 0x08, 0x42, 0x6f, 0x78, 0x4f, 0x61, 0x75, 0x74, 0x68, 0x10, 0xeb, 0x07, 0x12, 0x0f, 0x0a, + 0x0a, 0x41, 0x70, 0x69, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x10, 0xec, 0x07, 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 6f220b09d153..978e11fb4e57 100644 --- a/proto/detectors.proto +++ b/proto/detectors.proto @@ -654,7 +654,7 @@ enum DetectorType { Flightstats = 642; ChecIO = 643; Manifest = 644; - ApiScience = 645; + ApiScience = 645 [deprecated = true]; AppSynergy = 646; Caflou = 647; Caspio = 648; @@ -1013,6 +1013,7 @@ enum DetectorType { SaladCloudApiKey = 1001; Box = 1002; BoxOauth = 1003; + ApiMetrics = 1004; } message Result { From 9ad281a915f0470fb4a88aff2d72d9172a66870c Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 22 Oct 2024 09:43:49 -0700 Subject: [PATCH 51/76] fix(deps): update module github.com/fatih/color to v1.18.0 (#3492) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- go.mod | 2 +- go.sum | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/go.mod b/go.mod index 016dad7255d1..6882f251ae1c 100644 --- a/go.mod +++ b/go.mod @@ -38,7 +38,7 @@ require ( github.com/dustin/go-humanize v1.0.1 github.com/elastic/go-elasticsearch/v8 v8.15.0 github.com/envoyproxy/protoc-gen-validate v1.1.0 - github.com/fatih/color v1.17.0 + github.com/fatih/color v1.18.0 github.com/felixge/fgprof v0.9.5 github.com/gabriel-vasile/mimetype v1.4.6 github.com/getsentry/sentry-go v0.29.1 diff --git a/go.sum b/go.sum index 906668679003..78dad01d52e5 100644 --- a/go.sum +++ b/go.sum @@ -295,6 +295,8 @@ github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f h1:Y/CXytFA4m6 github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f/go.mod h1:vw97MGsxSvLiUE2X8qFplwetxpGLQrlU1Q9AUEIzCaM= github.com/fatih/color v1.17.0 h1:GlRw1BRJxkpqUCBKzKOw098ed57fEsKeNjpTe3cSjK4= github.com/fatih/color v1.17.0/go.mod h1:YZ7TlrGPkiz6ku9fK3TLD/pl3CpsiFyu8N92HLgmosI= +github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM= +github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU= github.com/felixge/fgprof v0.9.5 h1:8+vR6yu2vvSKn08urWyEuxx75NWPEvybbkBirEpsbVY= github.com/felixge/fgprof v0.9.5/go.mod h1:yKl+ERSa++RYOs32d8K6WEXCB4uXdLls4ZaZPpayhMM= github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= From 06e37caa043eed21a039269f93c907d7a00d1415 Mon Sep 17 00:00:00 2001 From: Richard Gomez <32133502+rgmz@users.noreply.github.com> Date: Wed, 23 Oct 2024 10:53:15 -0400 Subject: [PATCH 52/76] chore: re-order log context fields (#3430) --- pkg/sources/source_manager.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/sources/source_manager.go b/pkg/sources/source_manager.go index d3ba4a711952..f3afe74ecbca 100644 --- a/pkg/sources/source_manager.go +++ b/pkg/sources/source_manager.go @@ -364,7 +364,7 @@ func (s *SourceManager) runWithUnits(ctx context.Context, source SourceUnitEnumC // TODO: Catch panics and add to report. defer close(chunkReporter.chunkCh) id, kind := unit.SourceUnitID() - ctx := context.WithValues(ctx, "unit", id, "unit_kind", kind) + ctx := context.WithValues(ctx, "unit_kind", kind, "unit", id) ctx.Logger().V(3).Info("chunking unit") if err := source.ChunkUnit(ctx, unit, chunkReporter); err != nil { report.ReportError(Fatal{ChunkError{Unit: unit, Err: err}}) From 0608b22e4fea3b63e75125e3926a76758fa5be21 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 23 Oct 2024 09:20:04 -0700 Subject: [PATCH 53/76] fix(deps): update module google.golang.org/api to v0.202.0 (#3496) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- go.mod | 8 ++++---- go.sum | 8 ++++++++ 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/go.mod b/go.mod index 6882f251ae1c..e29107df6a1f 100644 --- a/go.mod +++ b/go.mod @@ -108,7 +108,7 @@ require ( golang.org/x/oauth2 v0.23.0 golang.org/x/sync v0.8.0 golang.org/x/text v0.19.0 - google.golang.org/api v0.201.0 + google.golang.org/api v0.202.0 google.golang.org/protobuf v1.35.1 gopkg.in/h2non/gock.v1 v1.1.2 gopkg.in/yaml.v2 v2.4.0 @@ -319,9 +319,9 @@ require ( golang.org/x/time v0.7.0 // indirect golang.org/x/tools v0.26.0 // indirect golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 // indirect - google.golang.org/genproto v0.0.0-20241007155032-5fefd90f89a9 // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20240930140551-af27646dc61f // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20241007155032-5fefd90f89a9 // indirect + google.golang.org/genproto v0.0.0-20241015192408-796eee8c2d53 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20241007155032-5fefd90f89a9 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20241015192408-796eee8c2d53 // indirect google.golang.org/grpc v1.67.1 // indirect google.golang.org/grpc/stats/opentelemetry v0.0.0-20240907200651-3ffb98b2c93a // indirect gopkg.in/warnings.v0 v0.1.2 // indirect diff --git a/go.sum b/go.sum index 78dad01d52e5..e3f027f88c28 100644 --- a/go.sum +++ b/go.sum @@ -1133,6 +1133,8 @@ google.golang.org/api v0.200.0 h1:0ytfNWn101is6e9VBoct2wrGDjOi5vn7jw5KtaQgDrU= google.golang.org/api v0.200.0/go.mod h1:Tc5u9kcbjO7A8SwGlYj4IiVifJU01UqXtEgDMYmBmV8= google.golang.org/api v0.201.0 h1:+7AD9JNM3tREtawRMu8sOjSbb8VYcYXJG/2eEOmfDu0= google.golang.org/api v0.201.0/go.mod h1:HVY0FCHVs89xIW9fzf/pBvOEm+OolHa86G/txFezyq4= +google.golang.org/api v0.202.0 h1:y1iuVHMqokQbimW79ZqPZWo4CiyFu6HcCYHwSNyzlfo= +google.golang.org/api v0.202.0/go.mod h1:3Jjeq7M/SFblTNCp7ES2xhq+WvGL0KeXI0joHQBfwTQ= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= @@ -1157,14 +1159,20 @@ google.golang.org/genproto v0.0.0-20240903143218-8af14fe29dc1 h1:BulPr26Jqjnd4eY google.golang.org/genproto v0.0.0-20240903143218-8af14fe29dc1/go.mod h1:hL97c3SYopEHblzpxRL4lSs523++l8DYxGM1FQiYmb4= google.golang.org/genproto v0.0.0-20241007155032-5fefd90f89a9 h1:nFS3IivktIU5Mk6KQa+v6RKkHUpdQpphqGNLxqNnbEk= google.golang.org/genproto v0.0.0-20241007155032-5fefd90f89a9/go.mod h1:tEzYTYZxbmVNOu0OAFH9HzdJtLn6h4Aj89zzlBCdHms= +google.golang.org/genproto v0.0.0-20241015192408-796eee8c2d53 h1:Df6WuGvthPzc+JiQ/G+m+sNX24kc0aTBqoDN/0yyykE= +google.golang.org/genproto v0.0.0-20241015192408-796eee8c2d53/go.mod h1:fheguH3Am2dGp1LfXkrvwqC/KlFq8F0nLq3LryOMrrE= google.golang.org/genproto/googleapis/api v0.0.0-20240903143218-8af14fe29dc1 h1:hjSy6tcFQZ171igDaN5QHOw2n6vx40juYbC/x67CEhc= google.golang.org/genproto/googleapis/api v0.0.0-20240903143218-8af14fe29dc1/go.mod h1:qpvKtACPCQhAdu3PyQgV4l3LMXZEtft7y8QcarRsp9I= google.golang.org/genproto/googleapis/api v0.0.0-20240930140551-af27646dc61f h1:jTm13A2itBi3La6yTGqn8bVSrc3ZZ1r8ENHlIXBfnRA= google.golang.org/genproto/googleapis/api v0.0.0-20240930140551-af27646dc61f/go.mod h1:CLGoBuH1VHxAUXVPP8FfPwPEVJB6lz3URE5mY2SuayE= +google.golang.org/genproto/googleapis/api v0.0.0-20241007155032-5fefd90f89a9 h1:T6rh4haD3GVYsgEfWExoCZA2o2FmbNyKpTuAxbEFPTg= +google.golang.org/genproto/googleapis/api v0.0.0-20241007155032-5fefd90f89a9/go.mod h1:wp2WsuBYj6j8wUdo3ToZsdxxixbvQNAHqVJrTgi5E5M= google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1 h1:pPJltXNxVzT4pK9yD8vR9X75DaWYYmLGMsEvBfFQZzQ= google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU= google.golang.org/genproto/googleapis/rpc v0.0.0-20241007155032-5fefd90f89a9 h1:QCqS/PdaHTSWGvupk2F/ehwHtGc0/GYkT+3GAcR1CCc= google.golang.org/genproto/googleapis/rpc v0.0.0-20241007155032-5fefd90f89a9/go.mod h1:GX3210XPVPUjJbTUbvwI8f2IpZDMZuPJWDzDuebbviI= +google.golang.org/genproto/googleapis/rpc v0.0.0-20241015192408-796eee8c2d53 h1:X58yt85/IXCx0Y3ZwN6sEIKZzQtDEYaBWrDvErdXrRE= +google.golang.org/genproto/googleapis/rpc v0.0.0-20241015192408-796eee8c2d53/go.mod h1:GX3210XPVPUjJbTUbvwI8f2IpZDMZuPJWDzDuebbviI= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= From c37edcd72e9ad6996c37eee097c2e28b41ce791e Mon Sep 17 00:00:00 2001 From: Sahil Silare <32628578+sahil9001@users.noreply.github.com> Date: Thu, 24 Oct 2024 17:43:14 +0530 Subject: [PATCH 54/76] fix: added correct verification endpoint & validation logic for alegra (#3437) * fix: added correct verification endpoint for alegra * fix: fixed email regex * fix: added correct tests and validation * fix: fixed alegra tests --- pkg/detectors/alegra/alegra.go | 80 ++++++++++++------- .../alegra/alegra_integration_test.go | 1 + pkg/detectors/alegra/alegra_test.go | 22 +++-- 3 files changed, 62 insertions(+), 41 deletions(-) diff --git a/pkg/detectors/alegra/alegra.go b/pkg/detectors/alegra/alegra.go index 1fcbfcb2bdce..856d77237681 100644 --- a/pkg/detectors/alegra/alegra.go +++ b/pkg/detectors/alegra/alegra.go @@ -2,6 +2,8 @@ package alegra import ( "context" + "fmt" + "io" "net/http" "strings" @@ -13,18 +15,17 @@ import ( ) type Scanner struct { - detectors.DefaultMultiPartCredentialProvider + client *http.Client } // Ensure the Scanner satisfies the interface at compile time. var _ detectors.Detector = (*Scanner)(nil) var ( - client = common.SaneHttpClient() - + defaultClient = common.SaneHttpClient() // Make sure that your group is surrounded in boundary characters such as below to reduce false positives. keyPat = regexp.MustCompile(detectors.PrefixRegex([]string{"alegra"}) + `\b([a-z0-9-]{20})\b`) - idPat = regexp.MustCompile(detectors.PrefixRegex([]string{"alegra"}) + `\b([a-zA-Z0-9\.\-\@]{25,30})\b`) + idPat = regexp.MustCompile(detectors.PrefixRegex([]string{"alegra"}) + common.EmailPattern) ) // Keywords are used for efficiently pre-filtering chunks. @@ -37,41 +38,38 @@ func (s Scanner) Keywords() []string { func (s Scanner) FromData(ctx context.Context, verify bool, data []byte) (results []detectors.Result, err error) { dataStr := string(data) - matches := keyPat.FindAllStringSubmatch(dataStr, -1) + keyMatches := keyPat.FindAllStringSubmatch(dataStr, -1) idMatches := idPat.FindAllStringSubmatch(dataStr, -1) - for _, match := range matches { - if len(match) != 2 { - continue - } - tokenPatMatch := strings.TrimSpace(match[1]) + uniqueTokens := make(map[string]struct{}) + uniqueIDs := make(map[string]struct{}) - for _, idMatch := range idMatches { - if len(idMatch) != 2 { - continue - } + for _, match := range keyMatches { + uniqueTokens[match[1]] = struct{}{} + } - userPatMatch := strings.TrimSpace(idMatch[1]) + for _, match := range idMatches { + id := match[0][strings.LastIndex(match[0], " ")+1:] + uniqueIDs[id] = struct{}{} + } + for token := range uniqueTokens { + for id := range uniqueIDs { s1 := detectors.Result{ DetectorType: detectorspb.DetectorType_Alegra, - Raw: []byte(tokenPatMatch), - RawV2: []byte(tokenPatMatch + userPatMatch), + Raw: []byte(token), + RawV2: []byte(token + ":" + id), } if verify { - req, err := http.NewRequestWithContext(ctx, "GET", "https://api.alegra.com/api/v1/users", nil) - if err != nil { - continue - } - req.SetBasicAuth(userPatMatch, tokenPatMatch) - res, err := client.Do(req) - if err == nil { - defer res.Body.Close() - if res.StatusCode >= 200 && res.StatusCode < 300 { - s1.Verified = true - } + client := s.client + if client == nil { + client = defaultClient } + + isVerified, verificationErr := verifyCredentials(ctx, client, id, token) + s1.Verified = isVerified + s1.SetVerificationError(verificationErr, token) } results = append(results, s1) @@ -81,6 +79,32 @@ func (s Scanner) FromData(ctx context.Context, verify bool, data []byte) (result return results, nil } +func verifyCredentials(ctx context.Context, client *http.Client, username, token string) (bool, error) { + req, err := http.NewRequestWithContext(ctx, http.MethodGet, "https://api.alegra.com/api/v1/users/self", nil) + if err != nil { + return false, nil + } + req.SetBasicAuth(username, token) + + res, err := client.Do(req) + if err != nil { + return false, err + } + defer func() { + _, _ = io.Copy(io.Discard, res.Body) + _ = res.Body.Close() + }() + + switch res.StatusCode { + case http.StatusOK: + return true, nil + case http.StatusUnauthorized: + return false, nil + default: + return false, fmt.Errorf("unexpected HTTP response status %d", res.StatusCode) + } +} + func (s Scanner) Type() detectorspb.DetectorType { return detectorspb.DetectorType_Alegra } diff --git a/pkg/detectors/alegra/alegra_integration_test.go b/pkg/detectors/alegra/alegra_integration_test.go index 19913d9c8aeb..35961518bcb9 100644 --- a/pkg/detectors/alegra/alegra_integration_test.go +++ b/pkg/detectors/alegra/alegra_integration_test.go @@ -96,6 +96,7 @@ func TestAlegra_FromChunk(t *testing.T) { t.Fatalf("no raw secret present: \n %+v", got[i]) } got[i].Raw = nil + got[i].RawV2 = nil } if diff := pretty.Compare(got, tt.want); diff != "" { t.Errorf("Alegra.FromData() %s diff: (-got +want)\n%s", tt.name, diff) diff --git a/pkg/detectors/alegra/alegra_test.go b/pkg/detectors/alegra/alegra_test.go index d2eb6e3469a6..5594c9ba4c1f 100644 --- a/pkg/detectors/alegra/alegra_test.go +++ b/pkg/detectors/alegra/alegra_test.go @@ -14,7 +14,7 @@ import ( var ( validPattern = "wdvn-usa87a-fxp9ioas/testUser.1005@example.com" validSpecialCharPattern = "wdvn-usa87a-fxp9ioas / test-User.1005@example.com" - invalidPattern = "wdvn-usa87a-fxp9ioas/testUser$1005@example.com" + invalidPattern = "wdvn-usa87a-fxp9ioasQQsstestUsQQ@example" ) func TestAlegra_Pattern(t *testing.T) { @@ -28,22 +28,22 @@ func TestAlegra_Pattern(t *testing.T) { }{ { name: "valid pattern", - input: fmt.Sprintf("alegra: '%s'", validPattern), - want: []string{"wdvn-usa87a-fxp9ioastestUser.1005@example.com"}, + input: fmt.Sprintf("alegra: %s", validPattern), + want: []string{"wdvn-usa87a-fxp9ioas:wdvn-usa87a-fxp9ioas/testUser.1005@example.com"}, }, { name: "valid pattern - with special characters", - input: fmt.Sprintf("alegra: '%s'", validSpecialCharPattern), - want: []string{"wdvn-usa87a-fxp9ioastest-User.1005@example.com"}, + input: fmt.Sprintf("alegra: %s", validSpecialCharPattern), + want: []string{"wdvn-usa87a-fxp9ioas:test-User.1005@example.com"}, }, { name: "valid pattern - key out of prefix range", - input: fmt.Sprintf("alegra keyword is not close to the real key and id = '%s'", validPattern), + input: fmt.Sprintf("alegra keyword is not close to the real key and id = %s", validPattern), want: nil, }, { name: "invalid pattern", - input: fmt.Sprintf("alegra: '%s'", invalidPattern), + input: fmt.Sprintf("alegra: %s", invalidPattern), want: nil, }, } @@ -51,7 +51,7 @@ func TestAlegra_Pattern(t *testing.T) { for _, test := range tests { t.Run(test.name, func(t *testing.T) { matchedDetectors := ahoCorasickCore.FindDetectorMatches([]byte(test.input)) - if len(matchedDetectors) == 0 { + if len(matchedDetectors) == 0 && test.want != nil { t.Errorf("keywords '%v' not matched by: %s", d.Keywords(), test.input) return } @@ -63,11 +63,7 @@ func TestAlegra_Pattern(t *testing.T) { } 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)) - } + t.Errorf("expected %d results, got %d", len(test.want), len(results)) return } From 4cc10d3da1307ea5f4c55a202fb9c833a59c8dce Mon Sep 17 00:00:00 2001 From: Cody Rose Date: Thu, 24 Oct 2024 11:59:30 -0400 Subject: [PATCH 55/76] delete unused code (#3504) --- pkg/log/level.go | 70 ---------- pkg/log/log_test.go | 313 -------------------------------------------- 2 files changed, 383 deletions(-) diff --git a/pkg/log/level.go b/pkg/log/level.go index cc8f8d4336d8..99dae3cba653 100644 --- a/pkg/log/level.go +++ b/pkg/log/level.go @@ -2,10 +2,8 @@ package log import ( "sort" - "sync" "github.com/go-logr/logr" - "github.com/go-logr/zapr" "go.uber.org/zap" "go.uber.org/zap/zapcore" ) @@ -14,15 +12,6 @@ import ( var ( // Global, default log level control. globalLogLevel levelSetter = zap.NewAtomicLevel() - - // Map of name -> level control for independently setting log levels. A new - // control is registered via WithNamedLevel. This map is never cleaned up - // and new entries will overwrite previous values. Currently, this is - // acceptable behavior because WithNamedLevel is used sparingly. - globalControls map[string]levelSetter = make(map[string]levelSetter, 16) - // globalControls is protected (both read and write) by a mutex to make it - // thread safe. Access is low frequency, so performance is not a concern. - globalControlsLock sync.Mutex ) type levelSetter interface { @@ -45,65 +34,6 @@ func SetLevelForControl(control levelSetter, level int8) { control.SetLevel(zapcore.Level(-level)) } -// SetLevelFor sets the log level for a given named control. -func SetLevelFor(name string, level int8) { - globalControlsLock.Lock() - defer globalControlsLock.Unlock() - if control, ok := globalControls[name]; ok { - SetLevelForControl(control, level) - return - } - // Create a new control so registering a control with the same name will - // inherit the existing level. - globalControls[name] = newAtomicLevelAt(level) -} - -// AddLeveler adds a log level control to a logr.Logger. -func AddLeveler(l logr.Logger, control levelSetter) (logr.Logger, error) { - zapLogger, err := getZapLogger(l) - if err != nil { - return l, err - } - - zapLogger = zapLogger.WithOptions(zap.WrapCore(func(core zapcore.Core) zapcore.Core { - return NewLevelCore(core, control) - })) - return zapr.NewLogger(zapLogger), nil -} - -// WithNamedLevel creates a child logger with a new name and independent log -// level control (see SetLevelFor). NOTE: if name already exists, the existing -// controller will be used, otherwise a new controller is created with level -// matching the parent's log level. -func WithNamedLevel(logger logr.Logger, name string) logr.Logger { - logger = logger.WithName(name) - - globalControlsLock.Lock() - defer globalControlsLock.Unlock() - - var leveler levelSetter - if currentControl, ok := globalControls[name]; ok { - leveler = currentControl - } else { - leveler = newAtomicLevelAt(findLevel(logger)) - globalControls[name] = leveler - } - newLogger, err := AddLeveler(logger, leveler) - if err != nil { - return logger - } - return newLogger -} - -// newAtomicLevelAt is a helper function to create a zap.AtomicLevel -// initialized with a level. We cannot use zap.NewAtomicLevelAt here because of -// a quirk with logr levels (see SetLevelForControl). -func newAtomicLevelAt(level int8) zap.AtomicLevel { - control := zap.NewAtomicLevel() - SetLevelForControl(control, level) - return control -} - // findLevel probes a logr.Logger to figure out what level it is at via binary // search. We only search [0, 128), so worst case is ~7 checks. func findLevel(logger logr.Logger) int8 { diff --git a/pkg/log/log_test.go b/pkg/log/log_test.go index 65593b7890c4..b158ce2d975d 100644 --- a/pkg/log/log_test.go +++ b/pkg/log/log_test.go @@ -3,16 +3,12 @@ package log import ( "bytes" "encoding/json" - "fmt" "io" - "sort" "strings" - "sync" "testing" "time" "github.com/getsentry/sentry-go" - "github.com/go-logr/logr" "github.com/stretchr/testify/assert" "go.uber.org/zap" ) @@ -217,290 +213,6 @@ func TestWithLeveler(t *testing.T) { assert.Contains(t, buf2.String(), "line 3") } -func TestWithNamedLevelMoreVerbose(t *testing.T) { - var buf bytes.Buffer - globalControls = make(map[string]levelSetter, 16) - - l1 := zap.NewAtomicLevel() - logger, flush := New( - "service-name", - WithConsoleSink(&buf, WithLeveler(l1)), - ) - - childLogger := WithNamedLevel(logger, "child") - - SetLevelForControl(l1, 1) - SetLevelFor("child", 2) - - logger.V(0).Info("line 1") - logger.V(1).Info("line 2") - logger.V(2).Info("line 3") - childLogger.V(0).Info("line A") - childLogger.V(1).Info("line B") - childLogger.V(2).Info("line C") - assert.Nil(t, flush()) - - // output should contain up to verbosity 1 - assert.Equal(t, []string{ - "info-0\tservice-name\tline 1", - "info-1\tservice-name\tline 2", - "info-0\tservice-name.child\tline A", - "info-1\tservice-name.child\tline B", - }, splitLines(buf.String())) -} - -func TestWithNamedLevelLessVerbose(t *testing.T) { - var buf bytes.Buffer - globalControls = make(map[string]levelSetter, 16) - - l1 := zap.NewAtomicLevel() - logger, flush := New( - "service-name", - WithConsoleSink(&buf, WithLeveler(l1)), - ) - - childLogger := WithNamedLevel(logger, "child") - - SetLevelForControl(l1, 1) - SetLevelFor("child", 0) - - logger.V(0).Info("line 1") - logger.V(1).Info("line 2") - logger.V(2).Info("line 3") - childLogger.V(0).Info("line A") - childLogger.V(1).Info("line B") - childLogger.V(2).Info("line C") - assert.Nil(t, flush()) - - // output should contain up to verbosity 1 for parent - // and verbosity 0 for child - assert.Equal(t, []string{ - "info-0\tservice-name\tline 1", - "info-1\tservice-name\tline 2", - "info-0\tservice-name.child\tline A", - }, splitLines(buf.String())) -} - -func TestNestedWithNamedLevel(t *testing.T) { - var buf bytes.Buffer - globalControls = make(map[string]levelSetter, 16) - - grandParent, flush := New("grandParent", WithConsoleSink(&buf, WithLevel(1))) - parent := WithNamedLevel(grandParent, "parent") - child := WithNamedLevel(parent, "child") - - SetLevelFor("parent", 0) - SetLevelFor("child", 2) - - grandParent.V(0).Info("line 1") - parent.V(0).Info("line 2") - child.V(0).Info("line 3") - - grandParent.V(1).Info("line 4") - parent.V(1).Info("line 5") - child.V(1).Info("line 6") - - grandParent.V(2).Info("line 7") - parent.V(2).Info("line 8") - child.V(2).Info("line 9") - - assert.Nil(t, flush()) - - lines := splitLines(buf.String()) - assert.Equal(t, 4, len(lines)) - - assert.Equal(t, `info-0 grandParent line 1`, lines[0]) - assert.Equal(t, `info-0 grandParent.parent line 2`, lines[1]) - assert.Equal(t, `info-0 grandParent.parent.child line 3`, lines[2]) - assert.Equal(t, `info-1 grandParent line 4`, lines[3]) -} - -func TestSiblingsWithNamedLevel(t *testing.T) { - var buf bytes.Buffer - globalControls = make(map[string]levelSetter, 16) - - parent, flush := New("parent", WithConsoleSink(&buf, WithLevel(1))) - alice := WithNamedLevel(parent, "alice") - bob := WithNamedLevel(parent, "bob") - - SetLevelFor("alice", 0) - SetLevelFor("bob", 2) - - parent.V(0).Info("line 1") - alice.V(0).Info("line 2") - bob.V(0).Info("line 3") - - parent.V(1).Info("line 4") - alice.V(1).Info("line 5") - bob.V(1).Info("line 6") - - parent.V(2).Info("line 7") - alice.V(2).Info("line 8") - bob.V(2).Info("line 9") - - assert.Nil(t, flush()) - lines := splitLines(buf.String()) - assert.Equal(t, 5, len(lines)) - - assert.Equal(t, `info-0 parent line 1`, lines[0]) - assert.Equal(t, `info-0 parent.alice line 2`, lines[1]) - assert.Equal(t, `info-0 parent.bob line 3`, lines[2]) - assert.Equal(t, `info-1 parent line 4`, lines[3]) - assert.Equal(t, `info-1 parent.bob line 6`, lines[4]) -} - -func TestWithNamedLevelConcurrency(t *testing.T) { - var buf bytes.Buffer - globalControls = make(map[string]levelSetter, 16) - - parent, flush := New("parent", WithConsoleSink(&buf)) - - alice := WithNamedLevel(parent, "alice") - bob := WithNamedLevel(parent, "bob") - - var wg sync.WaitGroup - f := func(logger logr.Logger) { - defer wg.Done() - for i := 0; i < 100_000; i++ { - logger.Info(fmt.Sprintf("%06d", i)) - } - } - wg.Add(3) - go f(parent) - go f(alice) - go f(bob) - wg.Wait() - - assert.Nil(t, flush()) - logLines := splitLines(buf.String()) - assert.Equal(t, 300_000, len(logLines)) - sort.Slice(logLines, func(i, j int) bool { - return logLines[i] < logLines[j] - }) - - for i := 0; i < 100_000; i++ { - assert.Equal(t, fmt.Sprintf("info-0\tparent\t%06d", i), logLines[i]) - assert.Equal(t, fmt.Sprintf("info-0\tparent.alice\t%06d", i), logLines[i+100_000]) - assert.Equal(t, fmt.Sprintf("info-0\tparent.bob\t%06d", i), logLines[i+200_000]) - } -} - -func TestWithNamedLevelInheritance(t *testing.T) { - t.Run("child inherits parent level", func(t *testing.T) { - var buf bytes.Buffer - globalControls = make(map[string]levelSetter, 16) - - parent, flush := New("parent", WithConsoleSink(&buf, WithLevel(2))) - parent = parent.WithValues("key", "value") - // child will inherit parent's log level 2 - child := WithNamedLevel(parent, "child") - - parent.V(2).Info("yay") - child.V(2).Info("yay again") - assert.Nil(t, flush()) - - logLines := splitLines(buf.String()) - assert.Equal(t, []string{ - `info-2 parent yay {"key": "value"}`, - `info-2 parent.child yay again {"key": "value"}`, - }, logLines) - }) - - t.Run("child inherits existing named level", func(t *testing.T) { - var buf bytes.Buffer - globalControls = make(map[string]levelSetter, 16) - - parent, flush := New("parent", WithConsoleSink(&buf, WithLevel(2))) - parent = parent.WithValues("key", "value") - SetLevelFor("child", 0) - // child will inherit existing named level 0 - child := WithNamedLevel(parent, "child") - - parent.V(2).Info("yay") - child.V(2).Info("yay again") - assert.Nil(t, flush()) - - logLines := splitLines(buf.String()) - assert.Equal(t, []string{`info-2 parent yay {"key": "value"}`}, logLines) - }) -} - -func TestExistingChildLevel(t *testing.T) { - var buf bytes.Buffer - globalControls = make(map[string]levelSetter, 16) - - parent, flush := New("parent", WithConsoleSink(&buf, WithLevel(2))) - - SetLevelFor("child", 2) - // child should start with a level of 2 due to SetLevelFor above - child := WithNamedLevel(parent, "child") - - parent.V(2).Info("yay") - child.V(2).Info("yay again") - assert.Nil(t, flush()) - - assert.Contains(t, buf.String(), "info-2\tparent\tyay") - assert.Contains(t, buf.String(), "info-2\tparent.child\tyay again") -} - -func TestSinkWithNamedLevel(t *testing.T) { - var buf1, buf2 bytes.Buffer - globalControls = make(map[string]levelSetter, 16) - - parent, flush := New( - "parent", - WithConsoleSink(&buf1, WithLevel(0)), - WithConsoleSink(&buf2, WithLevel(2)), - ) - child := WithNamedLevel(parent, "child") - - for level := 0; level < 3; level++ { - SetLevelFor("child", int8(level)) - child.Info("") - child.V(1).Info("") - child.V(2).Info("") - } - assert.Nil(t, flush()) - - // buf1 should get only level 0 logs - assert.Equal(t, []string{ - "info-0\tparent.child", - "info-0\tparent.child", - "info-0\tparent.child", - }, splitLines(buf1.String())) - - assert.Equal(t, []string{ - // child level 0 - "info-0\tparent.child", - // child level 1 - "info-0\tparent.child", - "info-1\tparent.child", - // child level 2 - "info-0\tparent.child", - "info-1\tparent.child", - "info-2\tparent.child", - }, splitLines(buf2.String())) -} - -func TestAddLeveler(t *testing.T) { - l1, l2 := zap.NewAtomicLevel(), zap.NewAtomicLevel() - logger, _ := New("parent", WithConsoleSink(io.Discard, WithLeveler(l1))) - - t.Run("child level more verbose", func(t *testing.T) { - l1.SetLevel(0) - l2.SetLevel(1) - _, err := AddLeveler(logger, l2) - assert.Nil(t, err) - }) - - t.Run("child level less verbose", func(t *testing.T) { - l1.SetLevel(1) - l2.SetLevel(0) - _, err := AddLeveler(logger, l2) - assert.Nil(t, err) - }) -} - func splitLines(s string) []string { lines := strings.Split(strings.TrimSpace(s), "\n") logLines := make([]string, len(lines)) @@ -521,28 +233,3 @@ func TestFindLevel(t *testing.T) { assert.Equal(t, i8, findLevel(logger)) } } - -func TestOverwriteWithNamedLevel(t *testing.T) { - var buf bytes.Buffer - globalControls = make(map[string]levelSetter, 16) - - parent, flush := New( - "parent", - WithConsoleSink(&buf, WithLevel(2)), - ) - SetLevelFor("child", 0) - child1 := WithNamedLevel(parent, "child") - child2 := WithNamedLevel(parent, "child") - SetLevelFor("child", 2) - - child1.V(2).Info("") - child2.V(2).Info("") - - assert.Nil(t, flush()) - - // buf1 should get only level 0 logs - assert.Equal(t, []string{ - "info-2\tparent.child", - "info-2\tparent.child", - }, splitLines(buf.String())) -} From 01a2a4a3cc45c0735625c3e1653cb1f54ab61850 Mon Sep 17 00:00:00 2001 From: ahrav Date: Thu, 24 Oct 2024 09:40:23 -0700 Subject: [PATCH 56/76] remove debug log (#3505) --- pkg/sources/s3/s3.go | 1 - 1 file changed, 1 deletion(-) diff --git a/pkg/sources/s3/s3.go b/pkg/sources/s3/s3.go index f5df0fd3a0d1..8c3aabca85b3 100644 --- a/pkg/sources/s3/s3.go +++ b/pkg/sources/s3/s3.go @@ -131,7 +131,6 @@ func (s *Source) setMaxObjectSize(maxObjectSize int64) { func (s *Source) newClient(region, roleArn string) (*s3.S3, error) { cfg := aws.NewConfig() cfg.CredentialsChainVerboseErrors = aws.Bool(true) - cfg.LogLevel = aws.LogLevel(aws.LogDebugWithRequestErrors) cfg.Region = aws.String(region) switch cred := s.conn.GetCredential().(type) { From 1aa1871f9ae24a8c8a3a48a9345514acf42beb39 Mon Sep 17 00:00:00 2001 From: Sahil Silare <32628578+sahil9001@users.noreply.github.com> Date: Thu, 24 Oct 2024 22:46:39 +0530 Subject: [PATCH 57/76] fix: added correct api endpoint for verification & logic for Aeroworkflow (#3435) * fix: added correct api endpoint for verification * fix: fixed pattern detection logic in aeroworkflow --- pkg/detectors/aeroworkflow/aeroworkflow.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/detectors/aeroworkflow/aeroworkflow.go b/pkg/detectors/aeroworkflow/aeroworkflow.go index 4ec0022f0876..d5ce4b33f533 100644 --- a/pkg/detectors/aeroworkflow/aeroworkflow.go +++ b/pkg/detectors/aeroworkflow/aeroworkflow.go @@ -27,7 +27,7 @@ var ( defaultClient = common.SaneHttpClient() // Make sure that your group is surrounded in boundary characters such as below to reduce false positives. - keyPat = regexp.MustCompile(detectors.PrefixRegex([]string{"aeroworkflow"}) + `([a-zA-Z0-9^!?#:*;]{20})\b`) + keyPat = regexp.MustCompile(detectors.PrefixRegex([]string{"aeroworkflow"}) + `\b([a-zA-Z0-9^!?#:*;]{20})`) idPat = regexp.MustCompile(detectors.PrefixRegex([]string{"aeroworkflow"}) + `\b([0-9]{1,})\b`) ) @@ -85,7 +85,7 @@ func (s Scanner) FromData(ctx context.Context, verify bool, data []byte) (result } func verifyAeroworkflow(ctx context.Context, client *http.Client, resMatch, resIdMatch string) (bool, error) { - req, err := http.NewRequestWithContext(ctx, http.MethodGet, aeroworkflowURL+"/api/"+resIdMatch+"/v1/AeroAppointments", nil) + req, err := http.NewRequestWithContext(ctx, http.MethodGet, aeroworkflowURL+"/api/"+resIdMatch+"/me", nil) if err != nil { return false, err } From 0199e25a6019c3f048e47ecd5a6a7a336f2a8de1 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 24 Oct 2024 10:44:43 -0700 Subject: [PATCH 58/76] fix(deps): update module google.golang.org/api to v0.203.0 (#3497) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- go.mod | 4 ++-- go.sum | 4 ++++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/go.mod b/go.mod index e29107df6a1f..bdea691f1f95 100644 --- a/go.mod +++ b/go.mod @@ -108,7 +108,7 @@ require ( golang.org/x/oauth2 v0.23.0 golang.org/x/sync v0.8.0 golang.org/x/text v0.19.0 - google.golang.org/api v0.202.0 + google.golang.org/api v0.203.0 google.golang.org/protobuf v1.35.1 gopkg.in/h2non/gock.v1 v1.1.2 gopkg.in/yaml.v2 v2.4.0 @@ -121,7 +121,7 @@ require ( require ( cel.dev/expr v0.16.1 // indirect cloud.google.com/go v0.116.0 // indirect - cloud.google.com/go/auth v0.9.8 // indirect + cloud.google.com/go/auth v0.9.9 // indirect cloud.google.com/go/auth/oauth2adapt v0.2.4 // indirect cloud.google.com/go/compute/metadata v0.5.2 // indirect cloud.google.com/go/iam v1.2.1 // indirect diff --git a/go.sum b/go.sum index e3f027f88c28..f6f944e86d97 100644 --- a/go.sum +++ b/go.sum @@ -17,6 +17,8 @@ cloud.google.com/go/auth v0.9.5 h1:4CTn43Eynw40aFVr3GpPqsQponx2jv0BQpjvajsbbzw= cloud.google.com/go/auth v0.9.5/go.mod h1:Xo0n7n66eHyOWWCnitop6870Ilwo3PiZyodVkkH1xWM= cloud.google.com/go/auth v0.9.8 h1:+CSJ0Gw9iVeSENVCKJoLHhdUykDgXSc4Qn+gu2BRtR8= cloud.google.com/go/auth v0.9.8/go.mod h1:xxA5AqpDrvS+Gkmo9RqrGGRh6WSNKKOXhY3zNOr38tI= +cloud.google.com/go/auth v0.9.9 h1:BmtbpNQozo8ZwW2t7QJjnrQtdganSdmqeIBxHxNkEZQ= +cloud.google.com/go/auth v0.9.9/go.mod h1:xxA5AqpDrvS+Gkmo9RqrGGRh6WSNKKOXhY3zNOr38tI= cloud.google.com/go/auth/oauth2adapt v0.2.4 h1:0GWE/FUsXhf6C+jAkWgYm7X9tK8cuEIfy19DBn6B6bY= cloud.google.com/go/auth/oauth2adapt v0.2.4/go.mod h1:jC/jOpwFP6JBxhB3P5Rr0a9HLMC/Pe3eaL4NmdvqPtc= cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= @@ -1135,6 +1137,8 @@ google.golang.org/api v0.201.0 h1:+7AD9JNM3tREtawRMu8sOjSbb8VYcYXJG/2eEOmfDu0= google.golang.org/api v0.201.0/go.mod h1:HVY0FCHVs89xIW9fzf/pBvOEm+OolHa86G/txFezyq4= google.golang.org/api v0.202.0 h1:y1iuVHMqokQbimW79ZqPZWo4CiyFu6HcCYHwSNyzlfo= google.golang.org/api v0.202.0/go.mod h1:3Jjeq7M/SFblTNCp7ES2xhq+WvGL0KeXI0joHQBfwTQ= +google.golang.org/api v0.203.0 h1:SrEeuwU3S11Wlscsn+LA1kb/Y5xT8uggJSkIhD08NAU= +google.golang.org/api v0.203.0/go.mod h1:BuOVyCSYEPwJb3npWvDnNmFI92f3GeRnHNkETneT3SI= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= From 9cf0a4cb28189c69ee710071ef49b58c9d04a2f0 Mon Sep 17 00:00:00 2001 From: Helio Machado <0x2b3bfa0+git@googlemail.com> Date: Thu, 24 Oct 2024 21:16:43 +0200 Subject: [PATCH 59/76] Extend `algoliaadminkey` with additional checks (#3459) --- .../algoliaadminkey/algoliaadminkey.go | 91 ++++++++++++++++--- .../algoliaadminkey_integration_test.go | 2 + 2 files changed, 78 insertions(+), 15 deletions(-) diff --git a/pkg/detectors/algoliaadminkey/algoliaadminkey.go b/pkg/detectors/algoliaadminkey/algoliaadminkey.go index c9436ee11ff0..a72a5ddeecb7 100644 --- a/pkg/detectors/algoliaadminkey/algoliaadminkey.go +++ b/pkg/detectors/algoliaadminkey/algoliaadminkey.go @@ -2,6 +2,8 @@ package algoliaadminkey import ( "context" + "fmt" + "encoding/json" regexp "github.com/wasilibs/go-re2" "net/http" "strings" @@ -22,14 +24,14 @@ var ( client = common.SaneHttpClient() // Make sure that your group is surrounded in boundary characters such as below to reduce false positives. - keyPat = regexp.MustCompile(detectors.PrefixRegex([]string{"algolia"}) + `\b([a-zA-Z0-9]{32})\b`) - idPat = regexp.MustCompile(detectors.PrefixRegex([]string{"algolia"}) + `\b([A-Z0-9]{10})\b`) + keyPat = regexp.MustCompile(detectors.PrefixRegex([]string{"algolia", "docsearch", "apiKey"}) + `\b([a-zA-Z0-9]{32})\b`) + idPat = regexp.MustCompile(detectors.PrefixRegex([]string{"algolia", "docsearch", "appId"}) + `\b([A-Z0-9]{10})\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{"algolia"} + return []string{"algolia", "docsearch"} } // FromData will find and optionally verify AlgoliaAdminKey secrets in a given set of bytes. @@ -57,19 +59,16 @@ func (s Scanner) FromData(ctx context.Context, verify bool, data []byte) (result } if verify { - req, err := http.NewRequestWithContext(ctx, "GET", "https://"+resIdMatch+"-dsn.algolia.net/1/keys", nil) - if err != nil { - continue - } - req.Header.Add("X-Algolia-Application-Id", resIdMatch) - req.Header.Add("X-Algolia-API-Key", resMatch) - res, err := client.Do(req) - if err == nil { - defer res.Body.Close() - if res.StatusCode >= 200 && res.StatusCode < 300 { - s1.Verified = true - } + // Verify if the key is a valid Algolia Admin Key. + isVerified, verificationErr := verifyAlgoliaKey(ctx, resIdMatch, resMatch) + + // Verify if the key has sensitive permissions, even if it's not an Admin Key. + if !isVerified { + isVerified, verificationErr = verifyAlgoliaKeyACL(ctx, resIdMatch, resMatch) } + + s1.SetVerificationError(verificationErr, resMatch) + s1.Verified = isVerified } results = append(results, s1) @@ -78,6 +77,68 @@ func (s Scanner) FromData(ctx context.Context, verify bool, data []byte) (result return results, nil } +func verifyAlgoliaKey(ctx context.Context, appId, apiKey string) (bool, error) { + req, err := http.NewRequestWithContext(ctx, http.MethodGet, "https://"+appId+"-dsn.algolia.net/1/keys", nil) + if err != nil { + return false, err + } + + req.Header.Add("X-Algolia-Application-Id", appId) + req.Header.Add("X-Algolia-API-Key", apiKey) + + res, err := client.Do(req) + if err != nil { + return false, err + } + defer res.Body.Close() + + if res.StatusCode == 403 { + return false, nil + } else if res.StatusCode < 200 || res.StatusCode > 299 { + return false, fmt.Errorf("unexpected HTTP response status %d", res.StatusCode) + } + + return true, nil +} + +func verifyAlgoliaKeyACL(ctx context.Context, appId, apiKey string) (bool, error) { + req, err := http.NewRequestWithContext(ctx, http.MethodGet, "https://"+appId+".algolia.net/1/keys/"+apiKey, nil) + if err != nil { + return false, err + } + + req.Header.Add("X-Algolia-Application-Id", appId) + req.Header.Add("X-Algolia-API-Key", apiKey) + + res, err := client.Do(req) + if err != nil { + return false, err + } + defer res.Body.Close() + + if res.StatusCode == 403 { + return false, nil + } else if res.StatusCode < 200 || res.StatusCode > 299 { + return false, fmt.Errorf("unexpected HTTP response status %d", res.StatusCode) + } + + var jsonResponse struct { + ACL []string `json:"acl"` + } + + if err := json.NewDecoder(res.Body).Decode(&jsonResponse); err != nil { + return false, err + } + + for _, acl := range jsonResponse.ACL { + if acl != "search" && acl != "listIndexes" && acl != "settings" { + return true, nil // Other permissions are sensitive. + } + } + + return false, nil +} + func (s Scanner) Type() detectorspb.DetectorType { return detectorspb.DetectorType_AlgoliaAdminKey } diff --git a/pkg/detectors/algoliaadminkey/algoliaadminkey_integration_test.go b/pkg/detectors/algoliaadminkey/algoliaadminkey_integration_test.go index 3a6985580f32..a5fe493f280b 100644 --- a/pkg/detectors/algoliaadminkey/algoliaadminkey_integration_test.go +++ b/pkg/detectors/algoliaadminkey/algoliaadminkey_integration_test.go @@ -51,6 +51,7 @@ func TestAlgoliaAdminKey_FromChunk(t *testing.T) { { DetectorType: detectorspb.DetectorType_AlgoliaAdminKey, Verified: true, + RawV2: []byte(fmt.Sprintf("%s%s", secret, id)), }, }, wantErr: false, @@ -67,6 +68,7 @@ func TestAlgoliaAdminKey_FromChunk(t *testing.T) { { DetectorType: detectorspb.DetectorType_AlgoliaAdminKey, Verified: false, + RawV2: []byte(fmt.Sprintf("%s%s", inactiveSecret, id)), }, }, wantErr: false, From b48f748be0abf90cf984348fe84d9af092981e9f Mon Sep 17 00:00:00 2001 From: Sahil Silare <32628578+sahil9001@users.noreply.github.com> Date: Fri, 25 Oct 2024 11:17:06 +0530 Subject: [PATCH 60/76] fix: fixed verifcation pattern logic for `bulksms` (#3478) * fix: fixed verifcation pattern logic for `bulksms` * fix: addressed review comments * fix: added check to break the loop if a combination matches * fix: fixed key verification logic Signed-off-by: Sahil Silare --------- Signed-off-by: Sahil Silare --- pkg/detectors/bulksms/bulksms.go | 57 ++++++++++++++------------- pkg/detectors/bulksms/bulksms_test.go | 1 + 2 files changed, 31 insertions(+), 27 deletions(-) diff --git a/pkg/detectors/bulksms/bulksms.go b/pkg/detectors/bulksms/bulksms.go index b543fd5a7fed..0a80a97bb426 100644 --- a/pkg/detectors/bulksms/bulksms.go +++ b/pkg/detectors/bulksms/bulksms.go @@ -2,18 +2,17 @@ package bulksms import ( "context" - b64 "encoding/base64" - "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" ) -type Scanner struct{ +type Scanner struct { detectors.DefaultMultiPartCredentialProvider } @@ -24,12 +23,11 @@ var ( client = common.SaneHttpClient() // Make sure that your group is surrounded in boundary characters such as below to reduce false positives - keyPat = regexp.MustCompile(detectors.PrefixRegex([]string{"bulksms"}) + `\b([a-fA-Z0-9*]{29})\b`) + keyPat = regexp.MustCompile(detectors.PrefixRegex([]string{"bulksms"}) + `\b([a-zA-Z0-9!@#$%^&*()]{29})\b`) idPat = regexp.MustCompile(detectors.PrefixRegex([]string{"bulksms"}) + `\b([A-F0-9-]{37})\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{"bulksms"} } @@ -38,46 +36,51 @@ func (s Scanner) Keywords() []string { func (s Scanner) FromData(ctx context.Context, verify bool, data []byte) (results []detectors.Result, err error) { dataStr := string(data) - matches := keyPat.FindAllStringSubmatch(dataStr, -1) - idMatches := idPat.FindAllStringSubmatch(dataStr, -1) + var uniqueIds = make(map[string]struct{}) + var uniqueKeys = make(map[string]struct{}) - for _, match := range matches { - if len(match) != 2 { - continue - } - resMatch := strings.TrimSpace(match[1]) - for _, idmatch := range idMatches { - if len(match) != 2 { - continue - } - resIdMatch := strings.TrimSpace(idmatch[1]) + for _, match := range idPat.FindAllStringSubmatch(dataStr, -1) { + uniqueIds[match[1]] = struct{}{} + } + + for _, match := range keyPat.FindAllStringSubmatch(dataStr, -1) { + uniqueKeys[match[1]] = struct{}{} + } + for id := range uniqueIds { + for key := range uniqueKeys { s1 := detectors.Result{ DetectorType: detectorspb.DetectorType_Bulksms, - Raw: []byte(resMatch), - RawV2: []byte(resMatch + resIdMatch), + Raw: []byte(key), + RawV2: []byte(key + id), } if verify { - data := fmt.Sprintf("%s:%s", resIdMatch, resMatch) - sEnc := b64.StdEncoding.EncodeToString([]byte(data)) req, err := http.NewRequestWithContext(ctx, "GET", "https://api.bulksms.com/v1/messages", nil) if err != nil { continue } - req.Header.Add("Authorization", fmt.Sprintf("Basic %s", sEnc)) + req.SetBasicAuth(id, key) res, err := client.Do(req) if err == nil { - defer res.Body.Close() - if res.StatusCode >= 200 && res.StatusCode < 300 { + defer func() { + _, _ = io.Copy(io.Discard, res.Body) + _ = res.Body.Close() + }() + + if res.StatusCode == http.StatusOK { s1.Verified = true + results = append(results, s1) + // move to next id, by skipping remaining key's + break } + } else { + s1.SetVerificationError(err, key) } } results = append(results, s1) } - } return results, nil diff --git a/pkg/detectors/bulksms/bulksms_test.go b/pkg/detectors/bulksms/bulksms_test.go index b087cacc6ded..aed029be3775 100644 --- a/pkg/detectors/bulksms/bulksms_test.go +++ b/pkg/detectors/bulksms/bulksms_test.go @@ -96,6 +96,7 @@ func TestBulksms_FromChunk(t *testing.T) { t.Fatalf("no raw secret present: \n %+v", got[i]) } got[i].Raw = nil + got[i].RawV2 = nil } if diff := pretty.Compare(got, tt.want); diff != "" { t.Errorf("Bulksms.FromData() %s diff: (-got +want)\n%s", tt.name, diff) From e5d138d824cac29d3e99d41ffcda9e2b7397d12d Mon Sep 17 00:00:00 2001 From: Zachary Rice Date: Fri, 25 Oct 2024 12:11:14 -0500 Subject: [PATCH 61/76] Adds a logging section in the contributing guidelines (#3509) * adding logging section in contrib doc * sample line * Space --- CONTRIBUTING.md | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 16fe1035b2f9..786b4a806c76 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -11,3 +11,26 @@ Contributors need to [sign our CLA](https://cla-assistant.io/trufflesecurity/tru ## Adding new secret detectors We have published some [documentation and tooling to get started on adding new secret detectors](hack/docs/Adding_Detectors_external.md). Let's improve detection together! + +## Logging in TruffleHog + +**Use fields over format strings**. For structured logging, fields allow us to better filter and search through logs than embedding data in the message. + +**Differentiate logs coming from dependencies**. This can be done with a `"dep"` field that gets passed to the library. Sometimes it’s not possible to do this. + +Limit log levels to _**info**_ (indicate normal or expected operation) and _**error**_ (functionality is impeded and should be checked by an engineer) + +**Choose an appropriate verbosity level** +``` +0. — logs we always want to see +1. — logs we could possibly want to turn off +2. — logs that are useful for debugging +3. — frequently called logs that may produce a lot of output +4. — extremely verbose logs or logs containing sensitive information +5. — ultimate verbosity +``` +Example: `Logger().V(2).Info("skipping file: extension is ignored", "ext", mimeExt)` + +**Either log an error or return it**. Doing one or the other will help defer logging for when there is more context for it and prevent duplicate “bubbling up” logs. + +**Log contextual information**. Every log emitted should contain this context via fields to easily filter and search. From 0e03eca376eafec53088c67b17d9644c94031f85 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 26 Oct 2024 07:48:33 -0700 Subject: [PATCH 62/76] fix(deps): update module cloud.google.com/go/secretmanager to v1.14.2 (#3498) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- go.mod | 2 +- go.sum | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/go.mod b/go.mod index bdea691f1f95..4c7dc820271f 100644 --- a/go.mod +++ b/go.mod @@ -14,7 +14,7 @@ replace github.com/coinbase/waas-client-library-go => github.com/trufflesecurity replace github.com/STARRY-S/zip => github.com/STARRY-S/zip v0.1.0 require ( - cloud.google.com/go/secretmanager v1.14.1 + cloud.google.com/go/secretmanager v1.14.2 cloud.google.com/go/storage v1.45.0 github.com/Azure/go-autorest/autorest/azure/auth v0.5.13 github.com/AzureAD/microsoft-authentication-library-for-go v1.2.2 diff --git a/go.sum b/go.sum index f6f944e86d97..e22b776408ce 100644 --- a/go.sum +++ b/go.sum @@ -40,6 +40,8 @@ cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2k cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= cloud.google.com/go/secretmanager v1.14.1 h1:xlWSIg8rtBn5qCr2f3XtQP19+5COyf/ll49SEvi/0vM= cloud.google.com/go/secretmanager v1.14.1/go.mod h1:L+gO+u2JA9CCyXpSR8gDH0o8EV7i/f0jdBOrUXcIV0U= +cloud.google.com/go/secretmanager v1.14.2 h1:2XscWCfy//l/qF96YE18/oUaNJynAx749Jg3u0CjQr8= +cloud.google.com/go/secretmanager v1.14.2/go.mod h1:Q18wAPMM6RXLC/zVpWTlqq2IBSbbm7pKBlM3lCKsmjw= cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= cloud.google.com/go/storage v1.44.0 h1:abBzXf4UJKMmQ04xxJf9dYM/fNl24KHoTuBjyJDX2AI= From ceb6e8f40044aa9bca6015af230292cba5f7ac3c Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 26 Oct 2024 07:49:12 -0700 Subject: [PATCH 63/76] fix(deps): update module github.com/schollz/progressbar/v3 to v3.17.0 (#3510) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- go.mod | 2 +- go.sum | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/go.mod b/go.mod index 4c7dc820271f..6c7319a861ce 100644 --- a/go.mod +++ b/go.mod @@ -81,7 +81,7 @@ require ( github.com/prometheus/client_golang v1.20.5 github.com/rabbitmq/amqp091-go v1.10.0 github.com/sassoftware/go-rpmutils v0.4.0 - github.com/schollz/progressbar/v3 v3.16.1 + github.com/schollz/progressbar/v3 v3.17.0 github.com/sendgrid/sendgrid-go v3.16.0+incompatible github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 github.com/shuheiktgw/go-travis v0.3.1 diff --git a/go.sum b/go.sum index e22b776408ce..46e21755bd2f 100644 --- a/go.sum +++ b/go.sum @@ -711,6 +711,8 @@ github.com/sassoftware/go-rpmutils v0.4.0 h1:ojND82NYBxgwrV+mX1CWsd5QJvvEZTKddtC github.com/sassoftware/go-rpmutils v0.4.0/go.mod h1:3goNWi7PGAT3/dlql2lv3+MSN5jNYPjT5mVcQcIsYzI= github.com/schollz/progressbar/v3 v3.16.1 h1:RnF1neWZFzLCoGx8yp1yF7SDl4AzNDI5y4I0aUJRrZQ= github.com/schollz/progressbar/v3 v3.16.1/go.mod h1:I2ILR76gz5VXqYMIY/LdLecvMHDPVcQm3W/MSKi1TME= +github.com/schollz/progressbar/v3 v3.17.0 h1:Fv+vG6O6jnJwdjCelvfyYO7sF2jaUGQVmdH4CxcZdsQ= +github.com/schollz/progressbar/v3 v3.17.0/go.mod h1:5H4fLgifX+KeQCsEJnZTOepgZLe1jFF1lpPXb68IJTA= github.com/sendgrid/rest v2.6.9+incompatible h1:1EyIcsNdn9KIisLW50MKwmSRSK+ekueiEMJ7NEoxJo0= github.com/sendgrid/rest v2.6.9+incompatible/go.mod h1:kXX7q3jZtJXK5c5qK83bSGMdV6tsOE70KbHoqJls4lE= github.com/sendgrid/sendgrid-go v3.16.0+incompatible h1:i8eE6IMkiCy7vusSdacHHSBUpXyTcTXy/Rl9N9aZ/Qw= From 03d999caf57b676c1ba53ff4382b6cdd26b1b15c Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 26 Oct 2024 07:49:46 -0700 Subject: [PATCH 64/76] fix(deps): update module github.com/brianvoe/gofakeit/v7 to v7.1.1 (#3512) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- go.mod | 2 +- go.sum | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/go.mod b/go.mod index 6c7319a861ce..45b70a6a50ad 100644 --- a/go.mod +++ b/go.mod @@ -27,7 +27,7 @@ require ( github.com/bill-rich/go-syslog v0.0.0-20220413021637-49edb52a574c github.com/bitfinexcom/bitfinex-api-go v0.0.0-20210608095005-9e0b26f200fb github.com/bradleyfalzon/ghinstallation/v2 v2.11.0 - github.com/brianvoe/gofakeit/v7 v7.0.4 + github.com/brianvoe/gofakeit/v7 v7.1.1 github.com/charmbracelet/bubbles v0.18.0 github.com/charmbracelet/bubbletea v0.27.0 github.com/charmbracelet/glamour v0.7.0 diff --git a/go.sum b/go.sum index 46e21755bd2f..a8859b417cc0 100644 --- a/go.sum +++ b/go.sum @@ -176,6 +176,8 @@ github.com/bradleyfalzon/ghinstallation/v2 v2.11.0 h1:R9d0v+iobRHSaE4wKUnXFiZp53 github.com/bradleyfalzon/ghinstallation/v2 v2.11.0/go.mod h1:0LWKQwOHewXO/1acI6TtyE0Xc4ObDb2rFN7eHBAG71M= github.com/brianvoe/gofakeit/v7 v7.0.4 h1:Mkxwz9jYg8Ad8NvT9HA27pCMZGFQo08MK6jD0QTKEww= github.com/brianvoe/gofakeit/v7 v7.0.4/go.mod h1:QXuPeBw164PJCzCUZVmgpgHJ3Llj49jSLVkKPMtxtxA= +github.com/brianvoe/gofakeit/v7 v7.1.1 h1:/DEG+f/mFtqqNjhZ0AXA0aDzrnfE85AcAKVE+mMdxAQ= +github.com/brianvoe/gofakeit/v7 v7.1.1/go.mod h1:QXuPeBw164PJCzCUZVmgpgHJ3Llj49jSLVkKPMtxtxA= github.com/bwesterb/go-ristretto v1.2.3/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0= github.com/cenkalti/backoff/v4 v4.2.1 h1:y4OZtCnogmCPw98Zjyt5a6+QwPLGkiQsYW5oUqylYbM= github.com/cenkalti/backoff/v4 v4.2.1/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= From 6a367ab763b77c47c905bb950a801dbc6bfbe97c Mon Sep 17 00:00:00 2001 From: Kashif Khan <70996046+kashifkhan0771@users.noreply.github.com> Date: Mon, 28 Oct 2024 18:35:04 +0500 Subject: [PATCH 65/76] updated gcpapplicationdefaultcredentials detector results with RawV2 (#3499) * updated results with RawV2 * censored the refresh token in result --- .../gcpapplicationdefaultcredentials.go | 2 ++ .../gcpapplicationdefaultcredentials_test.go | 7 +++++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/pkg/detectors/gcpapplicationdefaultcredentials/gcpapplicationdefaultcredentials.go b/pkg/detectors/gcpapplicationdefaultcredentials/gcpapplicationdefaultcredentials.go index 3b2de9ebbc95..a732c16508d3 100644 --- a/pkg/detectors/gcpapplicationdefaultcredentials/gcpapplicationdefaultcredentials.go +++ b/pkg/detectors/gcpapplicationdefaultcredentials/gcpapplicationdefaultcredentials.go @@ -79,6 +79,8 @@ func (s Scanner) FromData(ctx context.Context, verify bool, data []byte) (result s1 := detectors.Result{ DetectorType: detectorspb.DetectorType_GCPApplicationDefaultCredentials, Raw: []byte(detectedClientID), + RawV2: []byte(detectedClientID + creds.RefreshToken), + Redacted: creds.RefreshToken[:3] + "..." + creds.RefreshToken[min(len(creds.RefreshToken)-1, 47):], // censor the refresh token } if verify { diff --git a/pkg/detectors/gcpapplicationdefaultcredentials/gcpapplicationdefaultcredentials_test.go b/pkg/detectors/gcpapplicationdefaultcredentials/gcpapplicationdefaultcredentials_test.go index 4d77c47ebcc8..bb60e754ec6e 100644 --- a/pkg/detectors/gcpapplicationdefaultcredentials/gcpapplicationdefaultcredentials_test.go +++ b/pkg/detectors/gcpapplicationdefaultcredentials/gcpapplicationdefaultcredentials_test.go @@ -2,10 +2,11 @@ package gcpapplicationdefaultcredentials import ( "context" + "testing" + "github.com/google/go-cmp/cmp" "github.com/trufflesecurity/trufflehog/v3/pkg/detectors" "github.com/trufflesecurity/trufflehog/v3/pkg/engine/ahocorasick" - "testing" ) func TestGcpapplicationdefaultcredentials_Pattern(t *testing.T) { @@ -24,7 +25,9 @@ func TestGcpapplicationdefaultcredentials_Pattern(t *testing.T) { "refresh_token": "1//0_joijgor3i4ut98579862709342j3kjJOIE02834jijfewoifjowiejfhghyzznfoiwejfwnvuhewiufnwinciwu_-o2i3jjfcc", "type": "authorized_user" }`, - want: []string{"191375729402-oiuj2498ry3497gjveoierj8294jfj41"}, + want: []string{ + "191375729402-oiuj2498ry3497gjveoierj8294jfj411//0_joijgor3i4ut98579862709342j3kjJOIE02834jijfewoifjowiejfhghyzznfoiwejfwnvuhewiufnwinciwu_-o2i3jjfcc", + }, }, } From 97fac39885e13c956c7a2bf4c60b9cfe8dc63f57 Mon Sep 17 00:00:00 2001 From: Kashif Khan <70996046+kashifkhan0771@users.noreply.github.com> Date: Mon, 28 Oct 2024 21:12:30 +0500 Subject: [PATCH 66/76] Addeded 403 account block status code handling for gitlab (#3471) * Addeded 403 account block status code handling for gitlab * resolved comments * removed unmarshalling logic --- pkg/detectors/gitlab/v1/gitlab.go | 35 +++++++++++++++++++-------- pkg/detectors/gitlab/v2/gitlab_v2.go | 36 +++++++++++++++++++++------- 2 files changed, 52 insertions(+), 19 deletions(-) diff --git a/pkg/detectors/gitlab/v1/gitlab.go b/pkg/detectors/gitlab/v1/gitlab.go index a4d57be56b2e..62a5db140e96 100644 --- a/pkg/detectors/gitlab/v1/gitlab.go +++ b/pkg/detectors/gitlab/v1/gitlab.go @@ -34,6 +34,8 @@ func (Scanner) CloudEndpoint() string { return "https://gitlab.com" } var ( defaultClient = common.SaneHttpClient() keyPat = regexp.MustCompile(detectors.PrefixRegex([]string{"gitlab"}) + `\b([a-zA-Z0-9\-=_]{20,22})\b`) + + BlockedUserMessage = "403 Forbidden - Your account has been blocked" ) // Keywords are used for efficiently pre-filtering chunks. @@ -60,6 +62,7 @@ func (s Scanner) FromData(ctx context.Context, verify bool, data []byte) (result s1 := detectors.Result{ DetectorType: detectorspb.DetectorType_Gitlab, Raw: []byte(resMatch), + ExtraData: map[string]string{}, } s1.ExtraData = map[string]string{ "rotation_guide": "https://howtorotate.com/docs/tutorials/gitlab/", @@ -67,8 +70,10 @@ func (s Scanner) FromData(ctx context.Context, verify bool, data []byte) (result } if verify { - isVerified, verificationErr := s.verifyGitlab(ctx, resMatch) + isVerified, extraData, verificationErr := s.verifyGitlab(ctx, resMatch) s1.Verified = isVerified + s1.ExtraData = extraData + s1.SetVerificationError(verificationErr, resMatch) } @@ -78,7 +83,7 @@ func (s Scanner) FromData(ctx context.Context, verify bool, data []byte) (result return results, nil } -func (s Scanner) verifyGitlab(ctx context.Context, resMatch string) (bool, error) { +func (s Scanner) verifyGitlab(ctx context.Context, resMatch string) (bool, map[string]string, error) { // there are 4 read 'scopes' for a gitlab token: api, read_user, read_repo, and read_registry // they all grant access to different parts of the API. I couldn't find an endpoint that every // one of these scopes has access to, so we just check an example endpoint for each scope. If any @@ -98,13 +103,14 @@ func (s Scanner) verifyGitlab(ctx context.Context, resMatch string) (bool, error req.Header.Add("Authorization", fmt.Sprintf("Bearer %s", resMatch)) res, err := client.Do(req) if err != nil { - return false, err + return false, nil, err } defer res.Body.Close() - body, err := io.ReadAll(res.Body) + + bodyBytes, err := io.ReadAll(res.Body) if err != nil { - return false, err + return false, nil, err } // 200 means good key and has `read_user` scope @@ -112,19 +118,28 @@ func (s Scanner) verifyGitlab(ctx context.Context, resMatch string) (bool, error // 401 is bad key switch res.StatusCode { case http.StatusOK: - return json.Valid(body), nil + return json.Valid(bodyBytes), nil, nil case http.StatusForbidden: + // check if the user account is blocked or not + stringBody := string(bodyBytes) + if strings.Contains(stringBody, BlockedUserMessage) { + return true, map[string]string{ + "blocked": "True", + }, nil + } + // Good key but not the right scope - return true, nil + return true, nil, nil case http.StatusUnauthorized: // Nothing to do; zero values are the ones we want - return false, nil + return false, nil, nil default: - return false, fmt.Errorf("unexpected HTTP response status %d", res.StatusCode) + return false, nil, fmt.Errorf("unexpected HTTP response status %d", res.StatusCode) } } - return false, nil + + return false, nil, nil } func (s Scanner) Type() detectorspb.DetectorType { diff --git a/pkg/detectors/gitlab/v2/gitlab_v2.go b/pkg/detectors/gitlab/v2/gitlab_v2.go index 19284fdd71dd..ee04aee6f2f4 100644 --- a/pkg/detectors/gitlab/v2/gitlab_v2.go +++ b/pkg/detectors/gitlab/v2/gitlab_v2.go @@ -3,6 +3,7 @@ package gitlab import ( "context" "fmt" + "io" "net/http" "strings" @@ -10,6 +11,7 @@ import ( "github.com/trufflesecurity/trufflehog/v3/pkg/common" "github.com/trufflesecurity/trufflehog/v3/pkg/detectors" + v1 "github.com/trufflesecurity/trufflehog/v3/pkg/detectors/gitlab/v1" "github.com/trufflesecurity/trufflehog/v3/pkg/pb/detectorspb" ) @@ -49,6 +51,7 @@ func (s Scanner) FromData(ctx context.Context, verify bool, data []byte) (result s1 := detectors.Result{ DetectorType: detectorspb.DetectorType_Gitlab, Raw: []byte(resMatch), + ExtraData: map[string]string{}, } s1.ExtraData = map[string]string{ "rotation_guide": "https://howtorotate.com/docs/tutorials/gitlab/", @@ -56,8 +59,10 @@ func (s Scanner) FromData(ctx context.Context, verify bool, data []byte) (result } if verify { - isVerified, verificationErr := s.verifyGitlab(ctx, resMatch) + isVerified, extraData, verificationErr := s.verifyGitlab(ctx, resMatch) s1.Verified = isVerified + s1.ExtraData = extraData + s1.SetVerificationError(verificationErr, resMatch) } @@ -67,7 +72,7 @@ func (s Scanner) FromData(ctx context.Context, verify bool, data []byte) (result return results, nil } -func (s Scanner) verifyGitlab(ctx context.Context, resMatch string) (bool, error) { +func (s Scanner) verifyGitlab(ctx context.Context, resMatch string) (bool, map[string]string, error) { // there are 4 read 'scopes' for a gitlab token: api, read_user, read_repo, and read_registry // they all grant access to different parts of the API. I couldn't find an endpoint that every // one of these scopes has access to, so we just check an example endpoint for each scope. If any @@ -86,28 +91,41 @@ func (s Scanner) verifyGitlab(ctx context.Context, resMatch string) (bool, error req.Header.Add("Authorization", fmt.Sprintf("Bearer %s", resMatch)) res, err := client.Do(req) if err != nil { - return false, err + return false, nil, err + } + defer res.Body.Close() + + bodyBytes, err := io.ReadAll(res.Body) + if err != nil { + return false, nil, err } - defer res.Body.Close() // The request body is unused. // 200 means good key and has `read_user` scope // 403 means good key but not the right scope // 401 is bad key switch res.StatusCode { case http.StatusOK: - return true, nil + return true, nil, nil case http.StatusForbidden: + // check if the user account is blocked or not + stringBody := string(bodyBytes) + if strings.Contains(stringBody, v1.BlockedUserMessage) { + return true, map[string]string{ + "blocked": "True", + }, nil + } + // Good key but not the right scope - return true, nil + return true, nil, nil case http.StatusUnauthorized: // Nothing to do; zero values are the ones we want - return false, nil + return false, nil, nil default: - return false, fmt.Errorf("unexpected HTTP response status %d", res.StatusCode) + return false, nil, fmt.Errorf("unexpected HTTP response status %d", res.StatusCode) } } - return false, nil + return false, nil, nil } func (s Scanner) Type() detectorspb.DetectorType { From ad15888a331ae796208628c555850a4db8298278 Mon Sep 17 00:00:00 2001 From: Cody Rose Date: Mon, 28 Oct 2024 12:20:42 -0400 Subject: [PATCH 67/76] Move DecoderType into ResultWithMetadata #3502 Result.DecoderType is only ever used by ResultWithMetadata (via its embedded Result). This unnecessarily complicates the relationship between the types and adds some warts to #3457, so this PR moves DecoderType directly into the only struct which actually uses it. --- pkg/detectors/detectors.go | 6 +++--- pkg/output/github_actions.go | 4 ++-- pkg/output/plain.go | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/pkg/detectors/detectors.go b/pkg/detectors/detectors.go index 71fc8514f452..14eccba8e5ec 100644 --- a/pkg/detectors/detectors.go +++ b/pkg/detectors/detectors.go @@ -89,9 +89,7 @@ type Result struct { DetectorType detectorspb.DetectorType // DetectorName is the name of the Detector. Used for custom detectors. DetectorName string - // DecoderType is the type of Decoder. - DecoderType detectorspb.DecoderType - Verified bool + Verified bool // Raw contains the raw secret identifier data. Prefer IDs over secrets since it is used for deduping after hashing. Raw []byte // RawV2 contains the raw secret identifier that is a combination of both the ID and the secret. @@ -168,6 +166,8 @@ type ResultWithMetadata struct { Result // Data from the sources.Chunk which this result was emitted for Data []byte + // DecoderType is the type of decoder that was used to generate this result's data. + DecoderType detectorspb.DecoderType } // CopyMetadata returns a detector result with included metadata from the source chunk. diff --git a/pkg/output/github_actions.go b/pkg/output/github_actions.go index e6beaaa8c7be..a88a7e4e3f36 100644 --- a/pkg/output/github_actions.go +++ b/pkg/output/github_actions.go @@ -19,7 +19,7 @@ type GitHubActionsPrinter struct{ mu sync.Mutex } func (p *GitHubActionsPrinter) Print(_ context.Context, r *detectors.ResultWithMetadata) error { out := gitHubActionsOutputFormat{ DetectorType: r.Result.DetectorType.String(), - DecoderType: r.Result.DecoderType.String(), + DecoderType: r.DecoderType.String(), Verified: r.Result.Verified, } @@ -60,7 +60,7 @@ func (p *GitHubActionsPrinter) Print(_ context.Context, r *detectors.ResultWithM dedupeCache[key] = struct{}{} message := fmt.Sprintf("Found %s %s result 🐷🔑\n", verifiedStatus, out.DetectorType) - if r.Result.DecoderType != detectorspb.DecoderType_PLAIN { + if r.DecoderType != detectorspb.DecoderType_PLAIN { message = fmt.Sprintf("Found %s %s result with %s encoding 🐷🔑\n", verifiedStatus, out.DetectorType, out.DecoderType) } diff --git a/pkg/output/plain.go b/pkg/output/plain.go index 202e44cc4f17..91e4c8abb072 100644 --- a/pkg/output/plain.go +++ b/pkg/output/plain.go @@ -30,7 +30,7 @@ type PlainPrinter struct{ mu sync.Mutex } func (p *PlainPrinter) Print(_ context.Context, r *detectors.ResultWithMetadata) error { out := outputFormat{ DetectorType: r.Result.DetectorType.String(), - DecoderType: r.Result.DecoderType.String(), + DecoderType: r.DecoderType.String(), Verified: r.Result.Verified, VerificationError: r.Result.VerificationError(), MetaData: r.SourceMetadata, From fa9c4421dca30d27b69b7a01f6b6f78de548ea10 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 28 Oct 2024 09:23:23 -0700 Subject: [PATCH 68/76] fix(deps): update github.com/tailscale/depaware digest to 3d7f3b3 (#3518) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- go.mod | 2 +- go.sum | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/go.mod b/go.mod index 45b70a6a50ad..6c9d10cefcda 100644 --- a/go.mod +++ b/go.mod @@ -87,7 +87,7 @@ require ( github.com/shuheiktgw/go-travis v0.3.1 github.com/snowflakedb/gosnowflake v1.11.2 github.com/stretchr/testify v1.9.0 - github.com/tailscale/depaware v0.0.0-20240804103531-585336c3e1b3 + github.com/tailscale/depaware v0.0.0-20241028160002-3d7f3b30ed0e github.com/testcontainers/testcontainers-go v0.34.0 github.com/testcontainers/testcontainers-go/modules/elasticsearch v0.34.0 github.com/testcontainers/testcontainers-go/modules/mongodb v0.34.0 diff --git a/go.sum b/go.sum index a8859b417cc0..bf483f93330a 100644 --- a/go.sum +++ b/go.sum @@ -764,6 +764,8 @@ github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsT github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/tailscale/depaware v0.0.0-20240804103531-585336c3e1b3 h1:1wRadBXZ4ddC71FYpzDTS3weuj0IOgmeptZtgTDGU7g= github.com/tailscale/depaware v0.0.0-20240804103531-585336c3e1b3/go.mod h1:p9lPsd+cx33L3H9nNoecRRxPssFKUwwI50I3pZ0yT+8= +github.com/tailscale/depaware v0.0.0-20241028160002-3d7f3b30ed0e h1:Hb50wYyy5VblH5zpKkoy49TrJy3pxVWOaRSOEdzTWKA= +github.com/tailscale/depaware v0.0.0-20241028160002-3d7f3b30ed0e/go.mod h1:p9lPsd+cx33L3H9nNoecRRxPssFKUwwI50I3pZ0yT+8= github.com/testcontainers/testcontainers-go v0.33.0 h1:zJS9PfXYT5O0ZFXM2xxXfk4J5UMw/kRiISng037Gxdw= github.com/testcontainers/testcontainers-go v0.33.0/go.mod h1:W80YpTa8D5C3Yy16icheD01UTDu+LmXIA2Keo+jWtT8= github.com/testcontainers/testcontainers-go v0.34.0 h1:5fbgF0vIN5u+nD3IWabQwRybuB4GY8G2HHgCkbMzMHo= From c6aa491201de6cb04b9243d29ae66f86e9504755 Mon Sep 17 00:00:00 2001 From: Sahil Silare <32628578+sahil9001@users.noreply.github.com> Date: Mon, 28 Oct 2024 21:56:14 +0530 Subject: [PATCH 69/76] fix: fixed validation logic for `calendarific` (#3480) --- pkg/detectors/calendarific/calendarific.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/pkg/detectors/calendarific/calendarific.go b/pkg/detectors/calendarific/calendarific.go index 33429723ba8c..58637171b24e 100644 --- a/pkg/detectors/calendarific/calendarific.go +++ b/pkg/detectors/calendarific/calendarific.go @@ -2,10 +2,11 @@ package calendarific import ( "context" - regexp "github.com/wasilibs/go-re2" "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" @@ -20,7 +21,7 @@ var ( client = common.SaneHttpClient() // Make sure that your group is surrounded in boundary characters such as below to reduce false positives. - keyPat = regexp.MustCompile(detectors.PrefixRegex([]string{"calendarific"}) + `\b([a-z0-9]{40})\b`) + keyPat = regexp.MustCompile(detectors.PrefixRegex([]string{"calendarific"}) + `\b([a-zA-Z0-9]{32})\b`) ) // Keywords are used for efficiently pre-filtering chunks. From f164ebcd88000e363a6acb0f972f8b867b08302a Mon Sep 17 00:00:00 2001 From: Kashif Khan <70996046+kashifkhan0771@users.noreply.github.com> Date: Mon, 28 Oct 2024 23:09:14 +0500 Subject: [PATCH 70/76] Handle custom detector response and include in extra data (#3411) * Handle custom detector response and include in extra data * Added todo * fixed panic * simplicity is always good * limit the response to 200 chars * results should print now in output --- pkg/custom_detectors/custom_detectors.go | 34 ++++++++++++++++++------ pkg/detectors/meraki/meraki.go | 3 ++- 2 files changed, 28 insertions(+), 9 deletions(-) diff --git a/pkg/custom_detectors/custom_detectors.go b/pkg/custom_detectors/custom_detectors.go index 602e7f89bd52..7579324dc583 100644 --- a/pkg/custom_detectors/custom_detectors.go +++ b/pkg/custom_detectors/custom_detectors.go @@ -4,6 +4,7 @@ import ( "bytes" "context" "encoding/json" + "io" "net/http" "regexp" "strings" @@ -101,10 +102,6 @@ func (c *CustomRegexWebhook) FromData(ctx context.Context, verify bool, data []b close(resultsCh) for result := range resultsCh { - // NOTE: I don't believe this is being set anywhere else, hence the map assignment. - result.ExtraData = map[string]string{ - "name": c.GetName(), - } results = append(results, result) } @@ -129,6 +126,7 @@ func (c *CustomRegexWebhook) createResults(ctx context.Context, match map[string DetectorType: detectorspb.DetectorType_CustomRegex, DetectorName: c.GetName(), Raw: []byte(raw), + ExtraData: map[string]string{}, } if !verify { @@ -166,14 +164,34 @@ func (c *CustomRegexWebhook) createResults(ctx context.Context, match map[string } req.Header.Add(key, strings.TrimLeft(value, "\t\n\v\f\r ")) } - res, err := httpClient.Do(req) + resp, err := httpClient.Do(req) if err != nil { continue } - // TODO: Read response body. - res.Body.Close() - if res.StatusCode == http.StatusOK { + defer func() { + _, _ = io.Copy(io.Discard, resp.Body) + _ = resp.Body.Close() + }() + + if resp.StatusCode == http.StatusOK { + // mark the result as verified result.Verified = true + + body, err := io.ReadAll(resp.Body) + if err != nil { + continue + } + + // TODO: handle different content-type responses seperatly when implement custom detector configurations + responseStr := string(body) + // truncate to 200 characters if response length exceeds 200 + if len(responseStr) > 200 { + responseStr = responseStr[:200] + } + + // store the processed response in ExtraData + result.ExtraData["response"] = responseStr + break } } diff --git a/pkg/detectors/meraki/meraki.go b/pkg/detectors/meraki/meraki.go index 9aed559f4861..e326e84ced34 100644 --- a/pkg/detectors/meraki/meraki.go +++ b/pkg/detectors/meraki/meraki.go @@ -4,10 +4,11 @@ import ( "context" "encoding/json" "fmt" - regexp "github.com/wasilibs/go-re2" "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" From fe9cd2675c6a49e40c2a5cb445e9515aeecc06ff Mon Sep 17 00:00:00 2001 From: dylanTruffle <52866392+dylanTruffle@users.noreply.github.com> Date: Mon, 28 Oct 2024 11:26:44 -0700 Subject: [PATCH 71/76] Adding basic "what is trufflehog" to the readme (#3514) * Update README.md * Update README.md * Update README.md --------- Co-authored-by: Dustin Decker --- README.md | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/README.md b/README.md index 6d0ab298c801..5fe0dd350769 100644 --- a/README.md +++ b/README.md @@ -36,6 +36,26 @@ We take the revenue from the enterprise product to fund more awesome open source +# What is TruffleHog 🐽 + +TruffleHog is the most powerful secrets **Discovery, Classification, Validation,** and **Analysis** tool. In this context secret refers to a credential a machine uses to authenticate itself to another machine. This includes API keys, database passwords, private encryption keys, and more... + +## Discovery 🔍 + +TruffleHog can look for secrets in many places including Git, chats, wikis, logs, API testing platforms, object stores, filesystems and more + +## Classification 📁 + +TruffleHog classifies over 800 secret types, mapping them back to the specific identity they belong to. Is it an AWS secret? Stripe secret? Cloudflare secret? Postgres password? SSL Private key? Sometimes its hard to tell looking at it, so TruffleHog classifies everything it finds. + +## Validation ✅ + +For every secret TruffleHog can classify, it can also log in to confirm if that secret is live or not. This step is critical to know if there’s an active present danger or not. + +## Analysis 🔬 + +For the 20 some of the most commonly leaked out credential types, instead of sending one request to check if the secret can log in, TruffleHog can send many requests to learn everything there is to know about the secret. Who created it? What resources can it access? What permissions does it have on those resources? + # :loudspeaker: Join Our Community Have questions? Feedback? Jump in slack or discord and hang out with us From f42f63271b783c763cf3b5571411943df1c137fd Mon Sep 17 00:00:00 2001 From: Cody Rose Date: Tue, 29 Oct 2024 09:44:07 -0400 Subject: [PATCH 72/76] Create global log redaction capability (#3522) Some source use client libraries that can emit errors that contain sensitive information - in particular, git-facing libraries that embed tokens into repository URLs. This PR introduces a way of redacting them - starting with GitLab (where we've seen this most recently), but in theory extensible to other sources as needed. This implementation uses a custom zap core; this might also be possible with a custom zap encoder, but I didn't test it out. (The deleted core.go file was entirely unused.) --- main.go | 14 ++-- pkg/log/core.go | 41 ------------ pkg/log/dynamic_redactor.go | 50 ++++++++++++++ pkg/log/level.go | 1 - pkg/log/log.go | 30 ++++++--- pkg/log/log_test.go | 125 ++++++++++++++++++++++++++++++++++- pkg/log/redaction_core.go | 42 ++++++++++++ pkg/sources/gitlab/gitlab.go | 4 ++ 8 files changed, 247 insertions(+), 60 deletions(-) delete mode 100644 pkg/log/core.go create mode 100644 pkg/log/dynamic_redactor.go create mode 100644 pkg/log/redaction_core.go diff --git a/main.go b/main.go index f5b629fb7ae6..a1a1510d46e0 100644 --- a/main.go +++ b/main.go @@ -27,10 +27,10 @@ import ( "github.com/trufflesecurity/trufflehog/v3/pkg/config" "github.com/trufflesecurity/trufflehog/v3/pkg/context" "github.com/trufflesecurity/trufflehog/v3/pkg/engine" + "github.com/trufflesecurity/trufflehog/v3/pkg/feature" "github.com/trufflesecurity/trufflehog/v3/pkg/handlers" "github.com/trufflesecurity/trufflehog/v3/pkg/log" "github.com/trufflesecurity/trufflehog/v3/pkg/output" - "github.com/trufflesecurity/trufflehog/v3/pkg/feature" "github.com/trufflesecurity/trufflehog/v3/pkg/sources" "github.com/trufflesecurity/trufflehog/v3/pkg/tui" "github.com/trufflesecurity/trufflehog/v3/pkg/updater" @@ -72,10 +72,10 @@ var ( jobReportFile = cli.Flag("output-report", "Write a scan report to the provided path.").Hidden().OpenFile(os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0666) // Add feature flags - forceSkipBinaries = cli.Flag("force-skip-binaries", "Force skipping binaries.").Bool() - forceSkipArchives = cli.Flag("force-skip-archives", "Force skipping archives.").Bool() + forceSkipBinaries = cli.Flag("force-skip-binaries", "Force skipping binaries.").Bool() + forceSkipArchives = cli.Flag("force-skip-archives", "Force skipping archives.").Bool() skipAdditionalRefs = cli.Flag("skip-additional-refs", "Skip additional references.").Bool() - userAgentSuffix = cli.Flag("user-agent-suffix", "Suffix to add to User-Agent.").String() + userAgentSuffix = cli.Flag("user-agent-suffix", "Suffix to add to User-Agent.").String() gitScan = cli.Command("git", "Find credentials in git repositories.") gitScanURI = gitScan.Arg("uri", "Git repository URL. https://, file://, or ssh:// schema expected.").Required().String() @@ -285,7 +285,7 @@ func main() { if *jsonOut { logFormat = log.WithJSONSink } - logger, sync := log.New("trufflehog", logFormat(os.Stderr)) + logger, sync := log.New("trufflehog", logFormat(os.Stderr, log.WithGlobalRedaction())) // make it the default logger for contexts context.SetDefaultLogger(logger) @@ -375,7 +375,7 @@ func run(state overseer.State) { }() } - // Set feature configurations from CLI flags + // Set feature configurations from CLI flags if *forceSkipBinaries { feature.ForceSkipBinaries.Store(true) } @@ -383,7 +383,7 @@ func run(state overseer.State) { if *forceSkipArchives { feature.ForceSkipArchives.Store(true) } - + if *skipAdditionalRefs { feature.SkipAdditionalRefs.Store(true) } diff --git a/pkg/log/core.go b/pkg/log/core.go deleted file mode 100644 index 49a961c8ce80..000000000000 --- a/pkg/log/core.go +++ /dev/null @@ -1,41 +0,0 @@ -package log - -import ( - "go.uber.org/zap/zapcore" -) - -type levelFilterCore struct { - core zapcore.Core - level zapcore.LevelEnabler -} - -// NewLevelCore creates a core that can be used to independently control the -// level of an existing Core. This is essentially a filter that will only log -// if both the parent and the wrapper cores are enabled. -func NewLevelCore(core zapcore.Core, level zapcore.LevelEnabler) zapcore.Core { - return &levelFilterCore{core, level} -} - -func (c *levelFilterCore) Enabled(lvl zapcore.Level) bool { - return c.level.Enabled(lvl) -} - -func (c *levelFilterCore) With(fields []zapcore.Field) zapcore.Core { - return &levelFilterCore{c.core.With(fields), c.level} -} - -func (c *levelFilterCore) Check(ent zapcore.Entry, ce *zapcore.CheckedEntry) *zapcore.CheckedEntry { - if !c.Enabled(ent.Level) { - return ce - } - - return c.core.Check(ent, ce) -} - -func (c *levelFilterCore) Write(ent zapcore.Entry, fields []zapcore.Field) error { - return c.core.Write(ent, fields) -} - -func (c *levelFilterCore) Sync() error { - return c.core.Sync() -} diff --git a/pkg/log/dynamic_redactor.go b/pkg/log/dynamic_redactor.go new file mode 100644 index 000000000000..34ed0cbb3f72 --- /dev/null +++ b/pkg/log/dynamic_redactor.go @@ -0,0 +1,50 @@ +package log + +import ( + "strings" + "sync" + "sync/atomic" +) + +type dynamicRedactor struct { + denySet map[string]struct{} + denySlice []string + denyMu sync.Mutex + + replacer atomic.Pointer[strings.Replacer] +} + +var globalRedactor *dynamicRedactor + +func init() { + globalRedactor = &dynamicRedactor{denySet: make(map[string]struct{})} + globalRedactor.replacer.CompareAndSwap(nil, strings.NewReplacer()) +} + +// RedactGlobally configures the global log redactor to redact the provided value during log emission. The value will be +// redacted in log messages and values that are strings, but not in log keys or values of other types. +func RedactGlobally(sensitiveValue string) { + globalRedactor.configureForRedaction(sensitiveValue) +} + +func (r *dynamicRedactor) configureForRedaction(sensitiveValue string) { + if sensitiveValue == "" { + return + } + + r.denyMu.Lock() + defer r.denyMu.Unlock() + + if _, ok := r.denySet[sensitiveValue]; ok { + return + } + + r.denySet[sensitiveValue] = struct{}{} + r.denySlice = append(r.denySlice, sensitiveValue, "*****") + + r.replacer.Store(strings.NewReplacer(r.denySlice...)) +} + +func (r *dynamicRedactor) redact(s string) string { + return r.replacer.Load().Replace(s) +} diff --git a/pkg/log/level.go b/pkg/log/level.go index 99dae3cba653..d3c23b078f76 100644 --- a/pkg/log/level.go +++ b/pkg/log/level.go @@ -8,7 +8,6 @@ import ( "go.uber.org/zap/zapcore" ) -// TODO: Use a struct to make testing easier. var ( // Global, default log level control. globalLogLevel levelSetter = zap.NewAtomicLevel() diff --git a/pkg/log/log.go b/pkg/log/log.go index 41fbcae08478..35f6b10b9427 100644 --- a/pkg/log/log.go +++ b/pkg/log/log.go @@ -83,9 +83,10 @@ func WithSentry(opts sentry.ClientOptions, tags map[string]string) logConfig { } type sinkConfig struct { - encoder zapcore.Encoder - sink zapcore.WriteSyncer - level levelSetter + encoder zapcore.Encoder + sink zapcore.WriteSyncer + level levelSetter + redactor *dynamicRedactor } // WithJSONSink adds a JSON encoded output to the logger. @@ -176,6 +177,13 @@ func WithLeveler(leveler levelSetter) func(*sinkConfig) { } } +// WithGlobalRedaction adds values to be redacted from logs. +func WithGlobalRedaction() func(*sinkConfig) { + return func(conf *sinkConfig) { + conf.redactor = globalRedactor + } +} + // firstErrorFunc is a helper function that returns a function that executes // all provided args and returns the first error, if any. func firstErrorFunc(fs ...func() error) func() error { @@ -209,11 +217,15 @@ func newCoreConfig( for _, f := range opts { f(&conf) } - return logConfig{ - core: zapcore.NewCore( - conf.encoder, - conf.sink, - conf.level, - ), + core := zapcore.NewCore( + conf.encoder, + conf.sink, + conf.level, + ) + + if conf.redactor == nil { + return logConfig{core: core} } + + return logConfig{core: NewRedactionCore(core, conf.redactor)} } diff --git a/pkg/log/log_test.go b/pkg/log/log_test.go index b158ce2d975d..f1dced5e4d3c 100644 --- a/pkg/log/log_test.go +++ b/pkg/log/log_test.go @@ -10,14 +10,15 @@ import ( "github.com/getsentry/sentry-go" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" "go.uber.org/zap" ) func TestNew(t *testing.T) { var jsonBuffer, consoleBuffer bytes.Buffer logger, flush := New("service-name", - WithJSONSink(&jsonBuffer), - WithConsoleSink(&consoleBuffer), + WithJSONSink(&jsonBuffer, WithGlobalRedaction()), + WithConsoleSink(&consoleBuffer, WithGlobalRedaction()), ) logger.Info("yay") assert.Nil(t, flush()) @@ -233,3 +234,123 @@ func TestFindLevel(t *testing.T) { assert.Equal(t, i8, findLevel(logger)) } } + +func TestGlobalRedaction_Console(t *testing.T) { + oldState := globalRedactor + globalRedactor = &dynamicRedactor{ + denySet: make(map[string]struct{}), + } + defer func() { globalRedactor = oldState }() + + var buf bytes.Buffer + logger, flush := New("console-redaction-test", + WithConsoleSink(&buf, WithGlobalRedaction()), + ) + RedactGlobally("foo") + RedactGlobally("bar") + + logger.Info("this foo is :bar", + "foo", "bar", + "array", []string{"foo", "bar", "baz"}, + "object", map[string]string{"foo": "bar"}) + require.NoError(t, flush()) + + gotParts := strings.Split(buf.String(), "\t")[1:] // The first item is the timestamp + wantParts := []string{ + "info-0", + "console-redaction-test", + "this ***** is :*****", + "{\"foo\": \"*****\", \"array\": [\"foo\", \"bar\", \"baz\"], \"object\": {\"foo\":\"bar\"}}\n", + } + assert.Equal(t, wantParts, gotParts) +} + +func TestGlobalRedaction_JSON(t *testing.T) { + oldState := globalRedactor + globalRedactor = &dynamicRedactor{ + denySet: make(map[string]struct{}), + } + defer func() { globalRedactor = oldState }() + + var jsonBuffer bytes.Buffer + logger, flush := New("json-redaction-test", + WithJSONSink(&jsonBuffer, WithGlobalRedaction()), + ) + RedactGlobally("foo") + RedactGlobally("bar") + logger.Info("this foo is :bar", + "foo", "bar", + "array", []string{"foo", "bar", "baz"}, + "object", map[string]string{"foo": "bar"}) + require.NoError(t, flush()) + + var parsedJSON map[string]any + require.NoError(t, json.Unmarshal(jsonBuffer.Bytes(), &parsedJSON)) + assert.NotEmpty(t, parsedJSON["ts"]) + delete(parsedJSON, "ts") + assert.Equal(t, + map[string]any{ + "level": "info-0", + "logger": "json-redaction-test", + "msg": "this ***** is :*****", + "foo": "*****", + "array": []any{"foo", "bar", "baz"}, + "object": map[string]interface{}{"foo": "bar"}, + }, + parsedJSON, + ) +} + +func BenchmarkLoggerRedact(b *testing.B) { + msg := "this is a message with 'foo' in it" + logKvps := []any{"key", "value", "foo", "bar", "bar", "baz", "longval", "84hblnqwp97ewilbgoab8fhqlngahs6dl3i269haa"} + redactor := &dynamicRedactor{denySet: make(map[string]struct{})} + redactor.replacer.CompareAndSwap(nil, strings.NewReplacer()) + + b.Run("no redaction", func(b *testing.B) { + logger, flush := New("redaction-benchmark", WithJSONSink( + io.Discard, + func(conf *sinkConfig) { conf.redactor = redactor }, + )) + for i := 0; i < b.N; i++ { + logger.Info(msg, logKvps...) + } + require.NoError(b, flush()) + }) + b.Run("1 redaction", func(b *testing.B) { + logger, flush := New("redaction-benchmark", WithJSONSink( + io.Discard, + func(conf *sinkConfig) { conf.redactor = redactor }, + )) + redactor.configureForRedaction("84hblnqwp97ewilbgoab8fhqlngahs6dl3i269haa") + for i := 0; i < b.N; i++ { + logger.Info(msg, logKvps...) + } + require.NoError(b, flush()) + }) + b.Run("2 redactions", func(b *testing.B) { + logger, flush := New("redaction-benchmark", WithJSONSink( + io.Discard, + func(conf *sinkConfig) { conf.redactor = redactor }, + )) + redactor.configureForRedaction("84hblnqwp97ewilbgoab8fhqlngahs6dl3i269haa") + redactor.configureForRedaction("foo") + for i := 0; i < b.N; i++ { + logger.Info(msg, logKvps...) + } + require.NoError(b, flush()) + }) + b.Run("3 redactions", func(b *testing.B) { + logger, flush := New("redaction-benchmark", WithJSONSink( + io.Discard, + func(conf *sinkConfig) { conf.redactor = redactor }, + )) + redactor.configureForRedaction("84hblnqwp97ewilbgoab8fhqlngahs6dl3i269haa") + redactor.configureForRedaction("foo") + redactor.configureForRedaction("bar") + for i := 0; i < b.N; i++ { + logger.Info(msg, logKvps...) + } + require.NoError(b, flush()) + }) +} diff --git a/pkg/log/redaction_core.go b/pkg/log/redaction_core.go new file mode 100644 index 000000000000..11237ac518c4 --- /dev/null +++ b/pkg/log/redaction_core.go @@ -0,0 +1,42 @@ +package log + +import ( + "go.uber.org/zap/zapcore" +) + +// redactionCore wraps a zapcore.Core to perform redaction of log messages in +// the message and field values. +type redactionCore struct { + zapcore.Core + redactor *dynamicRedactor +} + +// NewRedactionCore creates a zapcore.Core that performs redaction of logs in +// the message and field values. +func NewRedactionCore(core zapcore.Core, redactor *dynamicRedactor) zapcore.Core { + return &redactionCore{core, redactor} +} + +// Check overrides the embedded zapcore.Core Check() method to add the +// redactionCore to the zapcore.CheckedEntry. +func (c *redactionCore) Check(ent zapcore.Entry, ce *zapcore.CheckedEntry) *zapcore.CheckedEntry { + if c.Enabled(ent.Level) { + return ce.AddCore(ent, c) + } + return ce +} + +func (c *redactionCore) With(fields []zapcore.Field) zapcore.Core { + return NewRedactionCore(c.Core.With(fields), c.redactor) +} + +// Write overrides the embedded zapcore.Core Write() method to redact the message and fields before passing them to be +// written. Only message and string values are redacted; keys and non-string values (e.g. those inside of arrays and +// structured objects) are not redacted. +func (c *redactionCore) Write(ent zapcore.Entry, fields []zapcore.Field) error { + ent.Message = c.redactor.redact(ent.Message) + for i := range fields { + fields[i].String = c.redactor.redact(fields[i].String) + } + return c.Core.Write(ent, fields) +} diff --git a/pkg/sources/gitlab/gitlab.go b/pkg/sources/gitlab/gitlab.go index 38030d8f2934..dd1aaba345d0 100644 --- a/pkg/sources/gitlab/gitlab.go +++ b/pkg/sources/gitlab/gitlab.go @@ -8,6 +8,7 @@ import ( "strings" "sync" + "github.com/trufflesecurity/trufflehog/v3/pkg/log" "golang.org/x/sync/errgroup" "github.com/trufflesecurity/trufflehog/v3/pkg/common" @@ -108,9 +109,11 @@ func (s *Source) Init(ctx context.Context, name string, jobId sources.JobID, sou case *sourcespb.GitLab_Token: s.authMethod = "TOKEN" s.token = cred.Token + log.RedactGlobally(s.token) case *sourcespb.GitLab_Oauth: s.authMethod = "OAUTH" s.token = cred.Oauth.RefreshToken + log.RedactGlobally(s.token) // TODO: is it okay if there is no client id and secret? Might be an issue when marshalling config to proto case *sourcespb.GitLab_BasicAuth: s.authMethod = "BASIC_AUTH" @@ -118,6 +121,7 @@ func (s *Source) Init(ctx context.Context, name string, jobId sources.JobID, sou s.password = cred.BasicAuth.Password // We may need the password as a token if the user is using an access_token with basic auth. s.token = cred.BasicAuth.Password + log.RedactGlobally(cred.BasicAuth.Password) default: return fmt.Errorf("invalid configuration given for source %q (%s)", name, s.Type().String()) } From a136e31d83436e37a29eb92b6d3b7c8bcdf6d436 Mon Sep 17 00:00:00 2001 From: Cody Rose Date: Tue, 29 Oct 2024 12:42:20 -0400 Subject: [PATCH 73/76] Redact more source credentials (#3526) This PR implements global log redaction for the credentials of most other source types. It doesn't redact for sources that don't load their credentials with Init as a way to keep the PR simple - we can do those separately. --- pkg/sources/circleci/circleci.go | 2 ++ pkg/sources/elasticsearch/elasticsearch.go | 4 ++++ pkg/sources/gcs/gcs.go | 2 ++ pkg/sources/github/connector.go | 4 ++++ pkg/sources/jenkins/jenkins.go | 3 +++ pkg/sources/postman/postman.go | 2 ++ pkg/sources/s3/s3.go | 4 ++++ pkg/sources/travisci/travisci.go | 2 ++ 8 files changed, 23 insertions(+) diff --git a/pkg/sources/circleci/circleci.go b/pkg/sources/circleci/circleci.go index ad539b3bd9c1..11325a9799f6 100644 --- a/pkg/sources/circleci/circleci.go +++ b/pkg/sources/circleci/circleci.go @@ -8,6 +8,7 @@ import ( "sync/atomic" "github.com/go-errors/errors" + "github.com/trufflesecurity/trufflehog/v3/pkg/log" "golang.org/x/sync/errgroup" "google.golang.org/protobuf/proto" "google.golang.org/protobuf/types/known/anypb" @@ -73,6 +74,7 @@ func (s *Source) Init(_ context.Context, name string, jobId sources.JobID, sourc switch conn.Credential.(type) { case *sourcespb.CircleCI_Token: s.token = conn.GetToken() + log.RedactGlobally(s.token) } return nil diff --git a/pkg/sources/elasticsearch/elasticsearch.go b/pkg/sources/elasticsearch/elasticsearch.go index 29b36a7a4c7e..2d8226e4c401 100644 --- a/pkg/sources/elasticsearch/elasticsearch.go +++ b/pkg/sources/elasticsearch/elasticsearch.go @@ -9,6 +9,7 @@ import ( "github.com/go-logr/logr" "github.com/trufflesecurity/trufflehog/v3/pkg/common" "github.com/trufflesecurity/trufflehog/v3/pkg/context" + "github.com/trufflesecurity/trufflehog/v3/pkg/log" "github.com/trufflesecurity/trufflehog/v3/pkg/pb/source_metadatapb" "github.com/trufflesecurity/trufflehog/v3/pkg/pb/sourcespb" "github.com/trufflesecurity/trufflehog/v3/pkg/sanitizer" @@ -71,6 +72,7 @@ func (s *Source) Init( if conn.Password != "" { esConfig.Password = conn.Password + log.RedactGlobally(conn.Password) } if conn.CloudId != "" { @@ -79,10 +81,12 @@ func (s *Source) Init( if conn.ApiKey != "" { esConfig.APIKey = conn.ApiKey + log.RedactGlobally(conn.ApiKey) } if conn.ServiceToken != "" { esConfig.ServiceToken = conn.ServiceToken + log.RedactGlobally(conn.ServiceToken) } s.esConfig = esConfig diff --git a/pkg/sources/gcs/gcs.go b/pkg/sources/gcs/gcs.go index 4bb44aea19a0..7e9a05ced140 100644 --- a/pkg/sources/gcs/gcs.go +++ b/pkg/sources/gcs/gcs.go @@ -12,6 +12,7 @@ import ( "cloud.google.com/go/storage" "github.com/go-errors/errors" "github.com/go-logr/logr" + "github.com/trufflesecurity/trufflehog/v3/pkg/log" "golang.org/x/oauth2" "golang.org/x/oauth2/endpoints" "google.golang.org/protobuf/proto" @@ -149,6 +150,7 @@ func configureGCSManager(aCtx context.Context, conn *sourcespb.GCS, concurrency switch conn.Credential.(type) { case *sourcespb.GCS_ApiKey: gcsManagerAuthOption = withAPIKey(aCtx, conn.GetApiKey()) + log.RedactGlobally(conn.GetApiKey()) case *sourcespb.GCS_ServiceAccountFile: b, err := os.ReadFile(conn.GetServiceAccountFile()) if err != nil { diff --git a/pkg/sources/github/connector.go b/pkg/sources/github/connector.go index 215e16dfb988..9703aa921ebc 100644 --- a/pkg/sources/github/connector.go +++ b/pkg/sources/github/connector.go @@ -5,6 +5,7 @@ import ( gogit "github.com/go-git/go-git/v5" "github.com/google/go-github/v66/github" + "github.com/trufflesecurity/trufflehog/v3/pkg/log" "github.com/trufflesecurity/trufflehog/v3/pkg/context" "github.com/trufflesecurity/trufflehog/v3/pkg/pb/sourcespb" @@ -27,10 +28,13 @@ func newConnector(source *Source) (connector, error) { switch cred := source.conn.GetCredential().(type) { case *sourcespb.GitHub_GithubApp: + log.RedactGlobally(cred.GithubApp.GetPrivateKey()) return newAppConnector(apiEndpoint, cred.GithubApp) case *sourcespb.GitHub_BasicAuth: + log.RedactGlobally(cred.BasicAuth.GetPassword()) return newBasicAuthConnector(apiEndpoint, cred.BasicAuth) case *sourcespb.GitHub_Token: + log.RedactGlobally(cred.Token) return newTokenConnector(apiEndpoint, cred.Token, source.handleRateLimit) case *sourcespb.GitHub_Unauthenticated: return newUnauthenticatedConnector(apiEndpoint) diff --git a/pkg/sources/jenkins/jenkins.go b/pkg/sources/jenkins/jenkins.go index d6769c3e8b03..704208d5f868 100644 --- a/pkg/sources/jenkins/jenkins.go +++ b/pkg/sources/jenkins/jenkins.go @@ -12,6 +12,7 @@ import ( "github.com/go-errors/errors" "github.com/go-logr/logr" + "github.com/trufflesecurity/trufflehog/v3/pkg/log" "google.golang.org/protobuf/proto" "google.golang.org/protobuf/types/known/anypb" @@ -111,12 +112,14 @@ func (s *Source) Init(aCtx context.Context, name string, jobId sources.JobID, so if len(s.token) == 0 { return errors.Errorf("Jenkins source basic auth credential requires 'password' to be specified") } + log.RedactGlobally(s.token) case *sourcespb.Jenkins_Header: unparsedURL = conn.Endpoint s.header = &header{ key: cred.Header.Key, value: cred.Header.Value, } + log.RedactGlobally(cred.Header.GetValue()) case *sourcespb.Jenkins_Unauthenticated: unparsedURL = conn.Endpoint default: diff --git a/pkg/sources/postman/postman.go b/pkg/sources/postman/postman.go index 2a274e03a781..9219d1d459ae 100644 --- a/pkg/sources/postman/postman.go +++ b/pkg/sources/postman/postman.go @@ -13,6 +13,7 @@ import ( "strings" "github.com/trufflesecurity/trufflehog/v3/pkg/context" + "github.com/trufflesecurity/trufflehog/v3/pkg/log" "google.golang.org/protobuf/proto" "google.golang.org/protobuf/types/known/anypb" @@ -117,6 +118,7 @@ func (s *Source) Init(ctx context.Context, name string, jobId sources.JobID, sou } s.client = NewClient(conn.GetToken()) s.client.HTTPClient = common.RetryableHTTPClientTimeout(3) + log.RedactGlobally(conn.GetToken()) case *sourcespb.Postman_Unauthenticated: s.client = nil // No client needed if reading from local diff --git a/pkg/sources/s3/s3.go b/pkg/sources/s3/s3.go index 8c3aabca85b3..c32faa0730f1 100644 --- a/pkg/sources/s3/s3.go +++ b/pkg/sources/s3/s3.go @@ -16,6 +16,7 @@ import ( "github.com/aws/aws-sdk-go/service/sts" "github.com/go-errors/errors" "github.com/go-logr/logr" + "github.com/trufflesecurity/trufflehog/v3/pkg/log" "golang.org/x/sync/errgroup" "google.golang.org/protobuf/proto" "google.golang.org/protobuf/types/known/anypb" @@ -136,8 +137,11 @@ func (s *Source) newClient(region, roleArn string) (*s3.S3, error) { switch cred := s.conn.GetCredential().(type) { case *sourcespb.S3_SessionToken: cfg.Credentials = credentials.NewStaticCredentials(cred.SessionToken.Key, cred.SessionToken.Secret, cred.SessionToken.SessionToken) + log.RedactGlobally(cred.SessionToken.GetSecret()) + log.RedactGlobally(cred.SessionToken.GetSessionToken()) case *sourcespb.S3_AccessKey: cfg.Credentials = credentials.NewStaticCredentials(cred.AccessKey.Key, cred.AccessKey.Secret, "") + log.RedactGlobally(cred.AccessKey.GetSecret()) case *sourcespb.S3_Unauthenticated: cfg.Credentials = credentials.AnonymousCredentials default: diff --git a/pkg/sources/travisci/travisci.go b/pkg/sources/travisci/travisci.go index 13c46aa9f1a5..a7ead20d0b7e 100644 --- a/pkg/sources/travisci/travisci.go +++ b/pkg/sources/travisci/travisci.go @@ -6,6 +6,7 @@ import ( "github.com/go-errors/errors" "github.com/shuheiktgw/go-travis" + "github.com/trufflesecurity/trufflehog/v3/pkg/log" "golang.org/x/sync/errgroup" "google.golang.org/protobuf/proto" "google.golang.org/protobuf/types/known/anypb" @@ -76,6 +77,7 @@ func (s *Source) Init(ctx context.Context, name string, jobId sources.JobID, sou } s.client = travis.NewClient(baseURL, conn.GetToken()) s.client.HTTPClient = common.RetryableHTTPClientTimeout(3) + log.RedactGlobally(conn.GetToken()) user, _, err := s.client.User.Current(ctx, nil) if err != nil { From 3e12bcb15cc56f1e740bd52c3e223e83670aad8d Mon Sep 17 00:00:00 2001 From: Zachary Rice Date: Tue, 29 Oct 2024 13:00:00 -0500 Subject: [PATCH 74/76] rm snifftest (#3527) --- .github/workflows/snifftest.yml | 24 ------------------------ Makefile | 3 --- 2 files changed, 27 deletions(-) delete mode 100644 .github/workflows/snifftest.yml diff --git a/.github/workflows/snifftest.yml b/.github/workflows/snifftest.yml deleted file mode 100644 index 778356971cb2..000000000000 --- a/.github/workflows/snifftest.yml +++ /dev/null @@ -1,24 +0,0 @@ -name: Snifftest - -on: - push: - tags: - - v* - branches: - - main - -permissions: - contents: read - pull-requests: read - -jobs: - Snifftest: - name: Run Snifftest - runs-on: ubuntu-latest - steps: - - uses: actions/setup-go@v5 - with: - go-version: "1.23" - - uses: actions/checkout@v4 - - name: Run Snifftest - run: make snifftest diff --git a/Makefile b/Makefile index 4f38b92d0a01..43e9a58ab587 100644 --- a/Makefile +++ b/Makefile @@ -61,8 +61,5 @@ release-protos-image: docker buildx build --push --platform=linux/amd64,linux/arm64 \ -t ${PROTOS_IMAGE} -f hack/Dockerfile.protos . -snifftest: - ./hack/snifftest/snifftest.sh - test-release: goreleaser release --clean --skip-publish --snapshot From b44dc244947b7bd689ae171f4382feaa202d7fdf Mon Sep 17 00:00:00 2001 From: Zachary Rice Date: Tue, 29 Oct 2024 15:59:02 -0500 Subject: [PATCH 75/76] enforce timeout on circleci test (#3528) * enforce timeout * bump to 10s, 3s seemed too aggro --- pkg/sources/circleci/circleci_test.go | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/pkg/sources/circleci/circleci_test.go b/pkg/sources/circleci/circleci_test.go index cf7e21f55a5d..5efad5fc802e 100644 --- a/pkg/sources/circleci/circleci_test.go +++ b/pkg/sources/circleci/circleci_test.go @@ -16,7 +16,7 @@ import ( ) func TestSource_Scan(t *testing.T) { - ctx, cancel := context.WithTimeout(context.Background(), time.Second*3) + ctx, cancel := context.WithTimeout(context.Background(), time.Second*10) defer cancel() secret, err := common.GetTestSecret(ctx) @@ -82,11 +82,16 @@ func TestSource_Scan(t *testing.T) { return } }() - gotChunk := <-chunksCh - gotChunk.SourceMetadata.Data.(*source_metadatapb.MetaData_Circleci).Circleci.BuildNumber = 0 // override this because we need to periodically re-run the builds - gotChunk.SourceMetadata.Data.(*source_metadatapb.MetaData_Circleci).Circleci.Link = "" // override this because we need to periodically re-run the builds - if diff := pretty.Compare(gotChunk.SourceMetadata, tt.wantSourceMetadata); diff != "" { - t.Errorf("Source.Chunks() %s diff: (-got +want)\n%s", tt.name, diff) + + select { + case gotChunk := <-chunksCh: + gotChunk.SourceMetadata.Data.(*source_metadatapb.MetaData_Circleci).Circleci.BuildNumber = 0 // override this because we need to periodically re-run the builds + gotChunk.SourceMetadata.Data.(*source_metadatapb.MetaData_Circleci).Circleci.Link = "" // override this because we need to periodically re-run the builds + if diff := pretty.Compare(gotChunk.SourceMetadata, tt.wantSourceMetadata); diff != "" { + t.Errorf("Source.Chunks() %s diff: (-got +want)\n%s", tt.name, diff) + } + case <-ctx.Done(): + t.Errorf("Source.Chunks() %s timed out", tt.name) } }) } From 0e7bce28e6c3d1c086991bf5ededf3c79ac9f4bc Mon Sep 17 00:00:00 2001 From: Dustin Decker Date: Tue, 29 Oct 2024 21:10:52 -0700 Subject: [PATCH 76/76] update aws descriptions (#3529) --- pkg/detectors/aws/aws.go | 2 +- pkg/detectors/awssessionkeys/awssessionkey.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/detectors/aws/aws.go b/pkg/detectors/aws/aws.go index cba39f1f6e77..a30b542f1da7 100644 --- a/pkg/detectors/aws/aws.go +++ b/pkg/detectors/aws/aws.go @@ -458,5 +458,5 @@ func (s scanner) Type() detectorspb.DetectorType { } func (s scanner) Description() string { - return "AWS is a cloud service used offering over 200 API's to transact data and compute. AWS API keys can be used to access and modify this data and compute." + return "AWS (Amazon Web Services) is a comprehensive cloud computing platform offering a wide range of on-demand services like computing power, storage, databases. API keys for AWS can have varying amount of access to these services depending on the IAM policy attached." } diff --git a/pkg/detectors/awssessionkeys/awssessionkey.go b/pkg/detectors/awssessionkeys/awssessionkey.go index 88c3745d4c89..51f5d51c9a86 100644 --- a/pkg/detectors/awssessionkeys/awssessionkey.go +++ b/pkg/detectors/awssessionkeys/awssessionkey.go @@ -344,5 +344,5 @@ func (s scanner) Type() detectorspb.DetectorType { } func (s scanner) Description() string { - return "AWS is a cloud service used offering over 200 API's to transact data and compute. AWS API keys can be used to access and modify this data and compute." + return "AWS (Amazon Web Services) is a comprehensive cloud computing platform offering a wide range of on-demand services like computing power, storage, databases. API keys for AWS can have varying amount of access to these services depending on the IAM policy attached. AWS Session Tokens are short-lived keys." }